The Problem
I create a dialog box in swing (JRE 6 update 10, Ubuntu linux). When the user has finished using the dialog box it is hidden. When the users click on a button in another frame, a label on the box is changed according to the button, and then the box is shown again.
The problem I'm having is that the box is shown before the label changes even though, programatically, I'm making the calls in the opposite order. This causes the box to appear followed by the label change which looks "glitchy" on our slow target HW. It appears that the EDT schedules the frame setVisible(true) ahead of the label setText(....); it gives priority to this call. Is there any way to get the EDT to schedule the setVisible(true) to execute after the setText(....)?
Note that the code is called from a button click which is already executing on the EDT so one can't use SwingUtilities.invokeAndWait. I've tried using the invokeLater method but the EDT still re-schedules it.
To reproduce
Run the following code in an IDE in debug mode and break in the showButton's action code after showing and hiding the "dialog" frame. The label's setText(....) change will not have an immediate effect on the GUI but the frame's setVisible(true) will. Then step through the EDT and you'll see that the setText eventually happens further down the EDT schedule.
import java.awt.FlowLayout;
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.WindowConstants;
public class DemonstrateFramePaintEDTPriority {
static class MyFrame extends JFrame {
private JFrame frame;
private JLabel label;
int i = 0;
public MyFrame() {
// Some label strings
final String string[] = new String[] { "label text one",
"label 2222222", "3 3 3 3 3 3 3" };
// Create GUI components.
frame = new JFrame("Dialog");
label = new JLabel("no text set on this label yet");
frame.setSize(500, 200);
frame.setLayout(new FlowLayout());
frame.add(label);
// Add show and hide buttons.
JButton showButton = new JButton("show dialog");
showButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// Set the label text - THIS HAPPENS AFTER frame.setVisible
label.setText(string[i]);
// Select new label text for next time.
i++;
if (i >= string.length) {
i = 0;
}
// Show dialog - THIS HAPPENS BEFORE label.setText
frame.setVisible(true);
}
});
JButton hideButton = new JButton("hide dialog");
hideButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
label.setText("label removed");
frame.setVisible(false);
}
});
setSize(500, 200);
setLayout(new FlowLayout());
add(showButton);
add(hideButton);
}
}
public static void main(String[] args) {
JFrame frame = new MyFrame();
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.setVisible(true);
}
}
The problem isn't that the label component's text hasn't change. It's that the repaint has been scheduled but hasn't happened yet. That and Linux has a tendency of being extremely slow to open windows (a problem with window manager or similar?). The
java.awt.EventQueue
schedules by priority, although I can't remember the details.JComponent.paintImmediately
looks like a likely method. You might want to find a (good) text on animation within Swing/AWT. (That or run without a window manager.)