I am new to Java swing programming. I want to make a frame which will appear red and blue in turn one after another. So, I took 2 child JPanel, 1 for red and other for blue, and a for-loop. On each iteration I remove one panel from parent panel and add another. But, when I run the program it only shows the last state of the frame.
Can anyone explain why? And what's the intended approach to make a program work like that? My code:
public class Test2 extends JFrame {
public Test2() {
JPanel Red = new JPanel(new BorderLayout());
JPanel Blue = new JPanel(new BorderLayout());
//...initialize Red and Blue
Red.setBackground(Color.red);
Blue.setBackground(Color.blue);
Red.setPreferredSize(new Dimension(200,200));
Blue.setPreferredSize(new Dimension(200,200));
JPanel panel = new JPanel(new BorderLayout());
panel.setPreferredSize(new Dimension(200,200));
add(panel);
pack();
setTitle("Border Example");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
int M = 1000000; //note that, I made a long iteration to not finish the program fast and visualize the effect
for(int i=0;i<M;i++)
{
if(i%(M/10)==0) System.out.println(i); //to detect whether the program is running
if(i%2==0)
{
panel.removeAll();
panel.repaint();
panel.revalidate();
panel.add(Red,BorderLayout.CENTER);
}
else
{
panel.removeAll();
panel.repaint();
panel.revalidate();
panel.add(Blue,BorderLayout.CENTER);
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Test2 ex = new Test2();
ex.setVisible(true);
}
});
}}
Basically you don't need to use a
while
(or any other) loop, Swing only paints once it has finished that loop then repaint the GUI.As stated before by @camickr on his answer, you could try a
Swing Timer
; here's an example that does exactly what you want.From your comment on another answer:
Swing is smart enough to know it doesn't needs to repaint in a loop, instead it will repaint once it the loop finishes, if you read the tutorial on Swing Custom Paint on the step 3 it says:
And Timer will repaint it, because it's not running on the EDT but in it's own Thread
Don't use a loop. Swing will only repaint the frame once the entire loop has finished executing.
Instead you need to use a Swing Timer. When the Timer fires you invoke your logic. Read the section from the Swing tutorial on How to Use Swing Timers.
Here is a simple example of a Timer that simply displays the time every second: Update a Label with a Swing Timer
Also, don't remove/add panels. Instead you can use a
Card Layout
and sway the visible panel. Again read the tutorial on How to Use CardLayout.I would suggest to take in one step at a time.
First make it run without changing panels / colors.
Now it doesn't because this
is a method (which is never used) and not a constructor. Change to a constructor declaration like :
to make the program do something. Then you can go to the next step.
Also use Java naming conventions (like blue instead of Blue).