最初は読みにくいかもしれませんが、プログラムを何度も繰り返し追うことで、次第にコツがつかめてきます。
今回は Swing で JFrame クラスを使った場合の、最も基本的な部分を解説します。
自動的に生成されたソースコード
PrefFrame.java
package pref;
import javax.swing.SwingUtilities;
import java.awt.BorderLayout;
import javax.swing.JPanel;
import javax.swing.JFrame;
public class PrefFrame extends JFrame {
private static final long serialVersionUID = 1L;
private JPanel jContentPane = null;
/**
* @param args
*/
public static void main(String[] args) {
// TODO 自動生成されたメソッド・スタブ
SwingUtilities.invokeLater(new Runnable() {
public void run() {
PrefFrame thisClass = new PrefFrame();
thisClass.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
thisClass.setVisible(true);
}
});
}
/**
* This is the default constructor
*/
public PrefFrame() {
super();
initialize();
}
/**
* This method initializes this
*
* @return void
*/
private void initialize() {
this.setSize(300, 200);
this.setContentPane(getJContentPane());
this.setTitle("JFrame");
}
/**
* This method initializes jContentPane
*
* @return javax.swing.JPanel
*/
private JPanel getJContentPane() {
if (jContentPane == null) {
jContentPane = new JPanel();
jContentPane.setLayout(new BorderLayout());
}
return jContentPane;
}
}
(1)パッケージを指定すると、フォルダの階層構造が自動的に変わります。
package pref;
(2)インポート文は自動的に追加することができます。
import javax.swing.SwingUtilities;
import java.awt.BorderLayout;
import javax.swing.JPanel;
import javax.swing.JFrame;
Javaエディタでは、インポート文やメソッドを折りたたむことができます。展開する場合は「+」マークをクリックします。
インポート文が展開して全て表示されました。
逆に「-」マークをクリックすると折りたたまれます。
(3)JFrame クラスを継承いていますので、スーパークラスのフィールドやメソッドを利用することができます。
public class PrefFrame extends JFrame {
省略
}
*スーパークラスは javax.swing.JFrame です。
(4)serialVersionUID について
private static final long serialVersionUID = 1L;
Eclipse3.1から Serializable インタフェースを実装したクラスで、serialVersionUID が宣言されていない場合に警告が表示されます。
JavaのAPI仕様で調べると、 JFrame クラスは Serializable インタフェースを実装していることがわかります。 JFrame クラスを継承したサブクラスも実装の対象となります。
シリアライズ可能なクラスでは、インスタンスをファイルに保存して、別のPCやVM環境でも復元できます。その時に serialVersionUID はインスタンスを区別するために使われます。
当面はEclipseが自動的に生成してくれる serialVersionUID をそのまま使ってください。シリアライズが必要になったときに意味を詳しく勉強すればいいと思います。
もし serialVersionUID を宣言しない場合、警告はそのままで問題ありません。気になるようでしたら、警告を表示しないようにもできます。
・方法1
@SuppressWarnings("serial") を加える
・方法2
Eclipseのメニューから ウィンドウ → 設定 を選択
Java → コンパイラー → エラー/警告 を選択
潜在的なプログラミングの問題 を選択
serialVersionUIDなしのシリアライズ可能クラス を「無視」にする。
*serialVersionUID や @SuppressWarnings("serial") は Javaエディタの左に表示される警告アイコンをクリックすると、自動的に追加するメニューが表示されます。
(5)jContentPane は複数のメソッドで参照しますので、フィールド変数として宣言しています。
private JPanel jContentPane = null;
(6)Javaアプリケーションでは最初にmainメソッドが呼び出されます。
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
PrefFrame thisClass = new PrefFrame();
thisClass.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
thisClass.setVisible(true);
}
});
}
・クラス自身をインスタンス化
・閉じるボタンを押した時の設定
・ウィンドウを可視にする
なぜ上記のようなプログラムになるかというと、Swingがシングルスレッド設計だからです。Swingではコンポーネントの状態に影響を与える処理は、イベントディスパッチスレッドという単一スレッドで実行することになっています。
そこで mainメソッド内で SwingUtilities クラスの invokeLater メソッドを呼び出し、イベントディスパッチスレッドに処理を実行させています。mainメソッドのスレッドが実行しているのではないところがポイントです。
Swingのコンポーネントが表示されたあと、イベント処理はイベントディスパッチスレッド上で実行されることになります。
(7)コンストラクタの部分です。
public PrefFrame() {
super();
initialize();
}
コンストラクタはインスタンスの生成時に必ず実行されます。スーパークラスのコンストラクタを呼び出した後、以下のinitialize()メソッドを呼び出しています。
(8)initialize()メソッドではウィンドウのサイズとタイトルを設定しています。そしてsetContentPane()メソッドの引数にgetJContentPane()を指定しています。thisはクラス自身を表すキーワードです。
private void initialize() {
this.setSize(300, 200);
this.setContentPane(getJContentPane());
this.setTitle("JFrame");
}
これまでは以下のようにコンテンツペインを取得していました。
Container cp = getContentPane();
しかし VisualEditor が自動生成するプログラムでは、getJContentPane()というメソッドを新しく定義し、その戻り値を使っています。
(9)getJContentPane()メソッドでは、jContentPane が null の場合に、コンテンツペインとして JPanel クラスのインスタンスを生成し、レイアウトマネージャにBorderLayoutを設定しています。そしてインスタンスを返してします。
private JPanel getJContentPane() {
if (jContentPane == null) {
jContentPane = new JPanel();
jContentPane.setLayout(new BorderLayout());
}
return jContentPane;
}
*VisualEditor では JPanel クラスのインスタンスをコンテンツペインとして利用しているところがポイントです。
このgetJContentPane()メソッドを中心にコンポーネントが追加されていきます。
【ワンポイント】
invokeLaterメソッドの引数には、Runnableインタフェースのrunメソッドを実装したクラスを指定する必要がありますが、簡単な方法として無名内部クラスを使っています。
無名内部クラスは以前にウィンドウを閉じる時の処理で解説しましたが、今回のmainメソッドの内部と比べると書き方が同じだということがわかります。
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
showExitDialog();
}
});
またデータベース接続のような時間のかかる処理は、イベントディスパッチスレッドとは別スレッドにして実行する必要があります。それにはSwingWorkerクラスを使います。SwingWorkerクラスを使った例はのちに説明します。