因此,我正在创建一个JProgressBar来显示CSV操作的进度,在其中读取并检查每一行,并检查强制性(NOT NULL)列中是否没有空值。为此,我创建了一个SwingWorker任务,该任务处理将文件中的行数转换为最大进度值的100%,并以正确的速率累加进度。
那就是SwingWorker:
public static class Task extends SwingWorker<String, Object> {
private int counter;
private double rate;
public Task(int max) {
// Adds the PropertyChangeListener to the ProgressBar
addPropertyChangeListener(
ViewHandler.getExportDialog().getProgressBar());
rate = (float)100/max;
setProgress(0);
counter = 0;
}
/** Increments the progress in 1 times the rate based on maximum */
public void step() {
counter++;
setProgress((int)Math.round(counter*rate));
}
@Override
public String doInBackground() throws IOException {
return null;
}
@Override
public void done() {
Toolkit.getDefaultToolkit().beep();
System.out.println("Progress done.");
}
}
我的
PropertyChangeListener
,由JProgressBar包装器实现:@Override
public void propertyChange(PropertyChangeEvent evt) {
if ("progress".equals(evt.getPropertyName())) {
progressBar.setIndeterminate(false);
progressBar.setValue((Integer) evt.getNewValue());
}
}
然后,在实际使用它的地方,我用需要的处理覆盖了
doInBackground()
方法,在每次迭代中都调用step()
。 Task read = new Task(lines) {
@Override
public String doInBackground() throws IOException {
while(content.hasNextValue()) {
step();
// Processing
}
return output.toString();
}
};
read.execute();
return read.get();
所以发生了什么:处理成功并成功,然后调用
done()
,紧接着propertyChange()
注册了两个“状态”事件和一个“进度”事件,将ProgressBar的进度从0%设置为100%。正在发生的事情我认为正在发生的事情(为澄清起见,使用check Hovercraft's answer)在JavaDocs中进行了描述:
由于PropertyChangeListener是在事件调度线程上异步通知的,因此在调用任何PropertyChangeListener之前,可能会对setProgress方法进行多次调用。出于性能目的,所有这些调用仅与最后一个调用参数合并为一个调用。
所以,毕竟,我的问题是:我做错了什么吗?如果不是,是否有办法让事件调度线程在onProgress()发生时或至少不时通知PropertyChangeListeners?
观察:我正在测试的处理需要3到5秒。
最佳答案
您的问题在这里:
read.execute();
return read.get();
get()
是阻塞调用,因此在执行工作程序后立即从事件线程调用它会阻塞事件线程和GUI。相反,应在工作程序将其状态属性更改为
done()
后从诸如SwingWorker.StateValue.DONE
方法之类的回调方法或从属性更改侦听器中调用它。例如
import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import javax.swing.*;
@SuppressWarnings("serial")
public class TestSwingWorkerGui extends JPanel {
private JProgressBar progressBar = new JProgressBar(0, 100);
private Action myAction = new MyAction("Do It!");
public TestSwingWorkerGui() {
progressBar.setStringPainted(true);
add(progressBar);
add(new JButton(myAction));
}
private class MyAction extends AbstractAction {
public MyAction(String name) {
super(name);
}
@Override
public void actionPerformed(ActionEvent e) {
myAction.setEnabled(false);
Task read = new Task(30) {
@Override
public String doInBackground() throws Exception {
int counter = getCounter();
int max = getMax();
while (counter < max) {
counter = getCounter();
step();
TimeUnit.MILLISECONDS.sleep(200);
}
return "Worker is Done";
}
};
read.addPropertyChangeListener(new MyPropListener());
read.execute();
}
}
private class MyPropListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String name = evt.getPropertyName();
if ("progress".equals(name)) {
progressBar.setIndeterminate(false);
progressBar.setValue((Integer) evt.getNewValue());
} else if ("state".equals(name)) {
if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
myAction.setEnabled(true);
@SuppressWarnings("unchecked")
SwingWorker<String, Void> worker = (SwingWorker<String, Void>) evt.getSource();
try {
String text = worker.get();
System.out.println("worker returns: " + text);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
}
private static void createAndShowGui() {
TestSwingWorkerGui mainPanel = new TestSwingWorkerGui();
JFrame frame = new JFrame("GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class Task extends SwingWorker<String, Void> {
private int counter;
// private double rate;
private int max;
public Task(int max) {
// Adds the PropertyChangeListener to the ProgressBar
// addPropertyChangeListener(gui);
// !!rate = (float)100/max;
this.max = max;
setProgress(0);
counter = 0;
}
/** Increments the progress in 1 times the rate based on maximum */
public void step() {
counter++;
int progress = (100 * counter) / max;
progress = Math.min(100, progress);
setProgress(progress);
// setProgress((int)Math.round(counter*rate));
}
public int getCounter() {
return counter;
}
public int getMax() {
return max;
}
@Override
public String doInBackground() throws Exception {
return null;
}
@Override
public void done() {
Toolkit.getDefaultToolkit().beep();
System.out.println("Progress done.");
}
}
关于java - 更快通知PropertyChangeListener,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52672462/