更快地通知 PropertyChangeListener

所以我正在创建一个 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.");

    }

}

My 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%。

由于在事件调度线程上异步通知 PropertyChangeListener,因此在调用任何 PropertyChangeListener 之前可能会发生对 setProgress 方法的多次调用。出于性能目的,所有这些调用都合并为一个仅具有最后一个调用参数的调用。

所以,毕竟,我的问题是:我做错了什么吗?如果没有,有没有办法让事件调度线程在 onProgress() 发生时或至少不时通知 PropertyChangeListeners?

观察:我正在测试的处理需要 3~5 秒。


梦里花落0921
浏览 123回答 1
1回答

守着星空守着你

你的问题在这里:read.execute();return read.get();get()是一个阻塞调用,因此在执行您的工作线程后立即从事件线程调用它会阻塞事件线程和您的 GUI。相反,它应该done()在 worker 将其 state 属性更改为 之后从回调方法(例如方法)或属性更改侦听器中调用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 {&nbsp; &nbsp; private JProgressBar progressBar = new JProgressBar(0, 100);&nbsp; &nbsp; private Action myAction = new MyAction("Do It!");&nbsp; &nbsp; public TestSwingWorkerGui() {&nbsp; &nbsp; &nbsp; &nbsp; progressBar.setStringPainted(true);&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; add(progressBar);&nbsp; &nbsp; &nbsp; &nbsp; add(new JButton(myAction));&nbsp; &nbsp; }&nbsp; &nbsp; private class MyAction extends AbstractAction {&nbsp; &nbsp; &nbsp; &nbsp; public MyAction(String name) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; super(name);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; @Override&nbsp; &nbsp; &nbsp; &nbsp; public void actionPerformed(ActionEvent e) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; myAction.setEnabled(false);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Task read = new Task(30) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; @Override&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; public String doInBackground() throws Exception {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int counter = getCounter();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int max = getMax();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while (counter < max) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; counter = getCounter();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; step();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TimeUnit.MILLISECONDS.sleep(200);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return "Worker is Done";&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; read.addPropertyChangeListener(new MyPropListener());&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; read.execute();&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; private class MyPropListener implements PropertyChangeListener {&nbsp; &nbsp; &nbsp; &nbsp; @Override&nbsp; &nbsp; &nbsp; &nbsp; public void propertyChange(PropertyChangeEvent evt) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; String name = evt.getPropertyName();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if ("progress".equals(name)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; progressBar.setIndeterminate(false);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; progressBar.setValue((Integer) evt.getNewValue());&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else if ("state".equals(name)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (evt.getNewValue() == SwingWorker.StateValue.DONE) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; myAction.setEnabled(true);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; @SuppressWarnings("unchecked")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; SwingWorker<String, Void> worker = (SwingWorker<String, Void>) evt.getSource();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; String text = worker.get();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println("worker returns: " + text);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } catch (InterruptedException e) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } catch (ExecutionException e) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; private static void createAndShowGui() {&nbsp; &nbsp; &nbsp; &nbsp; TestSwingWorkerGui mainPanel = new TestSwingWorkerGui();&nbsp; &nbsp; &nbsp; &nbsp; JFrame frame = new JFrame("GUI");&nbsp; &nbsp; &nbsp; &nbsp; frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);&nbsp; &nbsp; &nbsp; &nbsp; frame.getContentPane().add(mainPanel);&nbsp; &nbsp; &nbsp; &nbsp; frame.pack();&nbsp; &nbsp; &nbsp; &nbsp; frame.setLocationRelativeTo(null);&nbsp; &nbsp; &nbsp; &nbsp; frame.setVisible(true);&nbsp; &nbsp; }&nbsp; &nbsp; public static void main(String[] args) {&nbsp; &nbsp; &nbsp; &nbsp; SwingUtilities.invokeLater(() -> createAndShowGui());&nbsp; &nbsp; }}class Task extends SwingWorker<String, Void> {&nbsp; &nbsp; private int counter;&nbsp; &nbsp; // private double rate;&nbsp; &nbsp; private int max;&nbsp; &nbsp; public Task(int max) {&nbsp; &nbsp; &nbsp; &nbsp; // Adds the PropertyChangeListener to the ProgressBar&nbsp; &nbsp; &nbsp; &nbsp; // addPropertyChangeListener(gui);&nbsp; &nbsp; &nbsp; &nbsp; // !!rate = (float)100/max;&nbsp; &nbsp; &nbsp; &nbsp; this.max = max;&nbsp; &nbsp; &nbsp; &nbsp; setProgress(0);&nbsp; &nbsp; &nbsp; &nbsp; counter = 0;&nbsp; &nbsp; }&nbsp; &nbsp; /** Increments the progress in 1 times the rate based on maximum */&nbsp; &nbsp; public void step() {&nbsp; &nbsp; &nbsp; &nbsp; counter++;&nbsp; &nbsp; &nbsp; &nbsp; int progress = (100 * counter) / max;&nbsp; &nbsp; &nbsp; &nbsp; progress = Math.min(100, progress);&nbsp; &nbsp; &nbsp; &nbsp; setProgress(progress);&nbsp; &nbsp; &nbsp; &nbsp; // setProgress((int)Math.round(counter*rate));&nbsp; &nbsp; }&nbsp; &nbsp; public int getCounter() {&nbsp; &nbsp; &nbsp; &nbsp; return counter;&nbsp; &nbsp; }&nbsp; &nbsp; public int getMax() {&nbsp; &nbsp; &nbsp; &nbsp; return max;&nbsp; &nbsp; }&nbsp; &nbsp; @Override&nbsp; &nbsp; public String doInBackground() throws Exception {&nbsp; &nbsp; &nbsp; &nbsp; return null;&nbsp; &nbsp; }&nbsp; &nbsp; @Override&nbsp; &nbsp; public void done() {&nbsp; &nbsp; &nbsp; Toolkit.getDefaultToolkit().beep();&nbsp; &nbsp; &nbsp; System.out.println("Progress done.");&nbsp; &nbsp; }}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java