MVC Progress Bar Threading - PullRequest
       20

MVC Progress Bar Threading

9 голосов
/ 04 апреля 2011

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

Я пытался использовать Swingworker, но индикатор выполнения не обновляется.Я подозреваю, что я делаю что-то не так с моим потоком.

Моя кнопка, как определено в контроллере:

 class SearchBtnListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            _view.displayProgress();  
        }    
}

Это вызывает поиск в модели и имеет следующий вызов в представлении:

public void displayProgress() {

    TwoWorker task = new TwoWorker();
    task.addPropertyChangeListener(new PropertyChangeListener() {

         @Override
         public void propertyChange(PropertyChangeEvent e) {
             if ("progress".equals(e.getPropertyName())) {
                _progressBar.setValue((Integer) e.getNewValue());
             }
         }

     });
     task.execute();             
}      


private class TwoWorker extends SwingWorker<Void, Void> {        
    @Override
    protected Void doInBackground() throws Exception {
        _model.startSearch(getTerm());                  // time intensive code
        File file = new File("lock");           
        while (file.exists()){
            setProgress(_model.getStatus());
            System.out.println(_model.getStatus()); // never called
        }           
        return null;
    }  

    protected void done(){
        updateMain();
    }
}

Фиктивная функция, определенная в модели для тестирования:

public int getStatus(){
    Random r = new Random();
    return r.nextInt();
}

1 Ответ

12 голосов
/ 04 апреля 2011

Не вызывайте

_progressBar.setValue(_model.getStatus());

изнутри вашего SwingWorker, так как это вызывает код Swing из фонового потока и для чего в любом случае предназначен PropertyChangeListener.Вместо этого просто установите свойство progress, и все.

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

Кроме того, Done () должно быть сделано () - первая буква не должна начинаться с заглавной буквы, и вы должны использовать аннотации @Override вэтот код, чтобы вы могли быть уверены, что вы корректно переопределяете методы.

Кроме того, что это делает?

 _model.startSearch(_view.getTerm());

Вызывает ли он код, выполнение которого занимает некоторое время?Должна ли она быть инициализирована из самого SwingWorker doInBackground?

Редактировать: Еще один вариант - присвоить Model привязанное свойство int, скажем, называемое progress, а затем добавить к нему PropertyChangeListener, позволяя ему обновить JProgressBar.Например,

import java.awt.BorderLayout;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

import javax.swing.*;

public class MVC_ProgressBarThread {
   private static void createAndShowUI() {
      MVC_View view = new MVC_View();
      MVC_Model model = new MVC_Model();
      MVC_Control control = new MVC_Control(view, model);
      view.setControl(control);

      JFrame frame = new JFrame("MVC_ProgressBarThread");
      frame.getContentPane().add(view);
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      java.awt.EventQueue.invokeLater(new Runnable() {
         public void run() {
            createAndShowUI();
         }
      });
   }
}

@SuppressWarnings("serial")
class MVC_View extends JPanel {
   private MVC_Control control;
   private JProgressBar progressBar = new JProgressBar();
   private JButton startActionButton = new JButton("Start Action");

   public MVC_View() {
      startActionButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            buttonActionPerformed();
         }
      });

      JPanel buttonPanel = new JPanel();
      buttonPanel.add(startActionButton);
      setLayout(new BorderLayout());
      add(buttonPanel, BorderLayout.NORTH);
      add(progressBar, BorderLayout.CENTER);
   }

   public void setControl(MVC_Control control) {
      this.control = control;
   }

   private void buttonActionPerformed() {
      if (control != null) {
         control.doButtonAction();
      }
   }

   public void setProgress(int progress) {
      progressBar.setValue(progress);
   }

   public void start() {
      startActionButton.setEnabled(false);
   }

   public void done() {
      startActionButton.setEnabled(true);
      setProgress(100);
   }
}

class MVC_Control {
   private MVC_View view;
   private MVC_Model model;

   public MVC_Control(final MVC_View view, final MVC_Model model) {
      this.view = view;
      this.model = model;
      model.addPropertyChangeListener(new PropertyChangeListener() {
         public void propertyChange(PropertyChangeEvent pce) {
            if (MVC_Model.PROGRESS.equals(pce.getPropertyName())) {
               view.setProgress((Integer)pce.getNewValue());
            }
         }
      });
   }

   public void doButtonAction() {
      view.start();
      SwingWorker<Void, Void> swingworker = new SwingWorker<Void, Void>() {
         @Override
         protected Void doInBackground() throws Exception {
            model.reset();
            model.startSearch();
            return null;
         }

         @Override
         protected void done() {
            view.done();
         }
      };
      swingworker.execute();
   }

}

class MVC_Model {
   public static final String PROGRESS = "progress";
   private static final int MAX = 100;
   private static final long SLEEP_DELAY = 100;
   private int progress = 0;
   private PropertyChangeSupport pcs = new PropertyChangeSupport(this);

   public void setProgress(int progress) {
      int oldProgress = this.progress;
      this.progress = progress;

      PropertyChangeEvent evt = new PropertyChangeEvent(this, PROGRESS, oldProgress, progress);
      pcs.firePropertyChange(evt);
   }

   public void reset() {
      setProgress(0);
   }

   public void addPropertyChangeListener(PropertyChangeListener listener) {
      pcs.addPropertyChangeListener(listener);
   }

   public void startSearch() {
      for (int i = 0; i < MAX; i++) {
         int newValue = (100 * i) / MAX;
         setProgress(newValue);
         try {
            Thread.sleep(SLEEP_DELAY);
         } catch (InterruptedException e) {}
      }
   }
}
...