我在swing中创建一个对话框(JRE 6 update 10,Ubuntu linux)。当用户使用完对话框后,它将被隐藏。当用户点击另一个框架中的按钮时,框中的标签会根据按钮发生变化,然后再次显示该框。
我遇到的问题是在标签更改之前显示该框,即使编程方式,我正以相反的顺序进行调用。这会导致框出现,然后是标签更改,在我们的慢速目标HW上看起来“毛刺”。似乎EDT在标签 setText(....)之前安排了框架 setVisible(true);它优先考虑这个电话。有没有办法让EDT安排在 setText(....)之后执行 setVisible(true)?
请注意,代码是从已经在EDT上执行的按钮单击调用的,因此无法使用 SwingUtilities.invokeAndWait 。我尝试过使用 invokeLater 方法,但EDT仍会重新安排它。
在调试模式下在IDE中运行以下代码,并在显示和隐藏“对话框”框后中断 showButton 的操作代码。标签的 setText(....)更改不会立即对GUI产生影响,但框架的 setVisible(true)将会立即生效。然后逐步完成EDT,你会发现 setText 最终会在EDT计划中进一步发生。
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);
}
}
答案 0 :(得分:1)
我不认为这是Linux绘画中的一个问题。我可以在Windows 7 64位(JDK 1.6.0_18(早期访问))上重现您的问题。你非常接近答案 - 你知道SwingUtilities.invokeLater,但是你并没有考虑在你需要的地方使用它。
跟我说:
您必须在EDT上初始化和修改Swing组件
如果你不这样做,会发生坏事。在这种情况下,您的奇怪重绘行为是由于未在EDT上创建JFrame和包含的组件。如果您将此行包装在SwingUtilities.invokeLater中,它将解决您的问题:
JFrame frame = new MyFrame();
你是对的 - 你的setText发生在EDT上,但组件本身的初始化并没有在EDT上发生,这就是根本原因。
如果对EDT上是否发生给定代码存在疑问,可以使用SwingUtilities.isEventDispatchThread()来查找。
如果您计划进行大量的Swing开发,我强烈建议您阅读Filthy Rich Clients。我现在正在阅读它。
答案 1 :(得分:0)
问题不在于标签组件的文本没有改变。这是重新安排已经安排但尚未发生。那和Linux有打开窗口极度慢的倾向(窗口管理器或类似的问题?)。 java.awt.EventQueue
按优先级排定,但我不记得细节。
JComponent.paintImmediately
看起来像是一种可能的方法。您可能想在Swing / AWT中找到关于动画的(好)文本。 (那个或没有窗口管理器运行。)
答案 2 :(得分:0)
我刚刚在OS X遇到了类似的问题。我的解决方案是:
frame.invalidate()
frame.pack()
frame.setVisible(true)
这似乎强制摆动以在显示之前重新绘制内存中的帧。