2014-12-23 2 views
0

У меня есть JAVA6 GUI обработка данных импорт в нашу базу данных. Я реализовал рабочий JProgressBar. Я понимаю, что изменения, внесенные в GUI, должны выполняться через поток отправки событий, который я не думаю, что я делаю (правильно/вообще).Swing Progress Bar обновляется через Worker to EventDispatch thread

фона рабочего потока, UploadWorker, строится путем пропускания в виде JProgressBar, созданной в основной программе, и устанавливает изменяет значение индикатора выполнения непосредственно после его Выполнил:

// when constructed, this gets set to the main program's JProgressBar. 
JProgressBar progress; 



protected Void doInBackground() throws Exception { 
    write("<!-- Import starting at " + getCurrentTime() + " -->\n"); 
    boolean chunked = false; 
    switch (importMethod) { 

      //do some importing 

    } 

    write("<!-- Import attempt completed at " + getCurrentTime() + "-->\n"); 

    //here changes to the GUI are made 
    progress.setMaximum(0); 
    progress.setIndeterminate(false); 
    progress.setString("Finished Working"); 
    return null; 
} 

Это прекрасно работает , но иногда (не всегда) бросает мне несколько НЭП в станд вне, и пользователи жалуются:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException 
at javax.swing.plaf.basic.BasicProgressBarUI.updateSizes(Unknown Source) 
...etc... 

во всяком случае, я считаю, есть что-то, что нужно сделать, чтобы получить эти обновления, выполняемые на соответствующую нить, правильно ? Как?

+0

только что обнаружил SwingUtilities.isEventDispatchThread, очень полезно и, как я подозревал, возвращает ложь. – tenwest

+0

Поскольку вы взаимодействуете с индикатором выполнения в методе doInBackground, я бы сказал, что вы, безусловно, нарушаете правила единственного потока Swing – MadProgrammer

+0

Мне всегда нравится этот [пример рабочего swing] (http://www.javacreed.com/swing-worker-example /) – nachokk

ответ

0

Вы можете просто создать новый Runnable, который выполняет обновления GUI и вызвать его в GUI потоке, используя SwingUtilities.invokeLater

+0

Из звуков, если это, вы предлагаете, чтобы OP создавал «Runnable», который выполняет там длительную работу/блокировку и вызывает его с помощью 'invokeLater', если это так , что поставит их в худшее место, тогда они будут прямо сейчас ... – MadProgrammer

+0

@MadProgrammer Не ясно, что я предлагаю создать Runnable, который выполняет только обновления GUI (а не операции вычисления/блокировки) и вызывает его с помощью invokeLater? – kraskevich

+0

Нет, иначе я бы не прокомментировал (я был с тех пор, как я думал, что мой мозг не может прерывать ответ совершенно правильно). Кроме того, 'SwingWorker' предоставляет методы' publish'/'process' для отправки обновлений для EDT, а также встроенная поддержка прогресса и уведомление через поддержку PropertyChange ... – MadProgrammer

3

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

Лучшее решение воспользоваться в SwingWorker сек прогресса и поддержки PropertyChange, например ....

worker.addPropertyChangeListener(new PropertyChangeListener() { 
    @Override 
    public void propertyChange(PropertyChangeEvent evt) { 
     if ("state".equalsIgnoreCase(evt.getPropertyName())) { 
      SwingWorker worker = (SwingWorker) evt.getSource(); 
      switch (worker.getState()) { 
       case DONE: 
        // Clean up here... 
        break; 
      } 
     } else if ("progress".equalsIgnoreCase(evt.getPropertyName())) { 
      // You could get the SwingWorker and use getProgress, but I'm lazy... 
      pb.setIndeterminate(false); 
      pb.setValue((Integer)evt.getNewValue()); 
     } 
    } 
}); 
worker.execute(); 

Это означает, что вы могли бы сделать это для любого SwingWorker, так долго, как это было работник звали setProgress внутренне ...

public static class ProgressWorker extends SwingWorker { 

    public static final int MAX = 1000; 

    @Override 
    protected Object doInBackground() throws Exception { 
     for (int index = 0; index < MAX; index++) { 
      Thread.sleep(250); 
      setProgress(Math.round((index/(float)MAX) * 100f)); 
     } 
     return null; 
    } 

} 

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

И полностью работоспособный пример ...

import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.GridBagLayout; 
import java.beans.PropertyChangeEvent; 
import java.beans.PropertyChangeListener; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JProgressBar; 
import javax.swing.SwingWorker; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 

public class SwingWorkerProgressExample { 

    public static void main(String[] args) { 
     new SwingWorkerProgressExample(); 
    } 

    public SwingWorkerProgressExample() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
        ex.printStackTrace(); 
       } 

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.add(new TestPane()); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public class TestPane extends JPanel { 

     private JProgressBar pb; 

     public TestPane() { 

      setLayout(new GridBagLayout()); 
      pb = new JProgressBar(0, 100); 
      pb.setIndeterminate(true); 
      add(pb); 

      ProgressWorker worker = new ProgressWorker(); 
      worker.addPropertyChangeListener(new PropertyChangeListener() { 
       @Override 
       public void propertyChange(PropertyChangeEvent evt) { 
        if ("state".equalsIgnoreCase(evt.getPropertyName())) { 
         SwingWorker worker = (SwingWorker) evt.getSource(); 
         switch (worker.getState()) { 
          case DONE: 
           // Clean up here... 
           break; 
         } 
        } else if ("progress".equalsIgnoreCase(evt.getPropertyName())) { 
         // You could get the SwingWorker and use getProgress, but I'm lazy... 
         System.out.println(EventQueue.isDispatchThread()); 
         pb.setIndeterminate(false); 
         pb.setValue((Integer) evt.getNewValue()); 
        } 
       } 
      }); 
      worker.execute(); 

     } 

     @Override 
     public Dimension getPreferredSize() { 
      return new Dimension(200, 200); 
     } 

    } 

    public static class ProgressWorker extends SwingWorker { 

     public static final int MAX = 1000; 

     @Override 
     protected Object doInBackground() throws Exception { 
      for (int index = 0; index < MAX; index++) { 
       Thread.sleep(250); 
       setProgress(Math.round((index/(float) MAX) * 100f)); 
      } 
      return null; 
     } 

    } 

} 
+0

Я думаю, что это действительно полезно! Я забыл упомянуть, что фактические обновления индикатора выполнения выполняются с помощью ContainerListener, но если я правильно понимаю этот код, то рабочий делает это сам, что, вероятно, является лучшим подходом. – tenwest

+0

Ну, рабочий, в этом примере, вычисляет прогресс, который запускает событие изменения свойства, которое затем позволяет «TestPane» обновлять индикатор выполнения ... пытаясь сохранить его развязку: P – MadProgrammer

+0

whoa! Хорошо. наконец, успел посидеть и изучить ваш ответ. Раньше я не видел PropertyChangeListener. Был немного смущен (и все еще до тех пор, пока я не попробую) разных строк, которые возвращаются из 'Event.getPropertyName'. FYI я использую Джерси 'ContainerListener' для отслеживания прогресса, поскольку он обрабатывает загрузки HTTP. OP отразил последний шаг, когда панель «очищается», как вы упоминаете. – tenwest

 Смежные вопросы

  • Нет связанных вопросов^_^