1 package charactermanaj.ui.progress;
\r
3 import java.awt.BorderLayout;
\r
4 import java.awt.Component;
\r
5 import java.awt.Container;
\r
6 import java.awt.Dimension;
\r
7 import java.awt.event.ActionEvent;
\r
8 import java.awt.event.ActionListener;
\r
9 import java.lang.Thread.UncaughtExceptionHandler;
\r
11 import javax.swing.BorderFactory;
\r
12 import javax.swing.JDialog;
\r
13 import javax.swing.JFrame;
\r
14 import javax.swing.JLabel;
\r
15 import javax.swing.JProgressBar;
\r
16 import javax.swing.JRootPane;
\r
17 import javax.swing.SwingUtilities;
\r
18 import javax.swing.Timer;
\r
19 import javax.swing.border.BevelBorder;
\r
23 * ワーカースレッドの実行中、プログレスを表示するモーダルダイアログ.<br>
\r
24 * ワーカースレッドの実行が完了するとダイアログは自動的に閉じられる.<br>
\r
25 * モーダルダイアログであるため、ワーカースレッドの実行中はユーザはUIを操作することはできない.<br>
\r
28 * @param <T> ワーカーの処理結果の戻り値の型
\r
30 public class WorkerWithProgessDialog<T> extends JDialog {
\r
32 private static final long serialVersionUID = 1L;
\r
35 * ワーカースレッドが停止したことを示すフラグ
\r
37 private volatile boolean exitThread;
\r
42 private volatile T result;
\r
45 * ワーカースレッドが例外により終了した場合の例外
\r
47 private volatile Throwable occuredException;
\r
52 private Thread thread;
\r
55 * ワーカースレッドの状態を監視しプログレスに反映させるタイマー
\r
57 private Timer timer;
\r
60 * プログレスの更新頻度(タイマーのインターバル)
\r
62 private static int interval = 200;
\r
66 * 親フレームとワーカーを指定して構築する.<br>
\r
67 * @param parent 親フレーム
\r
68 * @param worker ワーカー
\r
70 public WorkerWithProgessDialog(JFrame parent, Worker<T> worker) {
\r
71 super(parent, true);
\r
73 if (worker == null) {
\r
74 throw new IllegalArgumentException();
\r
77 initComponent(parent, worker);
\r
79 } catch (RuntimeException ex) {
\r
86 * 親ダイアログとワーカーを指定して構築する.<br>
\r
87 * @param parent 親フレーム
\r
88 * @param worker ワーカー
\r
90 public WorkerWithProgessDialog(JDialog parent, Worker<T> worker) {
\r
91 super(parent, true);
\r
93 if (worker == null) {
\r
94 throw new IllegalArgumentException();
\r
97 initComponent(parent, worker);
\r
99 } catch (RuntimeException ex) {
\r
107 * @param parent 親フレームまたは親ダイアログ
\r
108 * @param worker ワーカー
\r
110 private void initComponent(Component parent, Worker<T> worker) {
\r
112 setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
\r
115 setResizable(false);
\r
116 // ウィンドウ装飾なし (閉じるボタンやタイトルバーなども無し)
\r
117 setUndecorated(true);
\r
119 Container container = getContentPane();
\r
122 final JProgressBar progressBar = new JProgressBar();
\r
123 progressBar.setIndeterminate(true);
\r
124 progressBar.setStringPainted(false);
\r
126 container.add(progressBar, BorderLayout.SOUTH);
\r
129 String title = "please wait for a while.";
\r
130 final JLabel lblCaption = new JLabel(title);
\r
131 container.add(lblCaption, BorderLayout.NORTH);
\r
134 JRootPane rootPane = getRootPane();
\r
135 rootPane.setBorder(BorderFactory.createCompoundBorder(
\r
136 BorderFactory.createBevelBorder(BevelBorder.RAISED),
\r
137 BorderFactory.createEmptyBorder(5, 5, 5, 5))
\r
141 Dimension dim = progressBar.getPreferredSize();
\r
142 dim.width = (int)(parent.getWidth() * 0.7);
\r
143 progressBar.setPreferredSize(dim);
\r
149 setLocationRelativeTo(parent);
\r
151 // ワーカースレッドとプログレスダイアログとの状態通信用オブジェクト
\r
152 final ProgressInfoHolder progressHandle = new ProgressInfoHolder() {
\r
154 public synchronized void flush() {
\r
155 final String caption = getCaption();
\r
156 final Boolean indeterminate = getIndeterminate();
\r
157 final Integer progressMaximum = getProgressMaximum();
\r
158 final Integer progressCurrent = getProgressCurrent();
\r
160 if (caption != null || progressMaximum != null ||
\r
161 progressCurrent != null || indeterminate != null) {
\r
162 SwingUtilities.invokeLater(new Runnable() {
\r
163 public void run() {
\r
164 // 設定されている値でプログレスダイアログに状態を反映する.
\r
165 if (caption != null) {
\r
166 lblCaption.setText(caption);
\r
168 if (progressMaximum != null) {
\r
169 progressBar.setMaximum(progressMaximum.intValue());
\r
171 if (progressCurrent != null) {
\r
172 progressBar.setValue(progressCurrent.intValue());
\r
174 if (indeterminate != null) {
\r
175 progressBar.setIndeterminate(indeterminate.booleanValue());
\r
176 progressBar.setStringPainted( !indeterminate.booleanValue());
\r
186 // プログレスダイアログに状態を反映させるためのタイマー
\r
187 timer = new Timer(interval, new ActionListener() {
\r
188 public void actionPerformed(ActionEvent e) {
\r
189 if (exitThread || !thread.isAlive()) {
\r
190 // スレッドが終了していればスレッド停止を通知する.
\r
194 // スレッドが生きていれば、スレッドの進行状態を
\r
195 // プログレスダイアログに反映させる.
\r
196 progressHandle.flush();
\r
202 thread = new Thread(createJob(worker, progressHandle));
\r
203 thread.setDaemon(true);
\r
205 // ワーカースレッドが予期せぬハンドルされていない例外により終了した場合のハンドラ.
\r
206 thread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
\r
207 public void uncaughtException(Thread t, Throwable e) {
\r
208 occuredException = e;
\r
218 public static int getInterval() {
\r
224 * @param interval 表示間隔
\r
226 public static void setInterval(int interval) {
\r
227 WorkerWithProgessDialog.interval = interval;
\r
232 * ワーカーをラップするワーカースレッドのジョブを作成する.<br>
\r
233 * @param worker ワーカー
\r
234 * @param progressHandle 進行状態の通知ハンドル
\r
237 protected Runnable createJob(final Worker<T> worker, final ProgressHandle progressHandle) {
\r
238 return new Runnable() {
\r
239 public void run() {
\r
242 worker.doWork(progressHandle);
\r
244 } catch (Throwable ex) {
\r
245 occuredException = ex;
\r
256 * ワーカースレッドより、スレッドが終了したことを通知される.<br>
\r
257 * ワーカースレッド自身か、ワーカースレッドの例外ハンドラか、
\r
258 * タイマーから呼び出されるため、2回以上呼び出される可能性がある.<br>
\r
260 protected void onExitWork() {
\r
262 SwingUtilities.invokeLater(new Runnable() {
\r
263 public void run() {
\r
264 // プログレスダイアログが表示されている場合、
\r
265 // それを破棄する.(モーダルの解除)
\r
266 if (isDisplayable() && isVisible()) {
\r
274 * ワーカースレッドを開始し、プログレスダイアログを表示し、
\r
275 * ワーカースレッドの完了まで待機する.<br>
\r
276 * @throws WorkerException ワーカースレッドが例外により終了した場合
\r
278 public void startAndWait() throws WorkerException {
\r
281 occuredException = null;
\r
282 exitThread = false;
\r
290 // (モーダルダイアログが非表示されるまで制御を返さない.)
\r
300 // ワーカースレッドの停止を待機する.
\r
304 } catch (InterruptedException ex) {
\r
305 // 割り込みされた場合は、ワーカースレッドを割り込みする.
\r
306 thread.interrupt();
\r
311 // ワーカースレッドが例外により終了した場合
\r
313 if (occuredException != null) {
\r
314 throw new WorkerException(
\r
315 "worker has failed." + occuredException.getMessage(),
\r
322 * ワーカースレッドの戻り値を取得する.<br>
\r
323 * 正常終了していない場合、または処理中の場合は意味を持たない.<br>
\r
324 * @return ワーカースレッドの戻り値
\r
326 public T getResult() {
\r