JDialog中的组件未显示

时间:2011-06-17 09:46:48

标签: java swing jdialog

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

有时,当我在下面的代码中运行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());,框架总是空的,但有了它,它取决于风向的方向......(去图!)

3 个答案:

答案 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成员变量而不是扩展类? - 对我来说似乎有点多余。

无论如何,你也不应该在sleepEDT,因为这会使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()方法。