Swingでプログレスダイアログ
Swingで進捗ダイアログを出す必要性があったので書いてみた。
標準ライブラリに付属しているProgressMonitorやProgressMonitorInputStreamもまた、進捗ダイアログを出してくれるのだが、処理にどれだけ時間がかかるかわからない場合、ちょっと使いづらかったので。。
package jp.fraction.swing;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Frame;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* @author yuanying
*
* @param <R>
*/
public class ProgressDialog<R> extends JDialog implements ActionListener {
/**
*
*/
private static final long serialVersionUID = -4556558246742108136L;
private static final Log log = LogFactory.getLog(ProgressDialog.class);
private static final String CANCEL_TEXT = UIManager
.getString("OptionPane.cancelButtonText");
final private FutureTask<R> result;
final private String message;
private boolean canceled;
/**
* ProgressDialogをモーダルダイアログとして生成します。
*
* @param owner このダイアログの親フレーム。
* @param title ダイアログのタイトル。
* @param message ダイアログに表示するメッセージ。
* @param call 実行する処理。
* @throws HeadlessException
*/
@SuppressWarnings("unchecked")
public ProgressDialog(Frame owner, String title, String message,
Callable<R> call) throws HeadlessException {
super(owner, title, true);
this.initialize(owner);
InvocationHandler handler = new CallableHandler(call);
Callable<R> p = (Callable<R>) Proxy.newProxyInstance(Callable.class
.getClassLoader(), new Class[] { Callable.class }, handler);
this.result = new FutureTask(p);
this.message = message;
new Thread(this.result).start();
this.setVisible(true);
}
private void initialize(Frame owner) {
Container contentPane = this.getContentPane();
contentPane.setLayout(new BorderLayout());
contentPane.add(this.createOptionPane(), BorderLayout.CENTER);
this.pack();
this.setLocationRelativeTo(owner);
this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
if (ProgressDialog.this.result != null) {
ProgressDialog.this.cancel();
}
}
});
}
private JOptionPane createOptionPane() {
JProgressBar bar = new JProgressBar();
bar.setIndeterminate(true);
Object[] messageList = { this.message, bar };
JButton cancelBtn = new JButton(CANCEL_TEXT);
cancelBtn.addActionListener(this);
return new JOptionPane(messageList, JOptionPane.INFORMATION_MESSAGE,
JOptionPane.DEFAULT_OPTION, null, new Object[] { cancelBtn },
null);
}
public void actionPerformed(ActionEvent e) {
this.cancel();
}
/**
*
* @return
*/
public synchronized boolean isCanceled() {
return canceled;
}
/**
*
*
*/
public synchronized void cancel() {
if (this.result != null) {
this.result.cancel(true);
}
this.setVisible(false);
this.canceled = true;
}
/**
* 処理結果を返します。まだ処理が始まっていなかった場合、もしくは実行中に例外が発生した場合は例外を投げます。
*
* @return
* @throws Exception
*/
public R getResult() throws Exception {
return this.result.get();
}
private class CallableHandler implements InvocationHandler {
private Callable<R> call;
public CallableHandler(Callable<R> call) {
this.call = call;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Exception e1 = null;
Object rtn = null;
try {
rtn = method.invoke(this.call, args);
} catch (Exception e) {
e1 = e;
}
if ("call".equals(method.getName())) {
log.debug("call is finished");
SwingUtilities.invokeLater(new Runnable() {
public void run() {
ProgressDialog.this.setVisible(false);
// ProgressDialog.this.dispose();
}
});
}
if (e1 != null) {
throw e1;
}
return rtn;
}
}
/**
* モーダルダイアログを表示し、結果を返します。結果が途中でキャンセルされたり、計算中に例外が発生した場合は、例外を投げます。
*
* @param <R>
* @param owner ダイアログの親フレーム。
* @param title ダイアログのタイトル。
* @param message ダイアログに表示するメッセージ。
* @param callback 実行するコールバック関数。
* @return
* @throws Exception
*/
public static <R> R execute(Frame owner, String title, String message,
Callable<R> callback) throws Exception {
ProgressDialog<R> dialog = new ProgressDialog<R>(owner, title, message,
callback);
return dialog.getResult();
}
}