Перекраска в многопоточной среде - PullRequest
3 голосов
/ 24 мая 2011

Я работаю над апплетом с десятью различными источниками данных (например, статистика / журнал ошибок / ...). Каждый источник данных обновляется одним сетевым соединением и сообщает об обновлениях через механизм наблюдения. Апплет имеет разные представления, которые отображают части данных. Каждое представление интересуется только некоторыми частями данных и регистрируется в качестве наблюдателя на необходимых наблюдаемых объектах.

Представления (расширенные JPanels) в основном состоят из стандартных компонентов свинга (например, JLabels, JButton, ...). Некоторые атрибуты компонентов в представлениях зависят от информации из базовой модели данных.

Пример:

StatisticPanel::paintComponent(Graphics g) {
  clearStatisticButton.setEnabled(stat.hasEntries());
  minValueLabel.setText(stat.getMinValue());
  super.paintComponent(g);
}

Эта логика реализована в методе paintComponent() StatisticPanel, а методы update() просто вызывают repaint (), поскольку я не хотел манипулировать компонентами вне EDT.

Это предполагаемый способ обновления свинг-компонентов в многопоточной среде? Лучше использовать Runnable с SwingUtitlies.invokeLater()? Есть ли лучшие подходы к этой проблеме?

Ответы [ 2 ]

6 голосов
/ 24 мая 2011

Я второй рекомендацию camickr, но в отношении этого фрагмента кода:

StatisticPanel::paintComponent(Graphics g) {
  clearStatisticButton.setEnabled(stat.hasEntries());
  minValueLabel.setText(stat.getMinValue());
  super.paintComponent(g);
}

В вашем методе paintComponent (первые два метода) есть методы, не относящиеся к рисованию, и это не должно быть как 1) выхотите, чтобы этот метод был максимально простым и быстрым и, следовательно, имел только код, связанный с рисованием, и 2) у вас нет абсолютного контроля над тем, когда вызывается этот метод или даже если он вызывается, и поэтому код, не связанный с рисованием, илогика программы там не принадлежит.По этим причинам я настоятельно призываю вас вывести их оттуда, но вместо этого их следует называть отдельно от paintComponent, но, как и для большинства кода Swing, в EDT.

EDIT 1
Я не профессионал, но как насчет того, если бы вы дали вашей StaticPanel метод, подобный следующему:

   public void doMyUpdate() {
      if (SwingUtilities.isEventDispatchThread()) {
         clearStatisticButton.setEnabled(stat.hasEntries());
         minValueLabel.setText(stat.getMinValue());
      } else {
         SwingUtilities.invokeLater(new Runnable() {
            public void run() {
               clearStatisticButton.setEnabled(stat.hasEntries());
               minValueLabel.setText(stat.getMinValue());
            }
         });
      }
      repaint(); // if the paintComponent method has more than just a super call.
   }

РЕДАКТИРОВАТЬ 2
Также, пожалуйста, посмотрите наэтот поток: проверка-если-нить-это-необходимо-101 * *

4 голосов
/ 24 мая 2011

repaint () используется для вызова Swing RepaintManger, который, в свою очередь, будет планировать перекрашивание компонента, поэтому да, можно просто вызвать repaint напрямую. RepaintManager позаботится о том, чтобы все перекраски выполнялись на EDT.

...