【问题标题】:Run SwingWorker several times多次运行 SwingWorker
【发布时间】:2016-05-26 14:54:42
【问题描述】:

我想生成一个随机数 5 次并重复 6 次。每次生成随机数时,我都会使用该数字和进度条更新 GUI。

为了做到这一点,我想到了一个 SwingWorker,它在 doInBackground() 方法上生成随机数,并使用 publish() 方法在 GUI 上显示该数字。我这样做完全没有问题,当我尝试这样做 6 次时出现问题,因为在 done() 方法中,我在 TextField 上添加了一个空格,用于显示所有数字

如何运行 6 次 SwingWorker,并在 SwingWorker 的 done() 方法完成后启动?

谢谢!

编辑:代码 sn -p

public class SwingWorkerEjemplo extends SwingWorker<Void, Integer> {
private JProgressBar pBar;
private JTextField txtSalida;
private JTextArea txtArea;

public SwingWorkerEjemplo(JProgressBar pBar,JTextField txt, JTextArea txtArea) {
    this.pBar = pBar;
    addPropertyChangeListener(new PropertyChangeListener() {
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            if ("progress".equals(evt.getPropertyName())){
                pBar.setValue((Integer)evt.getNewValue());
            }
        }
    });

    this.pBar.setVisible(true);
    this.pBar.setStringPainted(true);
    this.pBar.setValue(0);
    setProgress(0);
    this.txtSalida = txt;
    this.txtArea = txtArea;
}

@Override
protected Void doInBackground() throws Exception {
    int num;
    for (int i=0;i<5;i++){
        num = ThreadLocalRandom.current().nextInt(1, 7);
        publish(num);
        setProgress(i+1);
        Thread.sleep(100);
    }
    return null;
}

@Override
protected void done() {
    try {
        txtSalida.setText(txtSalida.getText()+" ");
        Thread.sleep(0);
        txtArea.append("");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

@Override
protected void process(List<Integer> chunks) {
    Integer valor = chunks.get(chunks.size()-1);
    txtSalida.setText(txtSalida.getText()+String.valueOf(valor));
}

}

在 MainWindow.java 中

SwingWorkerEjemplo swe = new SwingWorkerEjemplo(pBar, txtNumeros, txtSalida);
swe.execute();
System.out.println("Worker 1");
swe = new SwingWorkerEjemplo(pBar, txtNumeros, txtSalida);
swe.execute();
System.out.println("Worker 2");
swe = new SwingWorkerEjemplo(pBar, txtNumeros, txtSalida);
swe.execute();
System.out.println("Worker 3");
swe = new SwingWorkerEjemplo(pBar, txtNumeros, txtSalida);
swe.execute();
System.out.println("Worker 4");
swe = new SwingWorkerEjemplo(pBar, txtNumeros, txtSalida);
swe.execute();
System.out.println("Worker 5");
swe = new SwingWorkerEjemplo(pBar, txtNumeros, txtSalida);
swe.execute();
System.out.println("Worker 6");

结果首先是 工人 1 工人 2 工人 3 工人 4 工人 5 工人 6 然后像 xxxxxyyyyyzzzzzaaaaabbbbbcccccddddd 之类的东西

【问题讨论】:

  • 请添加代码 sn-p 和你得到的结果

标签: java multithreading swing user-interface swingworker


【解决方案1】:

如何运行 6 次 SwingWorker,并在 SwingWorker 的 done() 方法完成后启动?

你不能。根据SwingWorker API documentation

SwingWorker 仅设计为执行一次。多次执行 SwingWorker 不会导致调用 doInBackground 方法两次。

因此,如果您需要延迟重复某个操作,请在您的 worker 中使用 while 循环执行此操作,然后通过 SwingWorker 的发布/进程对将结果输出到您的 GUI。如果你走这条路,你会创建一个SwingWorker&lt;Void, Integer&gt;(如果它需要产生 int 输出)。另一方面,如果您想运行 6 次 worker,每次响应一个事件,那么只需在每次需要时创建一个新的 worker。

我想知道您是否只需要更简单的 Swing Timer。


编辑

我还没有看到 Swing Timer 是做什么的,所以我无法回答这个问题。

如果您需要间歇性地延迟完成某些事情,那么Swing Timer(请参阅链接)是您的最佳选择。当您创建一个时,您传入 2 个参数、一个表示延迟时间的 int 和一个 ActionListener——其 actionPerformed 方法将被延迟大致重复调用。因此,如果您需要每秒生成一个随机 int,则需要传入 1000(1000 毫秒 = 1 秒)和一个 ActionListener,然后在侦听器的 actionPerformed 方法中,生成随机 int 并将其传递给需要它的任何人。请注意,actionPerformed 方法中的所有代码都是在 Swing 事件线程上调用的。

另一方面,如果您需要运行一些需要很长时间才能执行的代码,例如数据库查找、从套接字读取、从文件读取或写入,那么您将使用 SwingWorker ,因为通过这样做,您可以在后台线程和事件线程中运行长代码段,安全地将信息提取回 GUI。

还有一个简单的问题,你所说的工作人员是指 GUI?

不,工人 = SwingWorker。


因此,对于您发布的代码,如果这就是您想做的全部 - 延迟更新 JProgressBar,然后使用 Swing Timer。另一方面,如果您想要执行一个长时间运行的进程并希望在该进程运行时更新 JProgressBar,则使用 SwingWorker。请注意,如果您有后者的需要,则不需要使用发布/处理方法对。 SwingWorker 有一个progress 属性,它是一个“绑定”属性,这意味着如果您通过调用setProgress(...) 更改它,SwingWorker 将通知可能附加到它的任何PropertyChangeListeners。我经常使用这个很多


例如:

import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Random;
import java.util.concurrent.ExecutionException;

import javax.swing.*;

public class ProgressExampleGui {
   private JPanel mainPanel = new JPanel();
   private JProgressBar progressBar = new JProgressBar();
   private JButton pressMeBtn  = new JButton(new MyAction("Press Me", KeyEvent.VK_P, this));

   public ProgressExampleGui() {
      progressBar.setStringPainted(true);
      progressBar.setString("");

      mainPanel.add(pressMeBtn);
      mainPanel.add(progressBar);
   }

   public void setProgress(int progress) {
      progressBar.setValue(progress);
      progressBar.setString(progress + "%");
   }

   public JComponent getMainComponent() {
      return mainPanel;
   }

   public void setEnabled(boolean enabled) {
      pressMeBtn.setEnabled(enabled);
   }

   private static void createAndShowGui() {
      ProgressExampleGui progExampleGui = new ProgressExampleGui();

      JFrame frame = new JFrame("Progress Example");
      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame.getContentPane().add(progExampleGui.getMainComponent());
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

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

@SuppressWarnings("serial")
class MyAction extends AbstractAction {
   private ProgressExampleGui gui;

   public MyAction(String name, int mnemonic, ProgressExampleGui gui) {
      super(name);
      putValue(MNEMONIC_KEY, mnemonic);
      this.gui = gui;
   }

   @Override
   public void actionPerformed(ActionEvent e) {
      AbstractButton source = (AbstractButton) e.getSource();
      gui.setProgress(0);
      source.setEnabled(false);
      MyWorker myWorker = new MyWorker();
      myWorker.addPropertyChangeListener(new WorkerPropChngListener(gui));
      myWorker.execute();
   }
}

class WorkerPropChngListener implements PropertyChangeListener {

   private ProgressExampleGui gui;

   public WorkerPropChngListener(ProgressExampleGui gui) {
      this.gui = gui;
   }

   @Override
   public void propertyChange(PropertyChangeEvent pcEvt) {
      MyWorker myWorker = (MyWorker) pcEvt.getSource();
      if ("progress".equals(pcEvt.getPropertyName())) {
         int progress = ((Integer)pcEvt.getNewValue()).intValue();
         gui.setProgress(progress);
      }

      if (SwingWorker.StateValue.DONE.equals(pcEvt.getNewValue())) {
         try {
            myWorker.get();
         } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
         }
         gui.setEnabled(true);
      }
   }

}

class MyWorker extends SwingWorker<Void, Void> {
   private static final int MAX_INCR = 8;
   private static final long SLEEP_TIME = 200;
   private static final int MAX_VALUE = 100;
   private int value = 0;
   private Random random = new Random();

   @Override
   protected Void doInBackground() throws Exception {
      while (value < MAX_VALUE) {
         value += random.nextInt(MAX_INCR);
         value = Math.min(value, MAX_VALUE);
         Thread.sleep(SLEEP_TIME);
         setProgress(value);
      }
      return null;
   }
}

【讨论】:

  • 我还没有看到 Swing Timer 的作用,所以我无法回答这个问题。还有一个简单的问题,worker 是指 GUI?
  • 感谢您的回答。我想我会使用 Swing Timer 看看我能不能弄明白;)
猜你喜欢
  • 2020-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-07
  • 2020-07-24
  • 2013-01-15
  • 2020-03-29
  • 1970-01-01
相关资源
最近更新 更多