【问题标题】:Components in JDialog not showingJDialog 中的组件未显示
【发布时间】:2011-09-17 01:28:40
【问题描述】:

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

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

【问题讨论】:

  • "..有时 JFrame 是空的" 什么 JFrame?为了尽快获得更好的帮助,请发布SSCCE(在您研究的数百万个线程中可能已经提到了几千次)。
  • @Andrew 抱歉,我更新了代码,它现在扩展了 JDialog 而不是 JFrame。我的错!已进行更改。

标签: java swing jdialog


【解决方案1】:
update(getGraphics()); 

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

调用 update() 用于 AWT NOT Swing。

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

【讨论】:

    【解决方案2】:

    正如@Riduidel 所提到的,任何与Swing 相关的事情都发生在Event Dispatch Thread 或EDT 上是很重要的。这是因为 Swing 不是线程安全的。调用popup()时,你应该做以下事情

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

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

    无论如何,您也不应该在EDT 中使用sleep,因为这会使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
        }
    });
    

    【讨论】:

    • @mre 我现在意识到我对 Swing 一无所知 ;-) 非常感谢您提供有关该问题的所有信息!
    • @Oltarus,如果您仍然遇到问题,请告诉我! :)
    • @mre 我还是有问题。我做了你说的,包括定时器的东西,但有时,它仍然没有显示。如果它可以帮助理解,当我最小化/恢复框架时,is 显示的文本会消失。
    • 你的 if(SwingUtilities.isEventDispatchThread()) 今天为我节省了很多时间!!
    • @StephaneGrenier,很高兴听到! :)
    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 2015-12-24
      • 2012-09-19
      • 1970-01-01
      • 2023-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-12
      相关资源
      最近更新 更多