Неправильное поведение JDialog

JDialog dialog = new JDialog(parent JFrame, "blabla");
dialog.setLayout(new BorderLayout());

JLabel label = new JLabel("more blabla");

dialog.getContentPane().add(label, BorderLayout.CENTER);

dialog.setSize(new Dimension(280, 80));
dialog.setLocationRelativeTo(parent JFrame);
dialog.setVisible(true);

//part of code that takes time to execute
//actually, I'm sending an email here, but it doesn't really matter what I do,
//as you will read below        

dialog.dispose();

У меня есть приведенный выше код, и он используется для отображения сообщения пользователю во время выполнения некоторого кода (выполнение кода занимает около 5-10 секунд, я не хочу, чтобы пользователь думал, что программа зависла).

Проблема в том, что JLabel, добавленный в диалоговое окно, вообще не отображается. Что бы я ни добавлял в диалоговое окно, оно не появляется, если быть точным.

Однако, если я установлю для JDialog модальный режим (добавлю true в качестве последнего аргумента в приведенный выше конструктор), он появится, но тогда код, который я хотел выполнить, не будет выполняться до тех пор, пока диалог не будет закрыт, вопреки его цели.

Код, который будет выполняться, на самом деле не имеет значения из-за его положения в коде, и я попытался оставить его в том виде, в котором он сейчас указан выше - вообще без исполняемого кода - диалоговое окно появлялось на долю секунды, но я мог его видеть был пуст.

Я знаю, что мог бы создать окно подтверждения и сказать «ожидание в течение 10 секунд, код выполняется», но я не хочу делать это таким образом.

Я также попытался поменять JDialog на JFrame, текст все равно не появился.

Что мне не хватает?


person Karlovsky120    schedule 13.09.2012    source источник


Ответы (1)


Если длительная задача выполняется Event Dispatch Thread (восточноевропейское время), то у диалогового окна может не быть возможности отрисовать/перерисовать себя, пока задача не будет завершена. Ознакомьтесь с руководством по Concurrency in Swing, чтобы получить дополнительные сведения о EDT.

Вот пример, который использует ваш код и демонстрирует диалоговое окно неправильного поведения:

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class TestDialog {

    private static void createAndShowGUI() {
        final JFrame frame = new JFrame("Demo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JButton button = new JButton("Execute");
        button.addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                final JDialog dialog = new JDialog((JFrame)frame, "blabla");
                dialog.setLayout(new BorderLayout());
                JLabel label = new JLabel("more blabla");
                dialog.getContentPane().add(label, BorderLayout.CENTER);

                dialog.setSize(new Dimension(280, 80));
                dialog.setLocationRelativeTo(frame);
                dialog.setVisible(true);

                try {
                    Thread.sleep(3000);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }

                dialog.setVisible(false);
                dialog.dispose();
            }

        });

        frame.add(button);          
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}

Рассмотрите возможность рефакторинга своей реализации, выполнив длительную задачу в рабочем потоке. Например, это можно сделать с помощью SwingWorker.

Вот демо, иллюстрирующее тот же диалог с простым воркером:

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingWorker;

public class TestDialogWithWorker {

    private static void createAndShowGUI() {
        final JFrame frame = new JFrame("Demo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JButton button = new JButton("Execute");
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                new Worker(frame).execute();
            }

        });

        frame.add(button);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    static class Worker extends SwingWorker<Void, Void> {
        JDialog dialog;

        public Worker(JFrame parent) {
            dialog = new JDialog((JFrame) parent, "blabla");
            dialog.setLayout(new BorderLayout());
            JLabel label = new JLabel("more blabla");
            dialog.getContentPane().add(label, BorderLayout.CENTER);

            dialog.setSize(new Dimension(280, 80));
            dialog.setLocationRelativeTo(parent);
            dialog.setVisible(true);
        }

        @Override
        protected Void doInBackground() throws Exception {
            Thread.sleep(3000);
            return null;
        }

        @Override
        protected void done() {
            dialog.setVisible(false);
            dialog.dispose();

            try {
                get();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }       
}
person tenorsax    schedule 13.09.2012
comment
1+ показано довольно много усилий и очень красивый код. Спасибо. - person Hovercraft Full Of Eels; 13.09.2012
comment
@kleopatra не так уж применима в этом демонстрационном случае, но без вызова get() вы не узнаете, что в doInBackground() произошло исключение. - person tenorsax; 29.09.2012