【问题标题】:Display indeterminate JProgressBar while batch file runs批处理文件运行时显示不确定的 JProgressBar
【发布时间】:2014-01-03 05:48:05
【问题描述】:

我一直在浏览 SO 和 google 一段时间来寻找这个问题的答案,但我似乎找不到真正有效的答案。我将从头开始:

我使用在后台运行批处理文件的方法创建了一个 Java 类(不会出现命令窗口)。该程序运行良好,但最终用户会感到有些困惑,因为批处理文件需要一段时间才能完成——用户将不知道程序是否仍在运行。批处理脚本执行完成后,会出现一个消息对话框,说明它已完成,但在运行方法和出现对话框之间的一段时间内,程序看起来好像什么也没做。

所以这是我的问题:我非常想显示一个带有显示批处理文件输出的文本区域的新框架。但是,我知道如果不创建临时文件、写入它们、读取它们等等,这是非常困难的。如果可能的话,我宁愿避免这种情况。因此,我决定在进程运行时显示不确定的 JProgressBar 并在进程完成时关闭它可能会更好。不幸的是,我认为 Swing 无法处理这个问题,因为它需要同时运行多个进程。我听说过 SwingWorker,但不确定在这种情况下如何使用它。我有以下 SSCCE,它可以工作,但没有实现进度条。

public myClass(){
    public static void main(String[] args){
        String[] commands = {"cmd.exe", "/C", "C:\\users\\....\\myBat.bat"};
        Process p = Runtime.getRuntime().exec(commands);
        p.waitFor()
        JOptionPane.showMessageDialog(null, "Process finished!");
    }
}

当 p.waitFor() 等待进程时,屏幕上没有任何内容。我只想向用户显示一个进程仍在运行。想法?谢谢!

【问题讨论】:

    标签: java swing progress-bar joptionpane jprogressbar


    【解决方案1】:

    您可以在SwingWorker 的背景下运行ProcessBuilder,如下所示,以获得 输出和进度条。

    import java.awt.BorderLayout;
    import java.awt.EventQueue;
    import java.awt.event.*;
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import javax.swing.*;
    
    /**
     * @se http://stackoverflow.com/a/20603012/230513
     * @see http://stackoverflow.com/a/17763395/230513
     */
    public class SwingWorkerExample {
    
        private final JLabel statusLabel = new JLabel("Status: ", JLabel.CENTER);
        private final JTextArea textArea = new JTextArea(20, 20);
        private JButton startButton = new JButton("Start");
        private JButton stopButton = new JButton("Stop");
        private JProgressBar bar = new JProgressBar();
        private BackgroundTask backgroundTask;
        private final ActionListener buttonActions = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                JButton source = (JButton) ae.getSource();
                if (source == startButton) {
                    textArea.setText(null);
                    startButton.setEnabled(false);
                    stopButton.setEnabled(true);
                    backgroundTask = new BackgroundTask();
                    backgroundTask.execute();
                    bar.setIndeterminate(true);
                } else if (source == stopButton) {
                    backgroundTask.cancel(true);
                    backgroundTask.done();
                }
            }
        };
    
        private void displayGUI() {
            JFrame frame = new JFrame("Swing Worker Example");
            frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    
            JPanel panel = new JPanel();
            panel.setBorder(
                BorderFactory.createEmptyBorder(5, 5, 5, 5));
            panel.setLayout(new BorderLayout(5, 5));
    
            JScrollPane sp = new JScrollPane();
            sp.setBorder(BorderFactory.createTitledBorder("Output: "));
            sp.setViewportView(textArea);
    
            startButton.addActionListener(buttonActions);
            stopButton.setEnabled(false);
            stopButton.addActionListener(buttonActions);
            JPanel buttonPanel = new JPanel();
            buttonPanel.add(startButton);
            buttonPanel.add(stopButton);
            buttonPanel.add(bar);
    
            panel.add(statusLabel, BorderLayout.PAGE_START);
            panel.add(sp, BorderLayout.CENTER);
            panel.add(buttonPanel, BorderLayout.PAGE_END);
    
            frame.setContentPane(panel);
            frame.pack();
            frame.setLocationByPlatform(true);
            frame.setVisible(true);
        }
    
        private class BackgroundTask extends SwingWorker<Integer, String> {
    
            private int status;
    
            public BackgroundTask() {
                statusLabel.setText((this.getState()).toString());
            }
    
            @Override
            protected Integer doInBackground() {
                try {
                    ProcessBuilder pb = new ProcessBuilder("ls", "-lR", "/");
                    pb.redirectErrorStream(true);
                    Process p = pb.start();
                    String s;
                    BufferedReader stdout = new BufferedReader(
                        new InputStreamReader(p.getInputStream()));
                    while ((s = stdout.readLine()) != null && !isCancelled()) {
                        publish(s);
                    }
                    if (!isCancelled()) {
                        status = p.waitFor();
                    }
                    p.getInputStream().close();
                    p.getOutputStream().close();
                    p.getErrorStream().close();
                    p.destroy();
                } catch (IOException | InterruptedException ex) {
                    ex.printStackTrace(System.err);
                }
                return status;
            }
    
            @Override
            protected void process(java.util.List<String> messages) {
                statusLabel.setText((this.getState()).toString());
                for (String message : messages) {
                    textArea.append(message + "\n");
                }
            }
    
            @Override
            protected void done() {
                statusLabel.setText((this.getState()).toString() + " " + status);
                stopButton.setEnabled(false);
                startButton.setEnabled(true);
                bar.setIndeterminate(false);
            }
    
        }
    
        public static void main(String[] args) {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    new SwingWorkerExample().displayGUI();
                }
            });
        }
    }
    

    【讨论】:

    • 这太棒了!我将不得不使用它来满足我的需要。它必须是一个单独的类,并将我的进程命令传递给它。我目前有一个类变量和一个 mutator 方法来设置值。出于某种原因,虽然它似乎没有运行批处理文件。我会再做一点调试,然后再回复你。
    • 按预期工作,非常感谢!不幸的是,它运行得很慢。我不认为有办法可以加快速度?
    • 我猜是批处理文件;我不得不放慢速度进行测试; profile 是肯定的。
    • 在添加此类之前,批处理文件将在大约 30 秒内开始和完成。现在已经进行了一个多小时(可能是两个小时?),但仍未完成。
    • 对;这个想法是在doInBackground(worker 的后台线程)中运行慢速进程,并在 EDT 上运行process 结果。您的批次是否完成,尽管速度很慢,还是无限期地保持阻塞?
    猜你喜欢
    • 2019-03-17
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    • 2013-10-10
    • 2011-07-20
    相关资源
    最近更新 更多