0

私はSwingが初めてです。ユーザーがフォルダーを参照して選択できるようにするためのスイング ラッパーを作成しようとしています。そのフォルダー パスは、コンソール .exe プログラムへのコマンド ライン パラメーターとして使用されます。フォルダを選択して「プログラムの起動」ボタンをクリックした後、swing ウィンドウにプログラムが処理中であることを知らせるメッセージを表示し (そして時計のアニメーション GIF を表示)、外部プログラムを実行してから、別のメッセージを表示します。そのプログラムの実行が終了したとき。私が抱えている問題は、外部プログラムの実行が終了するまで「処理中」メッセージが表示されないことです。以下のコードでは、「プログラムの起動」ボタンがクリックされると、onLaunchProgram メソッドが実行されます。revalidate() と repaint() を試しましたが、変化はありませんでした。


    ...

    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 {
        }
    }
4

2 に答える 2

3

サンプル コードからメソッドの実行方法を判断するのは困難ですがonLaunchProgram、説明から、イベント ディスパッチ スレッドのコンテキスト内で実行していると想定するのが安全な方法です。

Event Dispatching Thread は、(とりわけ) 再描画要求のディスパッチを担当します。このスレッドをブロックすると、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をご覧ください。

于 2013-03-13T23:24:22.837 に答える
0

すべてを1つのスレッドで実行しているようです。

イベント ディスパッチ スレッドを使用して、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 {
        }
    }
于 2013-03-13T21:24:38.023 に答える