Ожидание ввода мыши в Java Swing

Я работаю над приложением Java Swing. У меня есть кнопка, действие которой запускает запрос к базе данных, а затем отображает результаты. Эти команды выполняются из слушателя на кнопке Run. Насколько я понимаю, это означает, что поток, работающий в этот момент, принадлежит EventQueue.

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

Любая помощь приветствуется. Заранее спасибо.


person Ryan    schedule 20.10.2009    source источник


Ответы (3)


Пусть EventDispatcherThread обрабатывает ввод. Скорее, ваш порожденный поток должен выполнять вычисления. Я создал интерактивный пользовательский интерфейс, который делал что-то подобное год или два назад, и именно так я добился такого поведения.

По сути, вы создаете модель производителя/потребителя между графическим интерфейсом и потоком обработки данных. Когда ввод срабатывает, вы передаете потоку потребителя и возобновляете активность.

person Stefan Kendall    schedule 20.10.2009
comment
Все, что вам нужно сделать, это создать экземпляр SwingWorker, в котором долгосрочный код базы данных находится в методе doInBackground(), а последующие обновления пользовательского интерфейса — в методе done(), и выполнить этот поток SwingWorker в ActionListener вашей кнопки. - person Chris B.; 06.11.2009

Используйте класс SwingWorker.

person alphazero    schedule 20.10.2009
comment
Я создал свое приложение до версии 1.6. Если у вас есть доступ к 1.6, обязательно используйте SwingWorker. - person Stefan Kendall; 20.10.2009
comment
К сожалению, я застрял на 1,5. У меня Mac на базе Intel, и в последний раз, когда я проверял, версия 1.6 была мне недоступна. - person Ryan; 20.10.2009
comment
Класс SwingWorker отлично подходит для демонстраций, но я бы не хотел, чтобы он использовался в рабочем коде. Это наносит ущерб дизайну, тесно связывая действия пользовательского интерфейса в EDT с действиями, не связанными с пользовательским интерфейсом, за пределами EDT. - person Tom Hawtin - tackline; 20.10.2009
comment
@Tom Hawtin - Что бы вы предложили для производственного кода? Я согласен, что это низкий уровень, но, честно говоря, когда вам нужно запустить длительную задачу вне EDT, у вас мало другого выбора, и в этом случае проверенный временем, отлаженный API — правильный путь. - person Nemi; 20.10.2009
comment
SwingWorker — это определенно то, что нужно. Вы можете получить порт для 1.5 версии 1.6 здесь: swingworker.dev.java.net - person Chris B.; 06.11.2009
comment
@nemi new Thread(new Runnable() {public void run() { /\* ... do work ... \*/ SwingUtilities.invokeLater(new Runnable() { /\* ... post results ... \*/ })) }}) - person David Moles; 17.03.2016
comment
(Однако, только если бы я застрял в Java 5. Java 6 или более поздняя версия, я бы использовал ExecutorService. И на самом деле, у IIRC был бэкпорт Java 5 пакета параллелизма Java 6.) - person David Moles; 17.03.2016

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

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

class QueryPerformer implements Runnable {
     private volatile boolean plotAreaClicked;

     public void run() {
         // Perform query and process
         while (!plotAreaClicked) {
              try {
                   Thread.sleep(500);
              } catch (InterruptedException exception) {
              }
         }
         // Perform tasks following plot area click
     }

     public void setPlotAreaClicked(boolean plotAreaClicked) {
         this.plotAreaClicked = plotAreaClicked;
     }
}

И в ваших прослушивателях пользовательского интерфейса:

private QueryPerformer queryPerformer;

public void actionPerformed(ActionEvent event) {
    // Run button pressed
    queryPerformer = new QueryPerformer();
    new Thread(queryPerformer).start();
}

public void mouseClicked(MouseEvent event) {
    // Plot area clicked
    if (queryPerformer != null) {
        queryPerformer.setPlotAreaClicked(true);
    }
}

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

person Russ Hayward    schedule 24.10.2009