2013-09-10 1 views
1

У меня есть два потока. Один работает бизнес-логику от моего класса BulkProcessor который обновляет() переменную BulkProcessor.getPercentComplete:Обновление потока Java jProgressBar не обновляется при вызове потока снова

public void run(){ 
    new SwingWorker<Void,Void>() { 
     protected Void doInBackground() throws Exception { 
     BulkProcessor.main(jTextField0.getText(), jTextField1.getText()); 
     return null; 
     }; 
    }.execute(); 
} 

Мой другой поток является то, что обновляет ценность JProgressBar в моем BulkGUI классе:

public void update(){ 
    jProgressBar0.setStringPainted(true); 
    jProgressBar0.repaint(); 
    new SwingWorker<Void,Integer>() { 
    protected Void doInBackground() throws Exception { 
     do 
     { 
      percentComplete = BulkProcessor.getPercentComplete(); 
      publish(percentComplete); 
      Thread.sleep(100); 
     } while(percentComplete < 100); 
     return null; 
     } 
     @Override 
     protected 
     void process(List<Integer> progress) 
     { 
      jProgressBar0.setValue(progress.get(0)); 
     } 
}.execute(); 
} 

я называю два потока при нажатии кнопки «Процесс»:

private void jButton0ActionActionPerformed(ActionEvent event) { 
run(); 
update(); 
} 

Выполнение этого в первый раз работает точно так, как ожидалось. Однако выбор кнопки «Процесс» второй раз не влияет на jProgressBar. Локальная переменная percentComplete в потоке обновления остается на уровне 100 и не обновляется, как это делает первый запуск. Я тестировал переменную percentComplete из класса BulkProcessor, и эта переменная действительно обновляется, как ожидалось. Поэтому по какой-то причине поток не извлекает значения обновления с помощью BulkProcessor.getPercentComplete() во второй раз, когда вызывается поток. У кого-нибудь есть представление об этом? Буду признателен за любую оказанную помощь.

+0

пожалуйста, причина в этой идее – mKorbel

+0

Таким образом, пользователь может обрабатывать несколько раз без перезапуска GUI – TaylorSmolik

ответ

2

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

  • reset percentComplete каждый раз, когда код запускается.
  • Избегайте совершать вызовы Swing из фоновой темы, включая чтение текстового поля.
  • Скорее сделайте это в конструкторе SwingWorker, а не в его методе doInBackground(...).
  • Вы создаете статические поля и/или вызовы методов. Если это так, не делайте этого, так как это укусит вас в конце, а вместо этого создаст и передаст действительные ссылки.
  • Я предполагаю, что для этого вам нужно создать новый объект BulkProcessor.
  • Вызов run(), а затем update(), как вы делаете, получение двух потоков для запуска одновременно выглядит опасным для меня, возможно настроенным для состояния гонки.

Редактировать

Вы должны смотреть используя свойство прогрессировать SwingWorker с более PropertyChangeListener. Например:

public class FooGUI { 

    // ..... 

    public void myRun() { 
     String text1 = someTextField.getText(); 
     String text2 = otherTextField.getText(); 
     final BulkProcessor bulkProcessor = new BulkProcessor(text1, text2); 
     bulkProcessor.addPropertyChangeListener(new PropertyChangeListener() { 

     @Override 
     public void propertyChange(PropertyChangeEvent pcEvt) { 
      if (pcEvt.getPropertyName().equals("progress")) { 
       int progress = bulkProcessor.getProgress(); 
       someProgressBar.setValue(progress); 
      } 
     } 
     }); 
    } 
} 

class BulkProcessor extends SwingWorker<Void, Void> { 
    private Random random = new Random(); // just for SSCCE sake 
    private String text1; 
    private String text2; 

    public BulkProcessor(String text1, String text2) { 
     this.text1 = text1; 
     this.text2 = text2; 
     // not sure what you do with these texts.... 
    } 

    @Override 
    protected Void doInBackground() throws Exception { 
     int progress = 0; 
     while (progress <= 100) { 
     progress = random.nextInt(5); // just as a for instance 
            // your code will do something else of course 
     setProgress(progress); 
     Thread.sleep(300); 
     } 
     return null; 
    } 

} 

Например:

