所有其他进程完成后,使用 InvokeLater 显示的框架

发布于 2024-12-13 20:49:20 字数 3178 浏览 2 评论 0原文

恐怕这个有点棘手,因为我无法在我为这个问题编写的示例中重现该问题(下面的示例完美运行)。希望有人能够了解实际应用程序可能出现的问题。 我编写了一个执行多个长文本操作的应用程序。每个操作都在其自己的线程中完成。有一个由线程更新的框架,让用户可以看到一切的进展情况。

问题在于,只有在所有线程完成其作业后,框架才会显示发送给它的所有更新。
我已将整个应用程序简化为下面的代码,但正如我所说,问题是它在这里工作。任何想法都非常受欢迎。

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();
                }
            }
        }
    }
}

I'm afraid that this one is a little tricky since I couldn't recreate the issue in the example I wrote for this question (the example below works perfectly). Hopefully someone may have a clue as to possible problems with the actual application.
I wrote a app with performs several long text operations. Each operation is done in its own thread. There is a Frame that is updated by the threads to let a user see how everything is progressing.

The problem is that the frame is displayed with all the updates that were sent to it only after all the threads are done with their jobs.
I've simplified the entire app into the code below but as I said the problem is that it works here. Any ideas are very welcome.

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();
                }
            }
        }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

撧情箌佬 2024-12-20 20:49:20

SwingWorker 的这项工作,只有一个 JFrame,例如 此处

来自 Runnable#Thread GUI 必须包装到 invokeLater() 示例 此处

或调用 来自执行器的 SwingWorker

that job for SwingWorker and only one JFrame, example here

output from Runnable#Thread to the GUI must be wrapped into invokeLater() example here

or invoke SwingWorker from Executor

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文