Swingで時間のかかる処理の進捗表示:Javaメモ
m(_ _)mすいません。ちと怪しい
JAVAのSwing表示で時間のかかる作業の進捗表示をする
時間のかかる作業をGUIから起動する場合、進捗状況が把握できなく不安になる ことがあります。
作業を別スレッドで行い、そのスレッドからGUIの要素に進捗表示を行い、 終了などのイベントをGUI部に送るサンプルを載せます。
// ProgressTest.java:別スレッドだてで進捗状況を画面に表示する import javax.swing.*; import java.awt.*; import java.awt.event.*; // メインのながなが作業(GUIとは別スレッドで動く) class TestRunner extends Thread{ ProgressTest win; // 親方 int count; TestRunner(ProgressTest win_,int count_){ win = win_; count= count_; } public void run(){ try{ for(int n=count;n>=0;--n){ // text系はswingの制御スレッド外から変更可能 win.tf_status.setText(Integer.toString(n));// 親画面に直接設定 Thread.sleep(1000); } // invokeLaterではthisは伝わらない win.actionPerformed(new ActionEvent(this,0,"カウントが終わりました")); } catch(Exception e){e.printStackTrace(System.err);} } } // メインのウィンドウ public class ProgressTest extends JFrame implements ActionListener{ private JTextField tf_count; // 開始カウント数の設定 private JButton btn_start; // 開始ボタン private JButton btn_end; // 終了ボタン public JTextField tf_status; // 進捗(カウント)表示 private TestRunner runner; public void actionPerformed(ActionEvent e){ try{ Object src= e.getSource(); if( src==btn_start && runner==null ){ // 開始ボタンが押された int count = Integer.parseInt(tf_count.getText()); runner = new TestRunner(this,count); // 作業者生成 runner.start(); // 作業開始 } else if( src==btn_end ){ // 終了ボタンが押された System.exit(0); } else if( src==runner ){ // TestRunnerからのイベント JOptionPane.showMessageDialog( this ,e.getActionCommand(), "確認" , JOptionPane.INFORMATION_MESSAGE); runner=null; } } catch(Exception ee){ ee.printStackTrace(System.err); } } public static void main(String[] args) { ProgressTest win = new ProgressTest(); win.pack(); // サイズを中身に合わせるおまじない win.setVisible(true);// 表示をするおまじない } public ProgressTest() { super("ProgressTest"); Container pane = getContentPane(); // 最外殻 JPanel p0= new JPanel(); p0.setLayout(new BoxLayout(p0,BoxLayout.Y_AXIS)); pane.add(p0); // 1段目 JPanel p1= new JPanel(); p1.setLayout(new BoxLayout(p1,BoxLayout.X_AXIS)); p0.add(p1); p1.add(new JLabel("開始カウント: ")); tf_count = new JTextField("5"); p1.add(tf_count); // 2段目 JPanel p2= new JPanel(); p2.setLayout(new BoxLayout(p2,BoxLayout.X_AXIS)); p0.add(p2); btn_start = new JButton("カウント開始"); btn_end = new JButton("試験終了"); btn_start.addActionListener(this); btn_end.addActionListener(this); p2.add(btn_start); p2.add(btn_end); // status行 JPanel ps= new JPanel(); ps.setLayout(new BoxLayout(ps,BoxLayout.X_AXIS)); p0.add(ps); ps.add(new JLabel("カウント : ")); tf_status = new JTextField(""); ps.add(tf_status); // ×で終了するおまじない setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } }
表示画面は次のようになります。
プログラムではTestRunnerが時間のかかる処理を行っており スレッド化されています。
Threadの派生として作成し、run()関数に処理を記述します。
GUIとのやり取りのためProgressTestを変数として保持しています。
途中経過はGUIの要素に直接値をセットしています。GUIとは別スレッドですが、Textに
対する操作は問題なくGUIに反映されます(らしい)。
終了イベントをActionPerformed()呼び出しで通知しています。引数として作成する
ActionEventに自分自身と、適当なコード、適当なメッセージを乗せます。
GUIの要素に直接値をセットせず、全てイベントで渡してGUI側でセットすることももちろん可能です。
SwingUtilities.invokeLater()を用いる場合、thisがうまく伝わりません。
GUI側はstart()でTestRunnerを起動し、ActionPerformedでTestRunnerからのイベントを待ちます。
ここでは単純にイベントからメッセージを取り出し表示しています。
ソースとantのbuild.xmlとant起動バッチを置きました。A10_test.batでビルドし起動します。
WinProgress.zip
| 固定リンク

