2009-12-03 4 views
5

Хорошо, что я прочитал обыск в Интернете, и я еще не нашел решение моей проблемы, возможно, я пропустил что-то простое, поэтому здесь я ...Почему InvokeLater вызывает неправильное отображение JFrame?

У меня есть довольно большой проект, который обрабатывает заказы на выполнение работ по ремонту. Все подключено к базе данных, многие страницы кода и классы. Но я просто добавил короткий код кода в интерфейс, который в основном проверяет новые сообщения в области заметок.

Во всяком случае, я показываю простой JFrame с двумя JLabel с в то время как отдельный поток запросов к базе данных. Все это происходит в начале программы. Проблема в том, что мой маленький «пожалуйста, подождите» JFrame подходит к своей рамке, но без кишок, нет фона и нет JLabel s, во время ожидания (это остальная часть загрузки программы, а не поток базы данных) после этого он отображает, но к тому времени его отсутствует его точка.

Я написал следующую примерную программу. Он отображает простой JFrame (CheckingMessagesGUI: а JFrame с двумя JLabel с, не более) не спит в течение 5 сек затем показывает пример (основная программа) фрейму, а затем мгновенно закрывается (System.exit(0)) в этом примере, конечно, моя настоящая программа продолжает делать намного больше. Я обнаружил, что проблема invokeLater. Как только таймер сна закончится, отобразится окно, но код для его отображения был указан до команды Thread.sleep и должен ли быть выполнен в этом порядке правильно?

Мой вопрос: почему invokeLater вызывают мои JFrame Не отображать правильно?

Его понимание того, что цель invokeLater такова, что элементы работают на правильном потоке событий AWT, что заставило бы меня подумать, что это окно будет правильно раскрашено. Во всяком случае, я уверен, что мне не хватает чего-то очевидного. Я прокомментировал часть invokeLater в коде ниже, и он работает правильно, если вы вернете его, это не ...

Большое спасибо заранее.

package javaapplication6; 

public class Example extends javax.swing.JFrame {   
    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(); 
     try { 
      System.out.println("timer started"); 
      Thread.sleep(5000); 
      System.out.println("timer done"); 
     } catch(InterruptedException e){ 
     } 
     System.exit(0); 
    } 

    public static void main(String[] args) { 
     /*java.awt.EventQueue.invokeLater(new Runnable() { 
     @Override 
     public void run() { */ 
     System.out.println("Started"); 
     System.out.println("example Instantiated"); 
     Example example = new Example(); 
     System.out.println("example visible"); 
     example.setVisible(true); 
     /*  } 
     }); 
     */ 
    } 
} 

UPDATE: Чтобы уточнить, я понимаю Thread.sleep() будет блокировать все, но не должен мой CheckingMessagesGUI уже был полностью использован, прежде чем я вызываю сон? Это проблема.

+0

Этот форум используется программистами на самых разных языках. Теги тега должны помочь сразу определить домен, чтобы читатели могли фильтровать вопросы, которые могут им помочь. Будет ли java и awt хорошими тегами для вашего вопроса? –

ответ

4

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

The Event Dispatch Queue заявляет

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

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

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(); 
} 

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

EDIT2:
invokeLater с выполняемым является добавляется в конец очереди, чтобы быть последней исполняемой EDT после того как все отложенные события были обработаны, будет выполняться следующая команда после вызова invokeLater.
invokeAndWait так же, как указано выше, но фактические блоки Thread до тех пор, пока Runnable не будет выполнен (после ожидающих событий) EDT, то есть команда, следующая за invokeAndWait, начнется только после того, как был отправлен представленный Runnable.

+0

@Marc: Нет, он не будет рисовать, потому что картина представляет собой отдельное событие, которое было отправлено в очередь событий, но никогда не обрабатывается. Покраска не происходит с графическим дизайном (так как она должна возникать из-за системного запроса на рисование в конкретном графическом контексте). –

+0

Я думаю, что это может быть ключом «никакие обновления не могут быть выполнены, пока вы не вернетесь из кода invokeLater». Я понимаю, что Thread.sleep() блокирует все в моем примере, но я хотел сказать, что мой «please wait» (CheckingMessagesGUI) должен был быть полностью отрисован до того, как я позвонил в режим сна. Разве это не так? – Marc

+0

@Software Monkey: Но он работает, если вы не используете InvokeLater? Зачем? – Marc

1

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

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

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

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

, но моя точка в том, что мой «Пожалуйста, подождите» (CheckingMessagesGUI) должен уже втянут полностью перед тем, как называемым сном. Разве это не так?

Вот мое упрощенное понимание процесса. Кадр создается и отображается, поскольку он является родным компонентом ОС. Тем не менее, компонент contentPane и дочерний компонент являются легкими компонентами, что означает, что диспетчер Swing Repaint планирует, когда они должны быть перекрашены. Поэтому, прежде чем перепланировка запланирована, EDT укладывается в сон, и перекраска не может быть выполнена до тех пор, пока сон не будет завершен.

Дополнительную информацию о менеджере по переписке можно найти в статье на Paintng in AWT and Swing.

0

Мой ответ заключался в том, что когда графический интерфейс сконструирован, он не будет автоматически окрашен в это время, вместо этого вызов рисования помещается в очередь EDT. Если в том же методе вы создаете объект GUI и setVisible (true), то в следующих нескольких строках делаете что-то интенсивное, он блокирует будущий вызов рисования от происходящего, потому что он не будет помещен в очередь EDT до этого метода (с интенсивным материалом) заканчивается.Также, как упоминалось, рамка или граница находится на стороне платформы уравнения (следовательно, она нарисована), а остальные (Jlabel, container, background и т. Д.) Находятся на стороне java и не происходят до тех пор, пока фактически не выполняется краска (т.е. очередь EDT доходит до него). Мой примерный код работал без вызова InvokeLater, потому что он запускал интенсивный материал в потоке инициализации и позволял рисовать поток EDT.

+0

Ну, это более или менее так, как я его изложил. – camickr

0

Невидимые компоненты не окрашены.

0

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

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(); 
}