首先:我知道这个问题似乎被问了几百万次,但其他问题的答案似乎都不适用于我。
有时,当我在下面的代码中运行Message.popup(String, int)
时,文本会正确显示,但有时JDialog为空,就好像组件根本没有添加一样。
public class Message extends JDialog {
private int width;
private int height;
private JLabel content;
public Message(String _content, int _margin) {
super();
this.content = new JLabel(_content);
content.setFont(new Font("Monospaced", Font.BOLD, 20));
this.margin = _margin;
this.width = content.getPreferredSize().width + _margin;
this.height = content.getPreferredSize().height + _margin;
createComponents();
setProperties();
}
public static void popup(String _content, int _time) {
if (SwingUtilities.isEventDispatchThread()) {
runPopup(_content, _time);
}
else {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
runPopup(_content, _time);
}
});
}
}
private static void runPopup(String _content, int _time) {
final Message message = new Message(_content);
new Timer(_time, new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
message.dispose();
}
}).start();
}
private void createComponents() {
setLayout(new BorderLayout());
Box box = Box.createHorizontalBox();
box.add(Box.createHorizontalGlue());
box.add(content, BorderLayout.CENTER);
box.add(Box.createHorizontalGlue());
add(box);
}
private void setProperties() {
setSize(width, height);
setLocation(Coordinator.calculateCenteredWindowLocation(width, height));
setUndecorated(true);
setResizable(false);
setTitle(content.getText());
setVisible(true);
update(getGraphics());
}
}
没有update(getGraphics());
,框架总是空的,但有了它,它取决于风向的方向......(去图!)
答案 0 :(得分:4)
您确定您的代码是在EDT中执行的吗?事实上,如果不是(这是我期望的,因为你sleep
当前的线程,Swing通常不喜欢),你的框架将无法渲染。
为了避免这些典型的Swing线程问题,请查看SwingUtilities
类,它提供了确保您在EDT中运行的方法。另外,您可以使用Swing javax.swing.Timer
(而不是将其与java.util.Timer
混淆)来代替直接沉睡您的线程。
答案 1 :(得分:4)
正如@Riduidel所提到的,重要的是在事件发送线程或EDT
上发生与Swing相关的任何事情。这是因为Swing不是线程安全的。在调用popup()
时,您应该执行以下操作
if(SwingUtilities.isEventDispatchThread()){
Message.popup(...);
}
else{
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run(){
Message.popup(...);
}
});
}
这将确保在JFrame
上创建EDT
。此外,从您发布的代码段中,Message
似乎应该有私有构造函数。另外,既然你没有做任何自定义渲染,为什么不只是创建一个JFrame
成员变量而不是扩展类? - 对我来说似乎有点多余。
无论如何,你也不应该在sleep
中EDT
,因为这会使GUI看起来“冻结”并阻止其他排队事件的执行。执行长时间运行的任务时,请使用SwingWorker
或@Riduidel,javax.swing.Timer
。但是,如果您更喜欢使用java.util.Timer
,请使用上面显示的SwingUtilities
实用程序类在Runnable
上发布要在EventQueue
中执行的EDT
任务}。
修改强>
这是我要做的(是的,它有效)
public class Message {
// Private constructor to prevent external instantiation
private Message(){
}
public static void createAndShowDialog(final String content, final int time){
final JDialog dialog = new JDialog();
dialog.setLayout(new BorderLayout());
dialog.setUndecorated(true);
JLabel label = new JLabel(content);
label.setFont(new Font("Monospaced", Font.BOLD, 20));
Box b = Box.createHorizontalBox();
b.add(Box.createHorizontalGlue());
b.add(label, BorderLayout.CENTER);
b.add(Box.createHorizontalGlue());
dialog.add(b);
dialog.pack();
dialog.setLocationRelativeTo(null);
dialog.setVisible(true);
// kick-off timer
Timer t = new Timer(time, new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
dialog.dispose();
}
});
t.setRepeats(false);
t.start();
}
}
无论您何时调用createAndShowDialog(...)
,请执行以下操作
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run(){
Message.createAndShowDialog("Content", 5000); // wait 5 seconds before disposing dialog
}
});
答案 2 :(得分:2)
update(getGraphics());
永远不要使用update()方法或getGraphics()方法。
调用update()用于AWT NOT Swing。
如果您需要进行自定义绘制,则覆盖已经有权访问图形对象的组件的paintComponent()方法。