Swing invokeLater никогда не обнаруживается, invokeAndWait выдает ошибку.Что я могу сделать? - PullRequest
2 голосов
/ 14 июня 2010

У меня есть этот код:

try {
    SwingUtilities.invokeAndWait(new Runnable() {
        public void run() {
        try {
            dialog.handleDownload();
        } catch (IOException io) {
            io.printStackTrace();
            }
        }
    });
} catch(Exception io) { io.printStackTrace(); }

в handleDownload Я читаю поток ввода, вычисляю значение индикатора выполнения и устанавливаю его на это. Поэтому, когда я нажимаю кнопку, открывается новый JFrame и выполняет все то, что я написал выше.

Если у меня есть dialog.handleDownload само по себе (без метода SwingUtilities), оно останавливается до завершения операции. Если я добавлю его в invokeLater, он закроется очень быстро (я ничего не вижу, и операция не закончена). Если я добавлю его в invokeAndWait, я получу invokeAndWait, который нельзя вызвать из-за ошибки потока диспетчера событий. Что мне делать?

Ответы [ 5 ]

4 голосов
/ 14 июня 2010

Похоже, вы могли бы использовать SwingWorker . Это позволяет вам переносить дорогостоящую операцию в фоновый поток (сохраняя отзывчивость вашего графического интерфейса), а когда операция завершится, выполните некоторые действия с графическим интерфейсом.

Редактировать: Пример

Вот немного более сложный пример, который показывает, как использовать основы SwingWorker, а также как публиковать / обрабатывать промежуточные результаты.

public static void main(String[] args) {
    final int SIZE = 1024*1024; //1 MiB

    //simulates downloading a 1 MiB file
    final InputStream in = new InputStream() {
        int read = 0;
        public int read() throws IOException {
            if ( read == SIZE ) {
                return -1;
            } else {
                if ( read % 200 == 0 ) {
                    try { Thread.sleep(1); } catch ( InterruptedException e ) {}
                }
                read++;
                return 5;
            }
        }
    };

    final JProgressBar progress = new JProgressBar(0, SIZE);

    final JButton button = new JButton("Start");
    button.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            button.setText("Working...");
            SwingWorker<byte[], Integer> worker = new SwingWorker<byte[], Integer>() {
                @Override
                protected byte[] doInBackground() throws Exception {
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    byte[] buff = new byte[1024];
                    for ( int read = -1; (read = in.read(buff)) != -1; ) {
                        baos.write(buff, 0, read);
                        publish(read);
                    }
                    return baos.toByteArray();
                }

                @Override
                protected void process(List<Integer> chunks) {
                    int total = 0;
                    for ( Integer amtRead : chunks ) {
                        total += amtRead;
                    }
                    progress.setValue(progress.getValue() + total);
                }

                @Override
                protected void done() {
                    try {
                        byte[] data = get();
                        button.setText("Read " + data.length + " bytes");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            };
            worker.execute();
        }
    });

    JFrame frame = new JFrame();
    frame.setLayout(new BorderLayout());
    frame.add(button, BorderLayout.NORTH);
    frame.add(progress, BorderLayout.SOUTH);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.pack(); frame.setVisible(true);
}

Редактировать: Изменен пример управления индикатором выполнения, как если бы происходила загрузка.

4 голосов
/ 14 июня 2010

Если вы делаете это в ответ на нажатие кнопки, вы уже находитесь в потоке событий, поэтому invokeAndWait действительно движется в неправильном направлении.

Вам необходимо запустить новый поток, чтобы выполнить поток handleDownload, который НЕ является потоком отправки события - НО

При работе в новом потоке убедитесь, что для любых обновлений GUI используется invokeAndWait или предпочтительно invokeLater, чтобы вернуться к EDT.

Запомните простые правила:

  • Любая нить, переданная вам Swing, является EDT, так что делайте с ней все необходимое для графического интерфейса
  • Делать ВСЕ обновления элементов GUI на EDT (ТОЛЬКО).
  • Делайте все, что занимает много времени в не-EDT-потоке (Начать новый поток).
  • Используйте invokeLater, чтобы вернуться к EDT из потока, не являющегося EDT
1 голос
/ 14 июня 2010

То, что вам нужно, это SwingWorker.Это позволит вам загружать файл в отдельном потоке, который не беспокоит EDT.

Ваш код будет выглядеть примерно так:

class Downloader extends SwingWorker<String, Void> {
   @Override
   public String doInBackground() {
       dialog.handleDownload();
       return "done";
   }

   @Override
   protected void done() {
       try { 
           someLabel.setText(get());
       } catch (Exception ignore) {
       }
   }
}
1 голос
/ 14 июня 2010

Что делает "handleDownload"? В потоке диспетчера событий не нужно делать много времени. Если что-то потребляет много циклов ЦП в потоке диспетчера событий, то дисплей будет зависать до тех пор, пока это не будет сделано. Вам гораздо лучше в таком случае вызывать нормальный поток (без использования SwingUtilities) для выполнения обработки вне потока диспетчера событий, а в этом потоке использовать SwingUtilities.invokeLater для отправки уведомлений об изменениях (например, обновление индикатор выполнения) через равные промежутки времени.

1 голос
/ 14 июня 2010

Вы не должны обращаться к вашему inputStream в потоке событий. Создайте новый поток, который фактически выполняет большую часть работы handleDownload (), а затем заставьте последнюю операцию, выполненную этим потоком, вызвать SwingUtilities.invokeLater () с кодом, который фактически показывает и заполняет диалоговое окно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...