0

首先:我知道这个问题似乎已经被问了几百万次,但其他问题的答案似乎都不适用于我。

有时,当我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());,框架总是空的,但是有了它,这取决于风吹的方向......(去图!)

4

3 回答 3

4

您确定您的代码正在EDT中执行吗?实际上,如果不是(这是我所期望的,因为您sleep是当前线程,Swing 通常不喜欢什么),您的框架将无法渲染。

为避免那些典型的 Swing 线程问题,请查看SwingUtilities该类,它为您提供了确保您在 EDT 中运行的方法。此外,您可以用 Swing 替换它,而不是直接休眠您的线程javax.swing.Timer(注意不要将其与 混淆java.util.Timer)。

于 2011-06-17T09:55:26.727 回答
4

正如@Riduidel 所提到的,任何与 Swing 相关的事情都发生在 Event Dispatch Thread 或EDT. 这是因为 Swing 不是线程安全的。调用时popup(),您应该执行以下操作

if(SwingUtilities.isEventDispatchThread()){
    Message.popup(...);
}
else{
    SwingUtilities.invokeLater(new Runnable(){
        @Override
        public void run(){
            Message.popup(...);
        }
    });
}

这将确保JFrameEDT. 此外,从您发布的代码片段来看,它似乎Message应该有一个私有构造函数。另外,既然你没有做任何自定义渲染,为什么不直接创建一个JFrame成员变量而不是扩展类呢?——对我来说似乎有点多余。

无论如何,您也不应该sleep在其中EDT任何一个中,因为这会使 GUI 看起来“冻结”并阻止其他排队事件的执行。执行长时间运行的任务时,请使用SwingWorker或@Riduidel 提到的javax.swing.Timer. 但是,如果您更喜欢java.util.Timer使用.SwingUtilitiesRunnableEventQueueEDT

编辑

这是我要做的(是的,它有效)

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
    }
});
于 2011-06-17T10:25:24.017 回答
2
update(getGraphics()); 

永远不要使用 update() 方法或 getGraphics() 方法。

调用 update() 用于 AWT NOT Swing。

如果您需要进行自定义绘画,那么您可以覆盖已经可以访问图形对象的组件的 paintComponent() 方法。

于 2011-06-17T15:13:28.930 回答