OSDN Git Service

FIX: FileChooser TEXTFIELDに直接ファイルパスを入力した後に「選択」ボタンを押しても入力されたフォルダをcurrent directoryとして開...
[importpicture/importpicture.git] / importPicture / src / osm / jp / gpx / matchtime / gui / AdjustTime.java
1 package osm.jp.gpx.matchtime.gui;
2 import java.awt.*;
3 import java.awt.event.ActionEvent;
4 import java.io.File;
5 import java.io.FileNotFoundException;
6 import java.io.IOException;
7 import java.text.SimpleDateFormat;
8 import java.util.Date;
9
10 import javax.swing.*;
11
12 import osm.jp.gpx.*;
13 import org.apache.commons.imaging.ImageReadException;
14 import org.apache.commons.imaging.ImageWriteException;
15 import org.apache.commons.imaging.Imaging;
16 import org.apache.commons.imaging.common.ImageMetadata;
17 import org.apache.commons.imaging.formats.jpeg.JpegImageMetadata;
18 import org.apache.commons.imaging.formats.tiff.TiffImageMetadata;
19 import org.apache.commons.imaging.formats.tiff.constants.ExifTagConstants;
20
21 /**
22  * 本プログラムのメインクラス
23  */
24 @SuppressWarnings("serial")
25 public class AdjustTime extends JFrame
26 {
27     public static final String PROGRAM_NAME = "AdjustTime for JOSM";
28     public static final String PROGRAM_VARSION = "3.0";
29     public static final String PROGRAM_UPDATE = "2015/07/26";
30         
31     // Used for addNotify check.
32     boolean fComponentsAdjusted = false;
33     
34     //{{DECLARE_CONTROLS
35     JPanel cardPanel;       // ウィザード形式パネル(カード型)
36     JPanel[] cards;
37     int cardPanelNo = 0;
38     JPanel argsPanel;           // パラメータ設定パネル       (上部)
39     JScrollPane imageSPane;     // スクロールパネル
40     JLabel imageLabel;          // 基準時刻画像表示
41     ButtonGroup baseTimeGroup;  // 基準時刻の指定グループ
42     JRadioButton exifBase;              // EXIF日時を基準にする/ !(ファイル更新日時を基準にする)
43     JRadioButton fupdateBase;   // File更新日時を基準にする/ !(XIF日時を基準にする)
44     JCheckBox noFirstNode;      // GPX: <trkseg>セグメントの最初の1ノードは無視する。 {ON | OFF}
45     JCheckBox gpxReuse;         // 生成されたGPXファイル(ファイル名が'_.gpx'で終わるもの)も対象にする。 {ON | OFF}
46     JTextArea textArea;         // 実行結果表示領域
47     //ImagePreview imagePane;   // 基準時刻画像表示
48     ParameterPanelFolder arg1_srcFolder;
49     ParameterPanelImageFile arg2_baseTimeImg;
50     ParameterPanel arg3_basetiome;
51     JCheckBox exifON;           // EXIF 書き出しモード / !(EXIFの書き換えはしない)
52     ParameterPanelFolder arg5_outputFolder;       // EXIF 書き出しフォルダ
53     ParameterPanelFolder arg4_gpxFolder;       // GPXファイル・フォルダ
54     
55     JPanel buttonPanel;         // ボタンパネル   (下部)
56     JButton openButton;         // [Fit]ボタン
57     JButton zoomInButton;       // [Zoom in]ボタン
58     JButton zoomOutButton;      // [Zoom out]ボタン
59     JButton nextButton;     // [次へ]ボタン
60     JButton backButton;     // [戻る]ボタン
61     JButton doButton;       // [処理実行]ボタン
62     //}}
63
64     //{{DECLARE_MENUS
65     java.awt.MenuBar mainMenuBar;
66     java.awt.Menu menu1;
67     java.awt.MenuItem miDoNewFileList;
68     java.awt.MenuItem miDoDirSize;
69     java.awt.MenuItem miDoReadXML;
70     java.awt.MenuItem miExit;
71     java.awt.Menu menu3;
72     java.awt.MenuItem miAbout;
73     //}}
74
75     class SymWindow extends java.awt.event.WindowAdapter {
76         /**
77          * このFrameが閉じられるときの動作。
78          * このパネルが閉じられたら、このアプリケーションも終了させる。
79          */
80         @Override
81         public void windowClosing(java.awt.event.WindowEvent event) {
82             Object object = event.getSource();
83             if (object == AdjustTime.this) {
84                 DbMang_WindowClosing(event);
85             }
86         }
87     }
88
89     class SymAction implements java.awt.event.ActionListener {
90         @Override
91         public void actionPerformed(java.awt.event.ActionEvent event) {
92             Object object = event.getSource();
93             if (object == miAbout) {
94                 miAbout_Action(event);
95             }
96             else if (object == miExit) {
97                 miExit_Action(event);
98             }
99             else if (object == openButton) {
100                 imageView_Action(event);
101             }
102             else if (object == zoomInButton) {
103                 zoomin_Action(event);
104             }
105             else if (object == zoomOutButton) {
106                 zoomout_Action(event);
107             }
108             else if (object == arg2_baseTimeImg.argField) {
109                 imageView_Action(event);
110             }
111             else if (object == arg2_baseTimeImg.openButton) {
112                 selectImage_Action(event);
113                 imageView_Action(event);
114             }
115             else if (object == exifON) {
116                 exifON_Action(event);
117             }
118             else if (object == doButton) {
119                 doButton_Action(event);
120             }
121             else if (object == nextButton) {
122                 nextButton_Action(event);
123             }
124             else if (object == backButton) {
125                 backButton_Action(event);
126             }
127         }
128     }
129     
130     AppParameters params;
131
132         /**
133          * データベース内のテーブルを一覧で表示するFrame
134          * @throws IOException 
135          */
136     public AdjustTime() throws IOException
137     {
138         // INIT_CONTROLS
139         Container container = getContentPane();
140         container.setLayout(new BorderLayout());
141         setSize(getInsets().left + getInsets().right + 960,getInsets().top + getInsets().bottom + 480);
142         setTitle(AdjustTime.PROGRAM_NAME +" v"+ AdjustTime.PROGRAM_VARSION);
143         
144         params = new AppParameters();
145         
146         //---------------------------------------------------------------------
147         cardPanel = new JPanel();
148         cardPanel.setLayout(new CardLayout());
149         container.add(cardPanel, BorderLayout.CENTER);
150         
151         nextButton = new JButton("次へ");
152         container.add(nextButton, BorderLayout.EAST);
153
154         backButton = new JButton("戻る");
155         container.add(backButton, BorderLayout.WEST);
156
157         cards = new JPanel[5];
158         for (int i=0; i < 5; i++) {
159             cards[i] = new JPanel();
160             cardPanel.add(cards[i], String.valueOf(i));
161         }
162         cardPanelNo = 0;
163
164         //---------------------------------------------------------------------
165         // 1.[対象フォルダ]設定パネル
166         int cardNo = 0;
167         cards[cardNo].setLayout(new BorderLayout());
168         JLabel label1 = new JLabel();
169         label1.setText("<html><p>1. 位置情報を付加したい画像ファイルが格納されているフォルダを選択してください。</p><ul><li>コピー動作を行うと、ファイル更新時刻がコピーを実行した時刻に書き換わってしまうことがあります。オリジナルのカメラUSB内のフォルダを直接指定することをおすすめします。</li></ul>");
170         cards[cardNo].add(label1, BorderLayout.NORTH);
171         
172         argsPanel = new JPanel();
173         argsPanel.setLayout(new BoxLayout(argsPanel, BoxLayout.Y_AXIS));
174         arg1_srcFolder = new ParameterPanelFolder("対象フォルダ: ", params.getProperty(AppParameters.IMG_SOURCE_FOLDER));
175         argsPanel.add(arg1_srcFolder);
176         cards[cardNo].add(argsPanel, BorderLayout.CENTER);
177         
178         //---------------------------------------------------------------------
179         // 2.[基準時刻画像]設定パネル
180         cardNo++;
181         cards[cardNo].setLayout(new BorderLayout());
182         JLabel label2 = new JLabel();
183         label2.setText("<html><p>2. 正確な撮影時刻が判明できる画像を選んでください。</p><ul><li>スマートフォンの時計画面(秒が判別できること)を撮影した画像</li><li>カメラの時計が正確ならば、どの画像を選んでも構いません。</li></ul>");
184         cards[cardNo].add(label2, BorderLayout.NORTH);
185
186         argsPanel = new JPanel();
187         argsPanel.setLayout(new BoxLayout(argsPanel, BoxLayout.Y_AXIS));
188         arg2_baseTimeImg = new ParameterPanelImageFile("基準時刻画像: ", params.getProperty(AppParameters.IMG_BASE_FILE), arg1_srcFolder);
189         argsPanel.add(arg2_baseTimeImg);
190         
191         baseTimeGroup = new ButtonGroup();
192         exifBase = new JRadioButton("EXIFの日時を基準にする");
193         fupdateBase = new JRadioButton("File更新日時を基準にする");
194         baseTimeGroup.add(exifBase);
195         baseTimeGroup.add(fupdateBase);
196         argsPanel.add(exifBase);
197         argsPanel.add(fupdateBase);
198         if (params.getProperty(AppParameters.GPX_BASETIME).equals("EXIF_TIME")) {
199                 fupdateBase.setSelected(false);
200                 exifBase.setSelected(true);
201         }
202         else {
203                 fupdateBase.setSelected(true);
204                 exifBase.setSelected(false);
205         }
206         cards[cardNo].add(argsPanel, BorderLayout.CENTER);
207         
208         //---------------------------------------------------------------------
209         // 3.基準時刻の入力画面
210         cardNo++;
211         cards[cardNo].setLayout(new BorderLayout());
212         argsPanel = new JPanel();
213         argsPanel.setLayout(new GridLayout(2, 1));
214
215         JLabel label3 = new JLabel();
216         label3.setText("<html><p>3. 正確な撮影時刻を入力してください。</p><ul><li>カメラの時計が正確ならば、設定を変更する必要はありません。</li></ul>");
217         argsPanel.add(label3);
218         arg3_basetiome = new ParameterPanel("  基準時刻: ", ImportPicture.TIME_FORMAT_STRING);
219         argsPanel.add(arg3_basetiome);
220         cards[cardNo].add(argsPanel, BorderLayout.NORTH);
221
222         // 参考画像
223         imageLabel = new JLabel();
224         imageSPane = new JScrollPane(imageLabel);
225         cards[cardNo].add(imageSPane, BorderLayout.CENTER);
226               
227         // 画像ファイル選択ダイアログを起動するボタン
228         buttonPanel = new JPanel();
229         buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
230         openButton = new JButton(createImageIcon("images/Fit16.gif"));
231         buttonPanel.add(openButton);
232         zoomInButton = new JButton(createImageIcon("images/ZoomIn16.gif"));
233         buttonPanel.add(zoomInButton);
234         zoomOutButton = new JButton(createImageIcon("images/ZoomOut16.gif"));
235         buttonPanel.add(zoomOutButton);
236         cards[cardNo].add(buttonPanel, BorderLayout.SOUTH);
237         
238         //---------------------------------------------------------------------
239         // 4.GPXファイル設定画面
240         cardNo++;
241         cards[cardNo].setLayout(new BorderLayout());
242         JLabel label4 = new JLabel();
243         label4.setText("<html><p>4. ヒモ付を行うGPXファイルを選択してください。</p><ul><li>フォルダを指定すると、フォルダ内にあるすべてのGPXファイルを対象とします。</li><li>カメラの時計が正確ならば、どの画像を選んでも構いません。</li></ul>");
244         cards[cardNo].add(label4, BorderLayout.NORTH);
245         
246         JPanel tmpPanel4a = new JPanel();
247         tmpPanel4a.setLayout(new BoxLayout(tmpPanel4a, BoxLayout.Y_AXIS));
248         arg4_gpxFolder = new ParameterPanelFolder("GPXフォルダ: ", params.getProperty(AppParameters.IMG_SOURCE_FOLDER), JFileChooser.FILES_AND_DIRECTORIES);
249         tmpPanel4a.add(arg4_gpxFolder);
250         noFirstNode = new JCheckBox("<trkseg>セグメントの最初の1ノードは無視する。", params.getProperty(AppParameters.GPX_NO_FIRST_NODE).equals("ON"));
251         tmpPanel4a.add(noFirstNode);
252         gpxReuse = new JCheckBox("生成されたGPXファイル(ファイル名が'_.gpx'で終わるもの)も対象にする。", params.getProperty(AppParameters.GPX_REUSE).equals("ON"));
253         gpxReuse.setEnabled(true);
254         tmpPanel4a.add(gpxReuse);
255         cards[cardNo].add(tmpPanel4a, BorderLayout.CENTER);
256         
257         //---------------------------------------------------------------------
258         // 5.EXIF更新設定画面
259         cardNo++;
260         cards[cardNo].setLayout(new BorderLayout());
261         JLabel label5 = new JLabel();
262         label5.setText("<html><p>5. EXIF変換を行うかどうかを選択してください。</p><ul><li>EXIF変換を行う場合には、変換ファイルを出力するフォルダも指定する必要があります。</li><li>出力フォルダには、書き込み権限と、十分な空き容量が必要です。</li></ul>");
263         cards[cardNo].add(label5, BorderLayout.NORTH);
264         
265         JPanel tmpPanel5 = new JPanel();
266         tmpPanel5.setLayout(new BoxLayout(tmpPanel5, BoxLayout.Y_AXIS));
267
268         exifON = new JCheckBox("EXIFの変換をする", false);
269         tmpPanel5.add(exifON);
270         
271         arg5_outputFolder = new ParameterPanelFolder("書き出しフォルダ: ", params.getProperty(AppParameters.IMG_OUTPUT_FOLDER));
272         tmpPanel5.add(arg5_outputFolder);
273         cards[cardNo].add(tmpPanel5, BorderLayout.CENTER);
274         
275         doButton = new JButton("処理実行", AdjustTime.createImageIcon("images/media_playback_start.png"));
276         cards[cardNo].add(doButton, BorderLayout.SOUTH);
277
278
279         //---------------------------------------------------------------------
280         // INIT_MENUS
281         menu1 = new java.awt.Menu("File");
282         miExit = new java.awt.MenuItem(QuitDialog.TITLE);
283         miExit.setFont(new Font("Dialog", Font.PLAIN, 12));
284         menu1.add(miExit);
285
286         miAbout = new java.awt.MenuItem("About...");
287         miAbout.setFont(new Font("Dialog", Font.PLAIN, 12));
288
289         menu3 = new java.awt.Menu("Help");
290         menu3.setFont(new Font("Dialog", Font.PLAIN, 12));
291         menu3.add(miAbout);
292
293         mainMenuBar = new java.awt.MenuBar();
294         mainMenuBar.setHelpMenu(menu3);
295         mainMenuBar.add(menu1);
296         mainMenuBar.add(menu3);
297         setMenuBar(mainMenuBar);
298         
299
300         //{{REGISTER_LISTENERS
301         SymWindow aSymWindow = new SymWindow();
302         this.addWindowListener(aSymWindow);
303         SymAction lSymAction = new SymAction();
304         miAbout.addActionListener(lSymAction);
305         miExit.addActionListener(lSymAction);
306         openButton.addActionListener(lSymAction);
307         zoomOutButton.addActionListener(lSymAction);
308         zoomInButton.addActionListener(lSymAction);
309         arg2_baseTimeImg.argField.addActionListener(lSymAction);
310         arg2_baseTimeImg.openButton.addActionListener(lSymAction);
311         doButton.addActionListener(lSymAction);
312         exifON.addActionListener(lSymAction);
313         noFirstNode.addActionListener(lSymAction);
314         gpxReuse.addActionListener(lSymAction);
315         //arg1Panel_4.field.addActionListener(lSymAction);
316         nextButton.addActionListener(lSymAction);
317         backButton.addActionListener(lSymAction);
318         //}}
319     }
320     
321     /**
322      * Shows or hides the component depending on the boolean flag b.
323      * @param b trueのときコンポーネントを表示; その他のとき, componentを隠す.
324      * @see java.awt.Component#isVisible
325      */
326     @Override
327     public void setVisible(boolean b) {
328         if(b) {
329             setLocation(50, 50);
330         }
331         super.setVisible(b);
332     }
333     
334     /**
335      * このクラスをインスタンスを生成して表示する。
336      * コマンドラインの引数はありません。
337      * @param args
338      */    
339     static public void main(String args[]) {
340         SwingUtilities.invokeLater(() -> {
341             try {
342                                 createAndShowGUI();
343                         } catch (Exception e) {
344                                 e.printStackTrace();
345                         }
346         });
347     }
348     private static void createAndShowGUI() throws IOException {
349         (new AdjustTime()).setVisible(true);
350     }
351
352     @Override
353     public void addNotify()     {
354         // Record the size of the window prior to calling parents addNotify.
355         Dimension d = getSize();
356
357         super.addNotify();
358
359         if (fComponentsAdjusted)
360             return;
361
362         // Adjust components according to the insets
363         setSize(getInsets().left + getInsets().right + d.width, getInsets().top + getInsets().bottom + d.height);
364         Component components[] = getComponents();
365         for (Component component : components) {
366             Point p = component.getLocation();
367             p.translate(getInsets().left, getInsets().top);
368             component.setLocation(p);
369         }
370         fComponentsAdjusted = true;
371     }
372
373     void DbMang_WindowClosing(java.awt.event.WindowEvent event) {
374         setVisible(false);  // hide the Manager
375         dispose();                      // free the system resources
376         System.exit(0);         // close the application
377     }
378
379     void miAbout_Action(java.awt.event.ActionEvent event) {
380         // Action from About Create and show as modal
381         (new AboutDialog(this, true)).setVisible(true);
382     }
383     
384     void miExit_Action(java.awt.event.ActionEvent event) {
385         // Action from Exit Create and show as modal
386         //(new hayashi.yuu.tools.gui.QuitDialog(this, true)).setVisible(true);
387         (new QuitDialog(this, true)).setVisible(true);
388     }
389
390     ImageIcon refImage;
391     
392     /**
393      * 選択された画像ファイルを表示する
394      * 基準画像ボタンがクリックされた時に、基準時刻フィールドに基準画像の作成日時を設定する。
395      * @param ev
396      * @throws ImageReadException 
397      * @throws ImageWriteException 
398      */
399     public void imageView_Action(ActionEvent ev) {
400         String path = (new File(arg1_srcFolder.getText(), arg2_baseTimeImg.getText())).getPath();
401         
402         File timeFile = new File(path);
403         long lastModifyTime = timeFile.lastModified();
404         arg3_basetiome.argField.setText(ImportPicture.dfjp.format(new Date(lastModifyTime)));
405
406         if (exifBase.isSelected()) {
407                 try {
408                 ImageMetadata meta = Imaging.getMetadata(timeFile);
409                 arg3_basetiome.argField.setText("imageView_Action : 412");
410
411                 JpegImageMetadata jpegMetadata = (JpegImageMetadata)meta;
412                 if (jpegMetadata != null) {
413                     TiffImageMetadata exif = jpegMetadata.getExif();
414                     if (exif != null) {
415                         String dateTimeOriginal = exif.getFieldValue(ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL)[0];
416                         lastModifyTime = (new SimpleDateFormat("yyyy:MM:dd HH:mm:ss")).parse(dateTimeOriginal).getTime();
417                         arg3_basetiome.argField.setText(ImportPicture.dfjp.format(new Date(lastModifyTime)));
418                     }
419                     else {
420                         arg3_basetiome.argField.setText("exif == null");
421                     }
422                 }
423                 }
424                 catch (Exception e) {}
425         }
426         
427         int size_x = imageSPane.getWidth() - 8;
428         ImageIcon tmpIcon = new ImageIcon(path);
429         refImage = tmpIcon;
430         if (tmpIcon.getIconWidth() > size_x) {
431             refImage = new ImageIcon(tmpIcon.getImage().getScaledInstance(size_x, -1, Image.SCALE_DEFAULT));
432         }
433         imageLabel.setIcon(refImage);
434         repaint();
435     }
436
437     public void zoomin_Action(ActionEvent ev) {
438         if (refImage != null) {
439                 int size_x = imageLabel.getWidth();
440                 String path = (new File(arg1_srcFolder.getText(), arg2_baseTimeImg.getText())).getPath();
441                 ImageIcon tmpIcon = new ImageIcon(path);
442                 refImage = new ImageIcon(tmpIcon.getImage().getScaledInstance(size_x * 2, -1, Image.SCALE_DEFAULT));
443                 imageLabel.setIcon(refImage);
444             repaint();
445         }
446     }
447
448     public void zoomout_Action(ActionEvent ev) {
449         if (refImage != null) {
450                 int size_x = imageLabel.getWidth();
451                 ImageIcon tmpIcon = refImage;
452                 refImage = new ImageIcon(tmpIcon.getImage().getScaledInstance(size_x / 2, -1, Image.SCALE_DEFAULT));
453                 imageLabel.setIcon(refImage);
454             repaint();
455         }
456     }
457     
458     /**
459      * ソースディレクトリが選択された時のアクション
460      * → AdjustTime.ini に書き込む
461      * @param ev
462      */
463     public void selectSource_Action(ActionEvent ev) {
464     }
465     
466     public void selectImage_Action(ActionEvent ev) {
467         JFileChooser fc;
468
469         //Set up the file chooser.
470                 File sdir = new File(arg1_srcFolder.getText());
471                 System.out.println(sdir.getPath());
472                 if (sdir.isDirectory()) {
473                 fc = new JFileChooser(sdir);
474                 }
475                 else {
476                 fc = new JFileChooser();
477                 }
478
479             //Add a custom file filter and disable the default
480             //(Accept All) file filter.
481         fc.addChoosableFileFilter(new ImageFilter());
482         fc.setAcceptAllFileFilterUsed(false);
483
484         //Add custom icons for file types.
485         fc.setFileView(new ImageFileView());
486
487         //Add the preview pane.
488         fc.setAccessory(new ImagePreview(fc));
489
490         //Show it.
491         int returnVal = fc.showDialog(this, "選択");
492
493         //Process the results.
494         if (returnVal == JFileChooser.APPROVE_OPTION) {
495             File file = fc.getSelectedFile();
496             arg2_baseTimeImg.argField.setText(file.getName());
497         }
498
499         //Reset the file chooser for the next time it's shown.
500         fc.setSelectedFile(null);
501     }
502     
503     /** Returns an ImageIcon, or null if the path was invalid.
504      * @param path
505      * @return  */
506     public static ImageIcon createImageIcon(String path) {
507         java.net.URL imgURL = AdjustTime.class.getResource(path);
508         if (imgURL != null) {
509             return new ImageIcon(imgURL);
510         } else {
511             System.err.println("Couldn't find file: " + path);
512             return null;
513         }
514     }
515     
516     /**
517      * checkbox[EXIF書き出し]を変更した場合のアクション
518      *  ON ー> EXIF変換先フォルダのフィールドを有効にする
519      *  OFF -> EXIF変換先フォルダのフィールドを無効にする
520      * @param event
521      */
522     void exifON_Action (ActionEvent event) {
523                 arg5_outputFolder.setEnabled(exifON.isEnabled());
524     }
525
526     /**
527      * [実行]ボタンをクリックしたときの動作
528      * @param event
529      * @throws IOException 
530      * @throws FileNotFoundException 
531      */
532     void doButton_Action(java.awt.event.ActionEvent event) {
533         doButton.setEnabled(false);
534
535         String[] argv = new String[5];
536         argv[0] = arg1_srcFolder.getText();
537         argv[1] = arg2_baseTimeImg.getText();
538         argv[2] = arg3_basetiome.getText();
539         argv[3] = (exifON.isSelected() ? arg5_outputFolder.getText() : "noEXIF");
540         argv[4] = arg4_gpxFolder.getText();
541         
542         this.params.setProperty(AppParameters.GPX_NO_FIRST_NODE, (noFirstNode.isSelected() ? "ON" : "OFF"));
543         this.params.setProperty(AppParameters.GPX_REUSE, (gpxReuse.isSelected() ? "ON" : "OFF"));
544         this.params.setProperty(AppParameters.GPX_SOURCE_FOLDER, arg4_gpxFolder.getText());
545         this.params.setProperty(AppParameters.IMG_SOURCE_FOLDER, arg1_srcFolder.getText());
546         this.params.setProperty(AppParameters.IMG_BASE_FILE, arg2_baseTimeImg.getText());
547         this.params.setProperty(AppParameters.GPX_BASETIME, arg3_basetiome.getText());
548         this.params.setProperty(AppParameters.IMG_OUTPUT_FOLDER, arg4_gpxFolder.getText());
549         try {
550             this.params.store();
551         }
552         catch(Exception e) {}
553
554         (new DoDialog(this, argv)).setVisible(true);
555                 
556         doButton.setEnabled(true);
557     }
558     
559     /**
560      * [次へ]ボタンをクリックした時の動作
561      * @param event 
562      */
563     void nextButton_Action(ActionEvent event) {
564         if ((cardPanelNo + 1) < cards.length) {
565             cardPanelNo++;
566             CardLayout cl = (CardLayout)(cardPanel.getLayout());
567             cl.show(cardPanel, String.valueOf(cardPanelNo));
568         }
569     }
570
571     /**
572      * [戻る]ボタンをクリックした時の動作
573      * @param event
574      */
575     void backButton_Action(ActionEvent event) {
576         if ((cardPanelNo - 1) >= 0) {
577             cardPanelNo--;
578             CardLayout cl = (CardLayout)(cardPanel.getLayout());
579             cl.show(cardPanel, String.valueOf(cardPanelNo));
580         }
581     }
582 }