0

I have a problem that one of my JPanels doesn't update itself according to the window when its supposed too. I shall try and briefly explain whats happening. A list of characters is fed into an arraylist (named lookReply) from another class (this works as I've tested this) it then uses 2 iterations to assign each one to a coordinate in a square table made from JLabels. These JLabels are in the lookReplyGUIPanel JPanel. After a button is pressed new characters get loaded into the arraylist and it repeats itself. However the window does not show this update. I know they are getting fed into the JLabels through some tests but its just the updating of the window doesn't seem to be working. I am using invalidate, validate and repaint but it still doesn't work. Please see my code below for the parts needed.

The first method called - deals with the arraylist then calls the other method.

private void look()
{
    //clear arrayList then add new lookReply to it
    lookReply.clear();
    while (HumanUser.lookReply==null)
    {
    }
    for(int n = 0; n<HumanUser.lookReply.length(); n++)
    {
        lookReply.add(HumanUser.lookReply.charAt(n));                   
    }
    lookReply();
//UP TO HERE WORKS FINE

    screen.invalidate();
    screen.validate();
    screen.repaint();
}

The method which deals with the JPanel in question.

/**
 * Made up of several smaller JPanels each relate to 1 map position from the lookReply command.
 */
private JPanel lookReply()
{
    JPanel lookReplyGUIPanel = new JPanel(new GridBagLayout());
    GridBagConstraints c = new GridBagConstraints();
    Border blackline = BorderFactory.createLineBorder(Color.black);


    //Create a square table dependent on the radius of view.
    //Then fill each cell with the block retrieved from the lookReply arrayList.
    for(int y = lookReplyY; y>0; y--)
    {
        for(int x = lookReplyX; x>0; x--)
        {wall...
            //Then assign it to a variable which is used in the JLabel.
            String item = null;
            if (lookReply.size()!=0)
            {
                item = lookReply.get(x*y-1) + "";
            }
            //ADD TO CHECK WHAT EACH ITEM IS AND USE THE RELEVENT PICTURE
            JLabel lookx = new JLabel(item);
            int width = (2*screenHeight/(5*lookReplyX)-10);
            lookx.setPreferredSize(new Dimension(width, width));
            lookx.setBorder(blackline);
            c.gridx = x;
            c.gridy = y;
            lookReplyGUIPanel.add(lookx, c);
        }
    }
    return lookReplyGUIPanel;
}

Some more details of the overview of everything if this helps. The first method called adds all the JPanels to the JFrame in the correct position using gridBagConstraints. The JFrame is created outside a method so all other methods can see it. All help much appreciated and happy to provide more details if needed! thanks

Here is a simple compilable piece of code which demonstrates the same problem. Ignoring the fact the window has to be resized - every button click on button increments m by 1 and should update to display the lookReply method of a 5X5 table of m. However it does not.

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class temp
{
JFrame screen = new JFrame("temp");
int m = 1;


public static void main(String[] args)
{
    temp g = new temp();
    g.create();
}

private void create()
{       
    screen.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    screen.setLayout(new GridBagLayout());
    GridBagConstraints c = new GridBagConstraints();

    c.gridy = 0;
    screen.add(lookReply(), c);


    c.gridy = 1;
    screen.add(button(), c);

    screen.setVisible(true);
}

private JPanel lookReply()
{
    JPanel lookReplyGUIPanel = new JPanel(new GridBagLayout());
    GridBagConstraints c = new GridBagConstraints();

    for(int y = 5; y>0; y--)
    {
        for(int x = 5; x>0; x--)
        {
            JLabel lookx = new JLabel((m + ""));
            c.gridx = x;
            c.gridy = y;
            lookReplyGUIPanel.add(lookx, c);
        }
    }

    screen.invalidate();
    screen.validate();
    screen.repaint();
    return lookReplyGUIPanel;
}

private JPanel button()
{
    JPanel button = new JPanel(new GridBagLayout());
    GridBagConstraints c = new GridBagConstraints();

    JButton b = new JButton("button");
    b.setBorder(null);
    c.gridx = 2;
    c.gridy = 2;
    button.add(b, c);
    b.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            m++;
            lookReply();                
        }
    });

    return button;
}

}

  • Without a fully runnable example, it's not going to be possible to know for sure what's going on, however, `while (HumanUser.lookReply==null)` is very scary, this either means you're running this piece of code in a separate thread, which is bad as you are updating the UI within the same piece of code or you're running it within the EDT, which is bad, as this will cause your program to look like it's "hung" (cause it has). Are you adding `lookReplyGUIPanel` to anything? – MadProgrammer Apr 11 '14 at 21:03
  • Where is your `SSCCE`? Why do you need to be asked every time to post your SSCCE? MadProgrammer and I both asked you to post a SSCCE/MCVE in your last question: http://stackoverflow.com/q/22849557/131872. Why do we have to repeat ourselves every time??? – camickr Apr 11 '14 at 21:05
  • @MadProgrammer I've used that while statement as a 'pause' while another thread updates the variable used to add the chars to the arraylist. And yes I am using multiple threads. `lookReplyGUIPanel` is added initially when the program is first run, but not after every update. I thought thats what invalidate, validate and repaint did after reading other questions. –  Apr 11 '14 at 21:13
  • @camickr I have asked many times, HOW do I do it, no-one has replied –  Apr 11 '14 at 21:13
  • @pokeairguy a simple, compilable, runnable example that demonstrates your problem is all we're asking for... – MadProgrammer Apr 11 '14 at 21:25
  • You should never be waiting like this in the EDT, you should have some kind of event notification that is sent from the class building the content and is sent to your UI so you can deal with it (observer pattern). You should never wait like this anyway, instead, you should be using Object.wait/notify as it will use less CPU – MadProgrammer Apr 11 '14 at 21:27
  • @MadProgrammer I have put a simple example of the problem in the question, I think this is what you were asking for. –  Apr 11 '14 at 21:49

2 Answers2

2

So, based on your example, lookReply creates a NEW JPanel, but you don't do anything with it. So the component is never added to the screen, so all attempts to make it refresh will have no effect...

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • +1, and to refresh the "screen" after you add the component to the screen you use `screen.revalidate()` and `screen.repaint()`. – camickr Apr 12 '14 at 01:23
  • Thanks, after a bit of tweaking that's worked. @camickr when I compile `screen.revalidate()` it says 'cannot find symbol symbol: method revalidate()'. After looking on other posts people suggested using `invalidate` and `validate` which is what you can see I've used and it works OK –  Apr 12 '14 at 10:49
  • @pokeairguy, `After looking on other posts people suggested...` that is old advice and is used when working with AWT. When using Swing you should use `revalidate()`. The revalidate() method was added to a JFrame in JDK7 so you are using an old version. However, revalidate() works on all Swing components, like JPanel. Usually people add a JPanel containing their components to the frame, Instead of adding comopnents directly to the frame. This way you have easy access to the panel and can use revalidate(). – camickr Apr 12 '14 at 14:40
  • @camickr `revalidate` works when I compile and run my program through eclipse, It does not when I do so in LCPU, (the Uni's linux command line) I think they have an older version, hence its not working. So theres not much I can do about that, cheers anyway –  Apr 12 '14 at 14:47
  • @pokeairguy, `So theres not much I can do about that` - I already suggested what you can do about that. You should better structure your program to add components to the content pane of the frame and not the frame directly. Read the Swing tutorials and create your programs with a better structure. Another thing you are doing wrong is you are not creating your components on the Event Dispatch Thread. – camickr Apr 12 '14 at 15:08
1

Update your GUI elements using a javax.swing.Timer, as shown here and here.

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045