Компоненты в JDialog не отображаются - PullRequest
0 голосов
/ 17 июня 2011

Прежде всего: я знаю, что этот вопрос, кажется, задавался несколько миллионов раз, но ни один из ответов на другие вопросы, кажется, не работает со мной.

Иногда, когда я запускаю 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 ]

4 голосов
/ 17 июня 2011

Как уже упоминалось @Riduidel, важно, чтобы что-то связанное с Swing происходило в потоке диспетчеризации событий, или EDT.Это потому, что 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
    }
});
4 голосов
/ 17 июня 2011

Вы уверены, что ваш код выполняется в EDT ?действительно, если нет (то, что я ожидаю, поскольку вы sleep текущий поток, что обычно не нравится Swing), ваш кадр будет иметь проблемы с рендерингом.

Чтобы избежать этих типичных SwingПроблемы с многопоточностью. Обратите внимание на класс SwingUtilities, который предоставляет вам методы для обеспечения работы в EDT.Кроме того, вместо того, чтобы напрямую спать с вашей нитью, вы можете отменить ее с помощью Swing javax.swing.Timer (остерегайтесь не путать ее с java.util.Timer).

2 голосов
/ 17 июня 2011
update(getGraphics()); 

Никогда не используйте метод update () или метод getGraphics ().

Вызывание update () используется для AWT NOT Swing.

Если вам нужно сделать пользовательское рисованиезатем вы переопределяете метод paintComponent () вашего компонента, который уже имеет доступ к графическому объекту.

...