Уведомить PropertyChangeListener быстрее - PullRequest
0 голосов
/ 05 октября 2018

Итак, я создаю 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%.

Что происходит ЧтоЯ думал, что это происходит ( проверьте ответ Hovercraft для уточнения) описан в JavaDocs:

Поскольку PropertyChangeListeners уведомляются асинхронно на несколько потоков вызова Event DispatchСвязи с методом setProgress могут произойти до того, как будет вызван любой PropertyChangeListeners.В целях производительности все эти вызовы объединены в один вызов только с последним аргументом вызова.

Итак, после всего этого мой вопрос : я что-то не так делаю?Если нет, то есть ли способ заставить поток обработки событий уведомлять PropertyChangeListeners, когда происходит onProgress (), или, по крайней мере, время от времени?

Obs .: обработка, которую ятестирование занимает от 3 до 5 с.

1 Ответ

0 голосов
/ 05 октября 2018

Ваша проблема здесь:

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.");
    }
}
...