Java: GUI должны быть инициализированы в потоке EDT?


2

Я - Джейсон. У меня проблемы с внешним видом (https://substance.dev.java.net/).

Моя проблема более общая. Я уже написал свой графический интерфейс, и все работает отлично, но когда я использую Look-and-feel вещества, он требует, чтобы вся инициализация GUI происходила в потоке EDT (Event Dispatching Thread или что-то еще).

Сейчас я использую com.sun.java.swing.plaf.windows.WindowsLookAndFeel (не уверен, что я записал это право), и он не требует ничего подобного.

Поэтому я поместил основную инициализацию в EDT, вызвав SwingUtilities.invokeLater(). Это заставило его работать. Тем не менее, программа также запускает несколько других окон во время ее выполнения. Сейчас у меня есть код, как:

SomeNewWindow window = new SomeNewWindow(); 
// ... some bs emitted 
window.doStuff(); 

Этот код прекрасно работает, потому что к тому времени window.doStuff() вызывается, это уже инициализирована. Но субстанция требует от меня, чтобы сделать что-то вроде этого:

SwingUtilities.invokeLater(new Runnable(){ 
public void run(){ 
SomeNewWindow window = new SomeNewWindow(); 
}}); 
// ... bs emitted 
window.doStuff(); 

Здесь иногда бросает NullPointerException, потому что окно не инициализируется во время window.doStuff() называется. Я не могу поместить window.doStuff() в поток EDT, потому что обычно требуется несколько секунд для возврата и зависает GUI.

Я попытался поставить Thread.sleep (1000) сразу после того, как я вызываю поток EDT, потому что он, вероятно, инициализируется к тому времени. Но это кажется неудобным. Мне просто нужен способ, чтобы основной поток «знал», когда инициализация SomeNewWindow вернулась, чтобы продолжить, не беспокоясь об исключении NullPointerException.

Заранее спасибо.

5

Вы можете переключиться с invokeLater на invokeAndWait, который будет ждать, пока не будет создано окно. Это немного дрянной, но не так плохо, как спать.

  0

Это работает! Никогда не знал, что существует. * facepalm * 21 фев. 092009-02-21 23:14:51


0

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

Другой способ - использовать флаг volatile, который инициализатор может установить, когда это будет сделано, чтобы другой поток мог проверить его в цикле и действовать в новом окне после установки флага.


0

Egwor предлагает использовать вместо этого CountDownLatch. Определенно выглядит так, что это упростит ситуацию.


Это работа для condition variables.

В основном, в run(), блокировка замка, построение нового окна и сигнализация состояния (и разблокировка блокировки). «Между тем», в другой ветке, делайте свои «bs», блокируйте замок; если окно равно null, wait() в переменной условия; разблокировать замок; window.doStuff();

  0

Я думаю, что обратный отсчет может быть лучше, нет? 21 фев. 092009-02-21 22:42:40

  0

Может быть. Я не знаю, что защелка обратного отсчета :) 21 фев. 092009-02-21 22:44:16


0

Есть ли причина, по которой вы не можете просто переместить вызов doStuff() в обратный вызов invokeLater?

SwingUtilities.invokeLater(new Runnable(){ 
    public void run(){ 
     SomeNewWindow window = new SomeNewWindow(); 
     window.doStuff(); 
    } 
}); 

Если выше невозможно, я бы с invokeAndWait() вместо invokeLater(), как Павел Tomblin уже предложил.

  0

И нет, потому что window.doStuff обычно занимает несколько секунд или минут. Я пытаюсь это сделать, и окно становится прозрачным для того времени. 22 фев. 092009-02-22 22:10:05

  0

Согласованная, плохая идея :-) 24 фев. 092009-02-24 21:55:53