Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
255 views
in Technique[技术] by (71.8m points)

java - Swing message doesn't get displayed until after Runtime.getRuntime().exec() finishes execution

I am new to Swing. I am trying to create a swing wrapper to allow the user to browse and select a folder, and that folder path is used as a command line parameter to a console .exe program. After they select the folder and click a "Launch Program" button, I want the swing window to display a message telling them that the program is processing (and display an animated gif of a clock), run the external program, then display another message when that program has finished execution. The problem I'm having is that the "Processing" message doesn't get displayed until after the external program finishes execution. In the code below, the onLaunchProgram method gets executed when the "Launch Program" button is clicked. I've tried revalidate() and repaint(), but there was no change. I have a waitFor() for the "Finished" message, but even when I take that out, the "Processing" message and gif don't get displayed until after the external program finishes execution.


    ...

    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 {
        }
    }
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

It's difficult from your sample code to determine how you are executing the onLaunchProgram method, but from your description, it would be a safe beat to assume you are executing it within the context of the Event Dispatching Thread.

The Event Dispatching Thread is responsible for (amongst other things) dispatching repaint requests. Any thing that blocks this thread will prevent it from updating the UI.

Because procCommand.waitFor() is a blocking action, this will prevent any repaint request (or any events for that matter) from been processed until it returns.

You should execute all time consuming or blocking processes in a separate thread. The problem you have though, is all updates to the UI mast be executed within the context of the EDT (that is, you should never change/update/modify/create any UI component from any thread other then the EDT)

In Swing you have a number of options, in your case, I would suggest using a SwingWorker. It will allow you to execute the process in a background thread, but has some easy to use methods for resyncing updates to the 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;
    }
}

You should also familiarise yourself with ProcessBuilder. It has a number of useful methods for building process and overcomes some of the difficulties people have when trying to get Runtime.getRuntime().exec to work.

You should take a look at http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html for more details


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

56.9k users

...