The following code shown below will add 3 JLabels to a JFrame and then remove the 3 JLabels. After 2 seconds it will repaint back the 3 JLabels.
import javax.swi
add(new JLabel(), BLANK_COMPONENT);
next()
on my CardLayout object, passing in the main CardLayout-using component: cardLayout.next(myMainJPanel);
For example,
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.event.*;
import javax.swing.*;
public class RepaintTest extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private static final int LABEL_COUNT = 3;
private static final String LABEL_PANEL = "label panel";
private static final Object BLANK_COMPONENT = "blank component";
private static final int TIMER_DELAY = 2000;
private CardLayout cardLayout = new CardLayout();
public RepaintTest() {
JPanel labelPanel = new JPanel();
for (int i = 0; i < LABEL_COUNT; i++) {
labelPanel.add(new JLabel("Label " + (i + 1)));
}
setLayout(cardLayout);
add(labelPanel, LABEL_PANEL);
add(new JLabel(), BLANK_COMPONENT);
new Timer(TIMER_DELAY, new TimerListener()).start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private class TimerListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
cardLayout.next(RepaintTest.this);
}
}
private static void createAndShowGui() {
RepaintTest mainPanel = new RepaintTest();
JFrame frame = new JFrame("RepaintTest");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
You are violating the single thread rules of Swing...
See Concurrency in Swing for more details.
Essentially, you should never update any UI component from any thread context other than the Event Dispatching Thread.
Instead, you should use either a SwingWorker or, probably more relevent to your problem, a javax.swing.Timer
The problem is, as you've clearly noted, is the reference to frameTwo
has nothing to do with the reference of frameOne
, they are completely separate objects and therefore have nothing in common with each other
What you need to be able to do is pass some kind of reference of the object you want updated to the class doing the updating...
In this example, I simply created a reapplyLabels
method in RepaintFrameTest
and used a Swing Timer
set for 2 a second delay, to call this method...
Personally, I'd prefer to pass an interface
as it exposes less and de-couples the code, but this is just a simple example...
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class RepaintFrameTest extends JFrame {
private JPanel panel = new JPanel();
private JLabel labelOne = new JLabel("label1");
private JLabel labelTwo = new JLabel("label2");
private JLabel labelThree = new JLabel("label3");
public RepaintFrameTest() {
add(panel);
}
public void reapplyLabels() {
panel.add(labelOne);
panel.add(labelTwo);
panel.add(labelThree);
revalidate();
repaint();
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
RepaintFrameTest frame = new RepaintFrameTest();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Timer timer = new Timer(2000, new RepaintAction(frame));
timer.setRepeats(false);
timer.start();
}
});
}
public static class RepaintAction implements ActionListener {
private RepaintFrameTest frame;
public RepaintAction(RepaintFrameTest frame) {
this.frame = frame;
}
@Override
public void actionPerformed(ActionEvent e) {
frame.reapplyLabels();
}
}
}
While there's not enough context to make a full judement call, I also agree with HovercraftFullOfEels, a CardLayout would achieve the same result, probably with less mess...