Почему InvokeLater заставляет мой JFrame не отображаться правильно?

Универсальные наборы будут работать лучше, чем их неуниверсальные дубликаты, особенно при итерации через многие объекты. Это вызвано тем, что упаковка и распаковывание больше не происходят.

6
задан CSchulz 27 January 2012 в 16:27
поделиться

5 ответов

invokeLater запускает Runnable в потоке отправки событий, который также используется для обновления графического интерфейса.
Ваш сон блокирует этот поток, поэтому графический интерфейс также не обслуживается , никакие обновления не могут быть выполнены, пока вы не вернетесь из кода invokeLater.
Вот почему вам не следует выполнять в этом потоке какие-либо длительные (требующие много времени) вычисления. Они должны выполняться в другом (новом) потоке.

Очередь отправки событий указывает

Задачи в потоке отправки событий должны завершаться быстро; в противном случае необработанные события сохраняются, и пользовательский интерфейс перестает отвечать.

Ваш код можно изменить на (не проверено):

public Example(){
    System.out.println("Example started");
    setBounds(100,100,200,200);

    System.out.println("cmGUI instantiated");
    CheckingMessagesGUI cmGUI = new CheckingMessagesGUI();
    System.out.println("Set cmGUI visible");
    cmGUI.setVisible(true);
    cmGUI.validate();

    Thread thread = new Thread(new Runnable() {
        try {
            System.out.println("timer started");
            Thread.sleep(5000);
            System.out.println("timer done");
        } catch(InterruptedException e) {
        }
        System.exit(0);
    });
    thread.start();
}

РЕДАКТИРОВАТЬ: давайте пойдем немного «глубже» (и это мой взгляд на работу Swing / AWT).
Я полагаю, что «пожалуйста, подождите» (см. Комментарии) должно отображаться в классе CheckingMessagesGUI, но это не так.
Это связано с тем, как работает графический интерфейс. Он ничего не меняет напрямую на дисплее, если вы вызываете соответствующие методы (Swing) (draw, setText, setLocation, ...); он просто помещает событие в очередь событий. Поток отправки событий является (должен быть) единственным потоком, который читает эту очередь и обрабатывает события. Пока он заблокирован - в данном случае из-за спящего режима - никакие изменения в графическом интерфейсе отображаться не будут. Графический интерфейс заблокирован.

РЕДАКТИРОВАТЬ2:
invokeLater Runnable добавлен в конец очереди для последующего выполнения EDT после того, как все ожидающие события были обработаны, следующее команда после вызова invokeLater будет выполнена.
invokeAndWait То же, что и выше, но фактический поток блокируется до тех пор, пока EDT не выполнит Runnable (после ожидающих событий), то есть

4
ответ дан 17 December 2019 в 02:30
поделиться

Насколько я понимаю, цель InvokeLater заключается в том, что элементы запускаются в правильном потоке событий AWT

Это правильно.

Однако это также означает, что Thread.sleep () выполняется в EDT, а это означает, что графический интерфейс не может перерисоваться, поскольку вы только что сказали EDT спать. Вам необходимо использовать отдельный поток для вашей длительной задачи.

Прочтите раздел из учебника Swing на Concurrency для получения дополнительной информации о EDT.

но я хотел сказать: «пожалуйста, подождите " (CheckingMessagesGUI) должен иметь уже был полностью нарисован до того, как я called sleep. Shouldn't this be true?

Here is my simplified understanding of the process. The frame is created and displayed because it is an OS native component. However, the contentPane and child component are lightweight components which means the Swing Repaint Manager schedules when they should be repainted. So before the repainting is scheduled, the EDT is put to sleep, and the repainting can't be done until the sleeping is finished.

You can find more infomation about the Repaint Manager in the article on Paintng in AWT and Swing.

1
ответ дан 17 December 2019 в 02:30
поделиться

My answer was that when the GUI is constructed its not automatically painted at that time, instead a call to paint is placed in the EDT queue. If in the same method you construct a GUI object, and setVisible(true) then in the next few lines do something intensive, it blocks the future call to paint from occurring, because it will not get placed into the EDT queue until that method (with the intensive stuff) finishes. Also as was mentioned the frame or border is on the platform side of the equation (hence gets drawn), and the rest (Jlabel, container, background, etc) is on the java side and doesn't happen until paint is actually run (i.e. the EDT queue gets to it). My example code worked without the InvokeLater call, because that ran the intensive stuff in the init thread, and allowed the EDT thread to still paint.

0
ответ дан 17 December 2019 в 02:30
поделиться

Invisible components are not painted.

0
ответ дан 17 December 2019 в 02:30
поделиться

Вот общий раствор для новичков, таких как я, у которых проблемы с нахождением того, что им нужно в качелях.

public void method(){
    final PleaseWaitWindow window = new PleaseWaitWindow();

    Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            //stuff that you want to do that is preventing window to display

            window.dispose();
        }
    }
    thread.start();
}
1
ответ дан 17 December 2019 в 02:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: