Как мне разработать модель Java Swing, которая также реагирует на внутренние события? - PullRequest
2 голосов
/ 19 июля 2011

Я написал графический интерфейс для работы устройства чтения карт, в основном состоящий из кнопки ADD, которая вызывает диалог FileChooser и ставит в очередь выбранный File на CardHopper, который визуально отображается как JList.

Теперь я хочу, чтобы процессор (другой JFrame в другом потоке) мог выполнять запросы устройства чтения карт; например прочитайте открытку и отправьте мне. До того, как кард-ридер имел графический интерфейс, это была просто модель, которая работала в том же потоке, что и процессор, поэтому я мог просто вызвать его метод readCard(). Теперь, когда он находится в отдельном потоке, кажется, что правильный способ общения - это передача сообщений.

Я собирался реализовать что-то, используя PriorityBlockingQueue, в результате чего ЦП будет put команду чтения карты в очереди, а CardReader будет take и выполнит команду, пока я не пойму, что поток CardReader будет обычно его блокируют где-то в его Swing-коде, предоставляемом NetBeans, в ожидании события графического интерфейса пользователя и в ожидании появления чего-либо в моей очереди событий. Более того, этот «внутренний» запрос изменил бы модель данных - поэтому, даже если бы я мог каким-то образом выполнить какой-то код в модели, было бы кошерно «пускать» уведомления в графический интерфейс пользователя ListDataListeners, пока GUI ждет событий GUI?

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

1 Ответ

4 голосов
/ 19 июля 2011

Было бы кошерно "запускать" уведомления для ListDataListeners GUI, пока GUI ожидает событий GUI?

Абсолютно нет.

Что вы хотитеdo выполняет все задачи, которые непосредственно манипулируют моделями вашего пользовательского интерфейса (или вызывают функции пользовательского интерфейса) в потоке событий Swing.

По сути, когда вы готовы опубликовать событие, которое выполнит какую-либо задачу пользовательского интерфейса, сделайте это следующим образом::

SwingUtilities.invokeLater(new Runnable() {
  public void run() {
     ...
  }
}

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

В противном случае вы рискуете, что Swing попытается прочитать ваши данные во время рисования, и вы обновляете свои данные.Вы начнете получать NullPointerException, ArrayIndexOutOfBoundExceptions, ConcurrentModifictionException и т. Д.

В идеале вы должны выполнять всю фоновую работу в отдельном потоке (или в SwingWorker), а затем, когда все будет готово, отправить обновление черезinvokeLater.

...