thisisnic
thisisnic

Reputation: 930

Dynamically updating CardLayout not working

My code uses Card Layout to display (predefined) JPanels with JButtons to the user, and then show a dynamically generated JPanel with feedback on their response, before proceeding to the next predefined JPanel. However, I can't get the dynamically generated JPanels to display, and having messed around a bit with commands like revalidate() and repaint(), I'm at a loss as to what to try next. I've probably made a fairly simple mistake, but having tried lots of combinations of things, I'm a bit stuck!

Edit: sorry, that was a pretty useless bit of code that I posted earlier! I've taken the time to write a better SSCCE, and it does look like it's to do with using Thread.sleep but I'm not great with that so not too sure what I need to do to make it work properly. Here is my example:

public class ExampleClass implements ActionListener{

public void doStuff(){
    ExampleClass ec = new ExampleClass();
    startExperiment();

}

public static void main(String[] args){

    ExampleClass e = new ExampleClass();
    e.doStuff();
}


JPanel j;
int count = 0;
CardLayout cards = new CardLayout();
JButton button;

public void startExperiment(){

    // Create frame and JFrames
    JFrame trial = new JFrame();

    trial.setSize(800,600);

    JPanel j1 = new JPanel();
    JPanel j2 = new JPanel();
    j1.setSize(800,600);
    button = new JButton("Click me!");
    button.addActionListener(this);

    j2.setSize(800,600);
    j1.add(new JLabel("A Panel"));
    j1.add(button);
    j2.add(new JLabel("Another Panel"));
    JPanel[] pans = {j1,j2};


    j = new JPanel();
    j.setLayout(cards);

    for(int i=0;i<pans.length;i++){
        j.add(pans[i], "Card"+i);
    }

    JPanel end = new JPanel();
    end.add(new JLabel("The end!"));
    j.add(end,"End");
    trial.add(j);
    trial.setVisible(true);
}



public void nextTrial(){

    JPanel ps = new JPanel();
    ps.add(new JLabel("This panel won't display!"));
    j.add(ps,"Pause"+count);
    cards.show(j,"Pause"+count);

}

class aThread extends Thread {
    public aThread(int duration){
        dur=duration;
    }
    int dur;
    public void run() {
        try {
            Thread.sleep(dur);
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public void pause(int dur){
    aThread myThread = new aThread(dur);
    myThread.start();
    try {
        myThread.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }


}

@Override
public void actionPerformed(ActionEvent e) {
    if(e.getSource()==button){
        System.out.println("Ow!");
        nextTrial();
        pause(500);
        cards.show(j,"Card1");
    }

}

}

I realise that this is a similar question to one I asked about 12 months ago here (http://stackoverflow.com/questions/9200072/jpanel-not-updating-cardlayout-properly-when-i-use-sleep?rq=1), but I mistakenly believed that using Thread.join() would solve the problems I mentioned.

Upvotes: 0

Views: 1742

Answers (3)

thisisnic
thisisnic

Reputation: 930

Thanks to everyone that answered, for pointing me in the right direction. I figured out in the end, it's to do with my poor understanding of threads and synchronisity. In case anyone else has a similar problem, I solved this by changing the last bit of my code to read:

public void actionPerformed(ActionEvent e) {
    if(e.getSource()==button){

         nextTrial();

        SwingUtilities.invokeLater(new Runnable() {
              public void run() {
                  pause(500);
                  cards.show(j,"Card1");

                }
              });
    }
}

Upvotes: 0

Michael Dunn
Michael Dunn

Reputation: 816

if you have "messed around a bit with commands like revalidate() and repaint(),", then, if this

pause(500);

has anything to do with Thread.sleep(), it is likely to be the problem.

It will block painting, then immediately show the next card.

To be sure, post a sample compilable program, as mentioned earlier.

Upvotes: 1

StanislavL
StanislavL

Reputation: 57381

Add the call

revalidate();
repaint();

after adding/removing components to/from container

Upvotes: 2

Related Questions