Java: GUI должны быть инициализированы в потоке EDT? - PullRequest
2 голосов
/ 22 февраля 2009

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

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

Прямо сейчас я использую 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, потому что для его возврата обычно требуется несколько секунд, и графический интерфейс пользователя будет зависать.

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

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

Ответы [ 4 ]

5 голосов
/ 22 февраля 2009

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

0 голосов
/ 22 февраля 2009

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

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

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

0 голосов
/ 22 февраля 2009

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


Это задание для условных переменных .

По сути, в run () заблокируйте блокировку, создайте новое окно и сообщите состояние (и разблокируйте блокировку). "Тем временем", в другом потоке, делайте другие "бс", блокируйте блокировку; если окно пустое, wait () для условной переменной; разблокировать замок; window.doStuff ();

0 голосов
/ 22 февраля 2009

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

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

...