当前位置: 首页 > 知识库问答 >
问题:

我如何使这个方法更新我的循环中的GUI?

段干华晖
2023-03-14
 public void load() throws IOException {
    ProcessBuilder builder = new ProcessBuilder(
            "cmd.exe", "/c", "cd \"C:\\usmt\" && loadstate.bat");
    builder.redirectErrorStream(true);
    Process p = builder.start();
    BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
    String line;

    while (true) {

        line = r.readLine();
        if (line == null) { break; }

        cOut.setText(line);
        System.out.println(line);
    }
}

共有1个答案

凌恩
2023-03-14

您的问题的基本原因是您阻塞了事件分派线程,这阻止了UI的更新,直到命令执行完毕。

Swing是一个单线程框架,这意味着您不应该在EDT上下文中执行阻塞或长时间运行的代码。Swing也不是线程安全的,这意味着您永远不应该在EDT上下文之外修改UI的状态。

有关更多详细信息,请参见Swing中的并发性

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Runner {

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

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

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private JTextArea ta;

        public TestPane() {
            setLayout(new BorderLayout());
            ta = new JTextArea(25, 80);
            add(new JScrollPane(ta));

            JButton execute = new JButton("Make it so");
            execute.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    execute.setEnabled(false);
                    CommandWorker worker = new CommandWorker(ta, "cmd.exe", "/c", "cd \"C:\\usmt\" && loadstate.bat");
                    worker.addPropertyChangeListener(new PropertyChangeListener() {
                        @Override
                        public void propertyChange(PropertyChangeEvent evt) {
                            switch (evt.getPropertyName()) {
                                case "state":
                                    SwingWorker work = (SwingWorker) evt.getSource();
                                    switch (worker.getState()) {
                                        case DONE: {
                                            try {
                                                worker.get();
                                            } catch (InterruptedException | ExecutionException ex) {
                                                ex.printStackTrace();;
                                                JOptionPane.showMessageDialog(TestPane.this, "Execution of command failed: " + ex.getMessage());
                                            } finally {
                                                execute.setEnabled(true);
                                            }
                                        }
                                        break;
                                    }
                                    break;
                            }
                        }
                    });
                    worker.execute();
                }
            });

            add(execute, BorderLayout.SOUTH);
        }

    }

    public static class CommandWorker extends SwingWorker<List<String>, String> {

        private JTextArea ta;
        private List<String> commands;

        public CommandWorker(JTextArea ta, List<String> commands) {
            this.ta = ta;
            this.commands = commands;
        }

        public CommandWorker(JTextArea ta, String... commands) {
            this(ta, Arrays.asList(commands));
        }

        @Override
        protected List<String> doInBackground() throws Exception {
            List<String> output = new ArrayList<>(25);
            ProcessBuilder builder = new ProcessBuilder(commands);
            builder.redirectErrorStream(true);

            Process p = builder.start();
            try (BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()))) {
                String line = null;
                while ((line = r.readLine()) != null) {
                    output.add(line);
                    publish(line);
                }
            }
            return output;
        }

        @Override
        protected void process(List<String> chunks) {
            for (String text : chunks) {
                ta.append(text);
                ta.append("\n");
            }
        }

    }

}
 类似资料:
  • 如下所示,我要反转数组。但我的代码不管用。这是我的for循环。请看一下。这个for循环正确吗。代码如下。

  • 问题内容: 我正在制作一个运行一些cmd命令(USMT和文件传输)的程序 它工作正常,但是只有在完成操作后,我才从文本框中的cmd获取最后一行。我希望它打印cmd实时输出的内容。 问题答案: 问题的根本原因是您阻止了事件调度线程,这将阻止在执行命令后更新UI。 Swing是一个单线程框架,这意味着您不应在EDT上下文中执行阻塞或长时间运行的代码。Swing也不是线程安全的,这意味着永远不要在EDT

  • 顺便说一下,我搜索了一下这种情况,我认为我没有使用数组索引或者错误地使用了错误的指针。另外,我在这里看到了同样的问题,但我想知道为什么代码不能工作,然后自己解决这个问题。非常感谢大家的帮助。

  • 我想使用以下循环创建一个新列。表中只有“open”和“start”列。我想创建一个新列“startopen”,如果“start”等于1,那么“startopen”等于“open”。否则,“startopen”等于此新创建列上方行中的任何“startopen”。目前,我能够通过以下方式实现这一点: 这有效,但对于大型数据集来说非常慢。是否有任何内置函数可以更快地完成此操作?

  • 下面是我想在用户健康和龙健康时循环的功能

  • 我正在尝试使我的循环回到列表的开始。 这是我当前用来检测列表末尾的东西(在这里找到): 当滚动到最后时,我希望视图在显示列表顶部的数据时是可见的,或者当滚动到列表顶部时,我将显示列表底部的数据。 例如: 视图5视图1视图2视图3视图4