繁体   English   中英

只有在Runtime.getRuntime()。exec()完成执行之后,Swing消息才会显示

[英]Swing message doesn't get displayed until after Runtime.getRuntime().exec() finishes execution

我是Swing的新手。 我试图创建一个摆动包装器,以允许用户浏览和选择文件夹,并且该文件夹路径用作控制台.exe程序的命令行参数。 他们选择文件夹并单击“启动程序”按钮后,我希望旋转窗口显示一条消息,告诉他们该程序正在处理(并显示时钟的gif动画),运行外部程序,然后显示另一条消息该程序完成执行时。 我遇到的问题是,直到外部程序完成执行后,才会显示“正在处理”消息。 在下面的代码中,单击“启动程序”按钮时,将执行onLaunchProgram方法。 我尝试过revalidate()和repaint(),但没有任何变化。 我有一个“已完成”消息的waitFor(),但是即使取出该消息,也不会显示“正在处理”消息和gif,直到外部程序完成执行。


    ...

    JTextField txtFolder = new JTextField();
    JLabel lblMessage = new JLabel();
    JLabel lblPic = new JLabel();
    JButton btnLaunchApplication = new JButton("Launch Program");  

    ...  

    btnLaunchApplication.addActionListener(new ActionListener() {  
        public void actionPerformed(ActionEvent evt) {  
            onLaunchProgram(evt);  
        }  
     });  

    ...

    if (returnVal == JFileChooser.APPROVE_OPTION){
        file = fc.getSelectedFile();
        txtFolder.setText(file.getAbsolutePath());
    }

    ...

    private void onLaunchProgram(ActionEvent evt) {
        String strExecutableFilename = "MyExecutableProgam";
        String strSourceFolder = txtFolder.getText();
        String strCommand = strExecutableFilename + " " + strSourceFolder;
        lblMessage.setText("Processing");
        ImageIcon icon = new ImageIcon("clock.gif");
        lblPic.setIcon(icon);
        try {
            Process procCommand = Runtime.getRuntime().exec(strCommand);
            try {
                procCommand.waitFor();
            } catch (InterruptedException exception) {
                exception.printStackTrace();
            } finally {
            }
            lblMessage.setText("Finished");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }
    }

从示例代码很难确定如何执行onLaunchProgram方法,但是从您的描述来看,假设您是在事件调度线程的上下文中执行它是一个onLaunchProgram选择。

事件分派线程负责(除其他事项外)分派重画请求。 阻止此线程的任何事情都将阻止它更新UI。

由于procCommand.waitFor()是阻止操作,因此将阻止处理任何重画请求(或与此事件有关的任何事件),直到返回为止。

您应该在单独的线程中执行所有耗时或阻塞的过程。 但是,您遇到的问题是,对UI桅杆的所有更新都是在EDT的上下文中执行的(也就是说,您不应从EDT之外的任何线程更改/更新/修改/创建任何UI组件)

在Swing中,您有很多选择,我建议您使用SwingWorker 它将允许您在后台线程中执行该过程,但具有一些易于使用的方法来将更新重新同步到UI。

public class ProcessWorker extends SwingWorker<Integer, String> {

    private String program;
    private String sourceFolder;

    public ProcessWorker(String program, String sourceFolder) {
        this.program = program;
        this.sourceFolder = sourceFolder;
    }

    @Override
    protected void process(List<String> chunks) {
        // Back on the EDT
        for (String value : chunks) {
            if (value.equalsIgnoreCase("PROCESSING")) {
                lblMessage.setText("Processing");
                ImageIcon icon = new ImageIcon("clock.gif");
                lblPic.setIcon(icon);
            } else if (value.equalsIgnoreCase("FINISHED")) {
                lblMessage.setText("Finished");
            } else {
                // Possible some other message...
            }
        }
    }

    @Override
    protected Integer doInBackground() throws Exception {
        int result = -1;

        String strExecutableFilename = program;
        String strSourceFolder = sourceFolder;
        String strCommand = strExecutableFilename + " " + strSourceFolder;
        publish("PROCESSING");
//        lblMessage.setText("Processing");
//        ImageIcon icon = new ImageIcon("clock.gif");
//        lblPic.setIcon(icon);
        try {
            ProcessBuilder pb = new ProcessBuilder(program);
            pb.redirectError();
            pb.directory(new File(strSourceFolder));
            Process procCommand = pb.start();
//            Process procCommand = Runtime.getRuntime().exec(strCommand);
            try {
                result = procCommand.waitFor();
            } catch (InterruptedException exception) {
                exception.printStackTrace();
            } finally {
            }
//            lblMessage.setText("Finished");
            publish("FINISHED");
        } catch (IOException e) {
            e.printStackTrace();
        }

        return result;
    }
}

您还应该熟悉ProcessBuilder 它具有许多用于构建过程的有用方法,并克服了人们在尝试使Runtime.getRuntime().exec工作时遇到的一些困难。

您应该查看http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html了解更多详细信息

似乎您正在一个线程中完成所有操作。

使用事件分配线程来调用您的gui代码。

private void onLaunchProgram(ActionEvent evt) {
        String strExecutableFilename = "MyExecutableProgam";
        String strSourceFolder = txtFolder.getText();
        String strCommand = strExecutableFilename + " " + strSourceFolder;
        ImageIcon icon = new ImageIcon("clock.gif");
        javax.swing.SwingUtilities.invokeLater(
            new Runnable() {
                 public void run() {
                     lblMessage.setText("Processing");
                     lblPic.setIcon(icon);
                 }
            });

        try {
            Process procCommand = Runtime.getRuntime().exec(strCommand);
            try {
                procCommand.waitFor();
            } catch (InterruptedException exception) {
                exception.printStackTrace();
            } finally {
            }

            javax.swing.SwingUtilities.invokeLater(
                new Runnable() {
                    public void run() {
                      lblMessage.setText("Finished");
                    }
                 });
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM