【问题标题】:GUI stuck if for loop is done inside EDT如果在 EDT 内完成 for 循环,则 GUI 卡住
【发布时间】:2015-09-25 08:40:18
【问题描述】:

我有这个代码:

Thread T=new Thread(new Runnable(){
    public void run(){
        SwingUtilities.invokeLater(new Runnable(){
            public void run(){
                for (int i=0;i<18;i++){
                    int percent=(int)(((i+1)*100)/18);
                    try {
                        lblNewLabel.setText("Loading... ("+percent+"%)");
                        Thread.sleep(1000);
                    }
                    catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }
});

我的问题是我的标签在启动该线程后不会更改其文本,但会保留旧文本(在此代码标签使用“正在加载...(0%)”文本创建之前)。 有没有办法避免呢?

然后...如果我只在我的 setText 调用中调用 invokeLater,如下所示:

    SwingUtilities.invokeLater(new Runnable(){

        public void run(){

            lblNewLabel.setText("Loading...("+percent+"%)");
        }
    });

它将被调用 18 次。这是一个好方法吗?还是最好不要调用这么多次invokeLater方法?

谢谢

【问题讨论】:

  • 您似乎已将edt 标签用于“事件调度线程”,但实际上并非如此。看看here。我对其进行了编辑以将其从该问题中删除(审核后将可见)。
  • 对不起,不知道。

标签: java multithreading user-interface


【解决方案1】:

以下作品:

    public class UIThreadTest {

    private JFrame mainFrame;
    private JLabel labelStatus;
    private JButton buttonProcess;

    public static void main(String[] args) {
        final UIThreadTest ui = new UIThreadTest();
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                ui.initGUI();
            }
        });
    }

    public void initGUI() {
        mainFrame = new JFrame("View");
        mainFrame.getContentPane().setLayout(new BorderLayout());
        mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mainFrame.setSize(200, 200);
        mainFrame.setVisible(true);
        mainFrame.setLocationRelativeTo(null);

        labelStatus = new JLabel("Status...");
        mainFrame.getContentPane().add(labelStatus, BorderLayout.NORTH);

        buttonProcess = new JButton("Start");
        buttonProcess.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                Runnable startLoop = new StartLoop();
                Thread startLoopThread = new Thread(startLoop);
                startLoopThread.start();
            }

        });
        mainFrame.getContentPane().add(buttonProcess, BorderLayout.SOUTH);
    }

    private void updateStatus(final int val) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                labelStatus.setText("Loading... (" + val + "%)");
            }
        });

    }

    private void runForLoop() {
        for (int i = 0; i < 18; i++) {
            int percent = (int) (((i + 1) * 100) / 18);
            updateStatus(percent);
            try {
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private class StartLoop implements Runnable {
        @Override
        public void run() {
            runForLoop();
        }

    }
}

【讨论】:

  • 非常感谢您的帮助,我也很接近这个解决方案.. 但是.. 调用这么多次invokeLater 是个好主意吗?这会效率低下吗?或者这样做是个好主意?在这段代码中,它被调用了 18 次......
  • 我认为它与调用任何其他方法 18 次一样好。 invokeLater 文档说:“导致 doRun.run() 在 AWT 事件调度线程上异步执行。这将在处理完所有未决 AWT 事件后发生。”为什么你认为它可能效率低下。”另外,我们并没有阻止 EDT。你可能还喜欢link
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-01
  • 1970-01-01
相关资源
最近更新 更多