Как заставить jprogressbar работать параллельно с моим алгоритмом

Возможный дубликат:
Java GUI JProgressBar не рисует
Можно ли использовать индикатор выполнения в класс вне основного?

Я использую перетаскивание Netbeans для выполнения приложения. Я получу ввод от пользователя и использую ввод для запуска моего алгоритма. Алгоритму потребуется разное время для запуска, а затем он покажет результат в новом кадре. В ожидании запуска алгоритма я хочу добавить индикатор выполнения. Я добавляю приведенный ниже код, когда пользователь нажимает кнопку отправки ввода.

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {   

    final JProgressBar bar = new JProgressBar(0,250000);
    bar.setValue(1000);
    bar.setIndeterminate(false);
    JOptionPane jO = new JOptionPane(bar);

    Thread th = new Thread(){

    public void run(){
        for(int i = 1000 ; i < 250000 ; i+=10000){
           bar.setValue(i);
            try {
                Thread.sleep(100);
           } catch (InterruptedException e) {
            }
        }
    }
};
th.start();

final JDialog dialog = jO.createDialog(jO,"Experiment X");
dialog.pack();
dialog.setVisible(true);

//Algorithm goes here

Индикатор выполнения отображается и запускается. Но когда значение индикатора выполнения обновляется до конца, запускается только мой алгоритм. Я вижу через другие примеры, но я не очень понимаю, как это работает.

Может кто-нибудь сказать мне, где я ошибся?


person yt729    schedule 31.12.2012    source источник
comment
Об этом много раз спрашивали и отвечали. Используйте фоновый поток, который может быть предоставлен SwingWorker. Пожалуйста, ознакомьтесь с руководствами по индикатору прогресса и свингворкеру, чтобы узнать больше об этом, и Google поможет вам найти их.   -  person Hovercraft Full Of Eels    schedule 31.12.2012
comment
Вот ссылки на учебные пособия: учебное пособие, параллелизм в Swing (и руководство по SwingWorker)   -  person Hovercraft Full Of Eels    schedule 31.12.2012
comment
..затем показать результат в новом фрейме. См. Использование нескольких JFrames, хорошая/плохая практика? для оценки (плохо) и альтернатив (много).   -  person Andrew Thompson    schedule 31.12.2012


Ответы (1)


Некоторые из наиболее важных концепций Swing:

НЕ выполняйте длительные/блокирующие операции в потоке диспетчеризации событий (ETD). Это приведет к тому, что пользовательский интерфейс будет выглядеть «замороженным» и не отвечающим. Что приятно, вы, кажется, понимаете это.

ЗАПРЕЩАЕТСЯ создавать или изменять ЛЮБОЙ компонент пользовательского интерфейса из любого потока, ДРУГОГО, кроме EDT. Вы не делаете этого.

Лучшей причиной для действий является использование SwingWorker, это позволяет вам выполнять длительные операции, предоставляя слушателям обратную связь о ходе выполнения.

public class TestProgress {

    public static void main(String[] args) {
        new TestProgress();
    }

    public TestProgress() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                ProgressPane progressPane = new ProgressPane();
                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(progressPane);
                frame.setSize(200, 200);
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);

//                progressPane.doWork();
            }
        });
    }

    public class ProgressPane extends JPanel {

        private JProgressBar progressBar;
        private JButton startButton;

        public ProgressPane() {

            setLayout(new GridBagLayout());
            progressBar = new JProgressBar();

            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            add(progressBar, gbc);
            startButton = new JButton("Start");
            gbc.gridy = 1;
            add(startButton, gbc);

            startButton.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    startButton.setEnabled(false);
                    doWork();
                }
            });

        }

        public void doWork() {

            Worker worker = new Worker();
            worker.addPropertyChangeListener(new PropertyChangeListener() {
                @Override
                public void propertyChange(PropertyChangeEvent evt) {
                    if ("progress".equals(evt.getPropertyName())) {
                        progressBar.setValue((Integer) evt.getNewValue());
                    }
                }
            });

            worker.execute();

        }

        public class Worker extends SwingWorker<Object, Object> {

            @Override
            protected void done() {
                startButton.setEnabled(true);
            }

            @Override
            protected Object doInBackground() throws Exception {

                for (int index = 0; index < 1000; index++) {
                    int progress = Math.round(((float) index / 1000f) * 100f);
                    setProgress(progress);

                    Thread.sleep(10);
                }

                return null;
            }
        }
    }
}

Другой вариант — использовать ProgressMonitor или, если вы действительно в отчаянии, используйте SwingUtilities#invokeLater(Runnable), но я настоятельно рекомендую вам вместо этого использовать SwingWorker ;)

person MadProgrammer    schedule 31.12.2012