Кадр отображается с InvokeLater после всех других процессов - PullRequest
1 голос
/ 07 ноября 2011

Боюсь, что это немного сложно, так как я не смог воссоздать проблему в примере, который я написал для этого вопроса (пример ниже работает отлично). Надеюсь, кто-то может иметь представление о возможных проблемах с фактическим применением. Я написал приложение с выполняет несколько длинных текстовых операций. Каждая операция выполняется в своем собственном потоке. Существует фрейм, который обновляется потоками, чтобы пользователь мог видеть, как все идет.

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

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class Main {

    private MyFrame frame;
    private ExecutorService executorService;

    public static void main(String[] args) throws InterruptedException {
        Main main = new Main();
        main.startProcess();
    }

    public void startProcess() throws InterruptedException {
        // Initialize the frame
        frame = new MyFrame();
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                frame.setVisible(true);
            }
        });

        // Initialize executorService for 3 threads and also 6 runnables
        executorService = Executors.newFixedThreadPool(3);
        MyRunnable runnable;
        for(int i = 0; i < 6; i++) {
            runnable = new MyRunnable(this, i);
            executorService.execute(runnable);
        }

        // Start runnables
        executorService.shutdown();

        // Wait until all runnables are executed
        while (!executorService.isTerminated()) {
            Thread.sleep(10000);
        }

        // When all runnables are done close the frame
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                frame.setVisible(false);
            }
        });
    }

    // Update the frame display
    public synchronized void updateDisplay(final String update) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                frame.updateDisplay(update);
            }
        });
    }

    private class MyFrame extends JFrame {
        private JPanel contentPane;
        private JLabel lblDisplay;

        public MyFrame() {
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            contentPane = new JPanel();
            contentPane.setLayout(new BorderLayout(0, 0));
            setContentPane(contentPane);

            lblDisplay = new JLabel("Display");
            contentPane.add(lblDisplay, BorderLayout.CENTER);

            pack();
        }

        public void updateDisplay(String update) {
            lblDisplay.setText(update);
            pack();
        }
    }

    private class MyRunnable implements Runnable {
        private int id;
        private Main main;

        public MyRunnable (Main main, int id) {
            this.main = main;
            this.id = id;
        }

        @Override
        public void run() {
            for(int i = 0; i < 3; i++) {
                main.updateDisplay("Runnable " + id + " stepped " + i + " times.");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

1 Ответ

3 голосов
/ 07 ноября 2011

это задание для SwingWorker и только одного JFrame, пример здесь

вывод из Runnable#Thread в GUI должен быть заключен в invokeLater() пример здесь

или вызовите SwingWorker от исполнителя

...