Encadeamento de barra de progresso MVC

Estou usando um padrão MVC para meu design, quando um usuário pressiona o botão de pesquisa, eu chamo uma pesquisa no modelo, mas também quero atualizar uma barra de progresso com informações retornadas desse modelo.

Eu tentei usar um swingworker, mas a barra de progresso não é atualizada. Eu suspeito que estou fazendo algo errado com o meu threading.

Meu botão, conforme definido no controlador, é:

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

Isso chama a pesquisa no modelo e tem a seguinte chamada na exibição:

 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 { @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(); } } 

Função dummy definida no modelo para teste:

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

Não ligue

 _progressBar.setValue(_model.getStatus()); 

de dentro do seu SwingWorker, pois isso está chamando o código Swing de um thread de segundo plano e é para isso que o PropertyChangeListener é. Em vez disso, basta definir a propriedade de progresso, isso é tudo.

Além disso, não chame done () de dentro do método doInBackground, pois ele precisa ser chamado pelo EDT pelo SwingWorker. Então deixe o próprio SwingWorker chamar esse método quando estiver de fato pronto.

Além disso, Done () deve ser feito () – a primeira letra não deve estar em maiúscula e você deve usar as annotations @Override nesse código para ter certeza de que está substituindo os methods corretamente.

Além disso, o que isso faz?

  _model.startSearch(_view.getTerm()); 

Chama o código que demora um pouco para ser concluído? Isso deve ser inicializado a partir do próprio SwingWorker doInBackground?

Edit: Outra opção é dar ao Model uma propriedade int ligada, digamos, chamada progress, e então adicionar um PropertyChangeListener a ela diretamente para atualizar o JProgressBar. Por exemplo,

 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 swingworker = new SwingWorker() { @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) {} } } }