import java.awt.event.*; 
import java.beans.*; 
import java.util.Random; 
import javax.swing.*; 

@SuppressWarnings("serial") 
public class Foo3 extends JPanel { 
    private static final String DEFAULT_SPEED = "15"; 
    private JTextField speedTextField = new JTextField(DEFAULT_SPEED, 5); 
    private JProgressBar someProgressBar = new JProgressBar(); 
    private RunAction runAction = new RunAction(); 
    private JButton runButton = new JButton(runAction); 

    public Foo3() { 
     speedTextField.setAction(runAction); 

     add(new JLabel("Speed:")); 
     add(speedTextField); 
     add(someProgressBar); 
     add(runButton); 
    } 

    public void myRun() { 
     String speedText = speedTextField.getText(); 
     try { 
     int speed = Integer.parseInt(speedText); 
     final BulkProcessor bulkProcessor = new BulkProcessor(speed); 
     bulkProcessor.addPropertyChangeListener(new PropertyChangeListener() { 

      @Override 
      public void propertyChange(PropertyChangeEvent pcEvt) { 
       if (pcEvt.getPropertyName().equals("progress")) { 
        int progress = bulkProcessor.getProgress(); 
        someProgressBar.setValue(progress); 
       } 
       if (pcEvt.getPropertyName().equals("state")) { 
        if (bulkProcessor.getState().equals(
         SwingWorker.StateValue.DONE)) { 
        someProgressBar.setValue(0); 
        setGuiEnabled(true); 
        } 
       } 
      } 
     }); 
     setGuiEnabled(false); 
     bulkProcessor.execute(); 
     } catch (NumberFormatException e) { 
     String text = "Speed of " + speedTextField.getText() 
       + " is invalid. Please enter an integer"; 

     JOptionPane.showMessageDialog(this, text, "Invalid Speed Value", 
       JOptionPane.ERROR_MESSAGE); 
     speedTextField.setText(DEFAULT_SPEED); 
     } 
    } 

    private class RunAction extends AbstractAction { 
     public RunAction() { 
     super("Run"); 
     putValue(MNEMONIC_KEY, KeyEvent.VK_R); 
     } 

     @Override 
     public void actionPerformed(ActionEvent arg0) { 
     myRun(); 
     } 

    } 

    private void setGuiEnabled(boolean enabled) { 
     runButton.setEnabled(enabled); 
     speedTextField.setEnabled(enabled); 
    } 

    private static void createAndShowGui() { 
     Foo3 mainPanel = new Foo3(); 

     JFrame frame = new JFrame("Foo3"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.getContentPane().add(mainPanel); 
     frame.pack(); 
     frame.setLocationByPlatform(true); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
      createAndShowGui(); 
     } 
     }); 
    } 
} 

class BulkProcessor extends SwingWorker<Void, Void> { 
    private Random random = new Random(); // just for SSCCE sake 
    private int speed; 

    public BulkProcessor(int speed) { 
     this.speed = speed; 
    } 

    @Override 
    protected Void doInBackground() throws Exception { 
     int progress = 0; 
     while (progress <= 100) { 
     progress += random.nextInt(speed); 
     setProgress(progress); 
     Thread.sleep(300); 
     } 
     return null; 
    } 

} 
+0

+1 Почти гарантировано. Рабочий 'update()' будет завершен, если другой рабочий не изменит процент завершения до того, как второй прочитает его в первый раз. – kiheru

+0

Итак, я сделал set percentComplete = 0; когда нажата кнопка процесса (до вызова потоков), и напечатайте значения percentComplete до и после percentComplete = BulkProcessor.getPercentComplete() в моем потоке update(). Результат percentComplete будет равен 0, прежде чем BulkProcessor.getPercentComplete() будет вызван и вернется обратно к 100 после. – TaylorSmolik

+0

@TaylorSmolik Тогда я бы посмотрел, что возвращает 'getPercentComplete()'. Кроме того, скорее всего, вы должны использовать * last * элемент в 'process()', а не первый. – kiheru

0

Таким образом установлено, что изменения в то время как (PERCENTCOMPLETE < 100) в то время (PERCENTCOMPLETE < = 100) держит нить работает на постоянной основе. Это действительно исправляет проблему, но не рекомендуется.