簡體   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