グラフィカルユーザインターフェース

グラフィカルユーザインターフェース (1)

これまでに扱ってきたプログラムは、大まかに言うと「コンソールに文字列を入力」して、「コンソールに文字列を表示」するだけのプログラムであった。このように、コンソールに文字の入出力でユーザとプログラムが対話する仕組みのことをキャラクタユーザインターフェース (CUI) と呼ぶ。

それに対して、グラフィカルユーザインタフェース (GUI) とは、絵やアイコンを仲立ちとして、ユーザとプログラムが対話する仕組みのことである。一般的に、GUI は GUI コンポーネント (部品) を使って構築される。GUI コンポーネントは、ユーザがマウスやキーボードを通してやり取りする視覚オブジェクトを指す。

現在、一般的なコンピュータユーザが扱うアプリケーションのほとんどは、この GUI という仕組みで作られており、操作のほとんどをマウスで行うものが多い。今回は、そのようなアプリケーションを開発するための足がかりとして、Java で GUI を扱うための基本的なコンポーネント、およびそれらの扱い方を紹介する。

Java で GUI を扱うための機構はいくつか存在するが、本講義では Swing と呼ばれる「実行環境 (Windows や Linux などのOS) に依存しない GUI のためのクラスライブラリ」を用いる。他にも Abstract Window Toolkit (AWT) と呼ばれるクラスライブラリも存在するが、現在の主流から外れてしまうためここでは扱わない。ただし、Swing は AWT の技術の上に成り立っているため、AWT で用意されているクラスライブラリのいくつかは知っておく必要がある。

ウィンドウを表示する

Java で GUI アプリケーションを作成する場合、ウィンドウ (フレーム) と呼ばれるものを作成し、その上に機能を持つ コンポーネント を貼り付けていく方法が楽である。

Java でウィンドウを表示するには、javax.swing.JFrame というクラスを使用するとよい。

package j2.lesson10.example;

import javax.swing.JFrame;

public class FrameViewer {

    public static void main(String[] args) {
        // ウィンドウを表すインスタンスを作る (引数はタイトル)
        JFrame frame = new JFrame("フレームのテスト");
        
        // 終了ボタンが押されたときの動作を決める (ウィンドウを処分する)
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        
        // ウィンドウの大きさを決める (400x300)
        frame.setSize(400, 300);
        
        // ウィンドウを表示する
        frame.setVisible(true);
    }
}

コメントにもあるように、まず「new JFrame("ウィンドウのタイトル")」と javax.swing.JFrame のコンストラクタを引数にタイトルを指定して呼び出す。その後、作成したインスタンスに対して setDefaultCloseOperation メソッドを呼び出して「プログラムの終了ボタン (Windows ならばウィンドウ右上の×ボタン)」を押した際の処理を設定している。

上記の処理だけでは「ウィンドウ」を表すオブジェクトが Java の実行環境の中に作成されただけである。これをディスプレイ上に表示させるには、「setSize(width, height)」でウィンドウサイズを決定後、「setVisible(true)」を呼び出せばよい。

上記のプログラムを実行すると、次のようにウィンドウが表示される。


このプログラムは「フレームのテスト」とタイトルに書かれたウィンドウが表示されるのみで、ウィンドウの右上「×」キーをクリックするとウィンドウが閉じられ、プログラムが終了する。

ラベル (テキスト) を貼り付ける

最も単純なコンポーネント (GUI 部品) として、テキストを表示する「ラベル」をウィンドウに貼り付ける。

ラベルを表すコンポーネントとして、Java には javax.swing.JLabel というクラスがある。このクラスのインスタンスをウィンドウに貼り付けることによって、ウィンドウに文字列を表示させることができる。

package j2.lesson10.example;

import javax.swing.JFrame;
import javax.swing.JLabel;

public class HelloSwing {

    public static void main(String[] args) {
        JFrame frame = new JFrame("文字表示のテスト");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setSize(400, 300);
        
        // ウィンドウの ContentPane にラベルを追加する
        JLabel label = new JLabel("Hello, world!");
        frame.getContentPane().add(label);
        
        // ウィンドウを表示する
        frame.setVisible(true);
    }
}

上記のプログラムを実行すると、以下のように表示される。


JFrame クラスを用いてウィンドウを生成し、表示する部分は同様であるが、表示する直前に次のような2行が追加されている。

// ウィンドウの ContentPane にラベルを追加する
JLabel label = new JLabel("Hello, world!");
frame.getContentPane().add(label);

一般的に、ウィンドウは「タイトルバー」「ウィンドウ境界」「クライアントエリア」から成り、そのうちプログラムを書く側が操作する部分はクライアントエリアである。


「ウィンドウにラベルを追加する」といっても、ウィンドウそのものにラベルを貼り付けるのではなく、クライアントエリア (Swing では Content Pane と呼ばれる) にラベルを貼り付ける。JFrame クラスを用いて作成したウィンドウのクライアントエリアを取得するには JFrame.getContentPane() というメソッドを呼び出せばよい。

JFrame.getContentPane() によって取得できるオブジェクトは java.awt.Container と呼ばれる 他のコンポーネントを貼り付けるための領域 である。この Container には add というメソッドが用意されていて、このメソッドの引数に GUI コンポーネントを渡すことによって、ウィンドウのクライアントエリアに様々なコンポーネントを貼り付けることができる。

今回の例では、JLabel というテキストを表示できるラベルをクライアントエリアに貼り付けることにより、文字列をウィンドウに表示している。このクラスは、インスタンスを生成する際に、コンストラクタ呼び出しの引数に表示させたい文字列を指定する。


この例では、文字列が左に寄ってしまっている。この文字列をウィンドウ中央に配置させたい場合、JLabel クラスのインスタンスメソッド setHorizontalAlignment に対し、JLabel クラスのクラスフィールド CENTER を引数に与えて呼び出してやればよい (他にも JLabel.LEFT, JLabel.RIGHT がある)。

package j2.lesson10.example;

import javax.swing.JFrame;
import javax.swing.JLabel;

public class CenteringHelloSwing {

    public static void main(String[] args) {
        JFrame frame = new JFrame("文字表示のテスト (2)");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setSize(400, 300);
        
        // ウィンドウの ContentPane にラベルを追加する
        JLabel label = new JLabel("Hello, world!");

        // - 文字を表示する位置を CENTER に設定する
        label.setHorizontalAlignment(JLabel.CENTER);
        frame.getContentPane().add(label);
        
        // ウィンドウを表示する
        frame.setVisible(true);
    }
}

画像を貼り付ける

javax.swing.JLabel には、文字列だけでなく画像を貼り付けることもできる。画像を貼り付けるには、javax.swing.ImageIcon というクラスを用いて表示したい画像をオブジェクト化し、このオブジェクトを JLabel のコンストラクタの引数として渡せばよい。

例えば、U:\duke.gif というファイルに、Java のマスコットキャラ「Duke」の画像が格納されていた場合、この画像を表示するには次のようなプログラムを書けばよい。

package j2.lesson10.example;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class ImageLabel {

    public static void main(String[] args) {
        JFrame frame = new JFrame("画像表示のテスト");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setSize(400, 300);
        
        // 画像を取り込んでアイコンにする
        ImageIcon icon = new ImageIcon("U:/duke.gif");
        
        // アイコンを表示するラベルを作成する
        JLabel label = new JLabel(icon);
        
        // ウィンドウの ContentPane にラベルを追加する
        frame.getContentPane().add(label);
        
        // ウィンドウを表示する
        frame.setVisible(true);
    }
}

ImageIcon クラスの使い方は簡単で、取り込みたい画像のファイル名をコンストラクタの引数に渡すだけである。上記のプログラムを実行すると、次のようなウィンドウが表示される。


JLabel のコンストラクタに引数としてアイコンを渡すと、そのアイコンはラベルの中央に配置される。左詰めや右詰めで表示したい場合、setHorizontalAlignment メソッドを使って設定すればよい。

labelLeft.setHorizontalAlignment(JLabel.LEFT);
labelRight.setHorizontalAlignment(JLabel.RIGHT);

ボタンを貼り付ける

javax.swing.JLabel は文字や画像を表示するだけの GUI コンポーネントであるが、javax.swing.JButton という GUI コンポーネントを使用すると、ウィンドウにボタンを貼り付けることができる。

package j2.lesson10.example;

import javax.swing.JButton;
import javax.swing.JFrame;

public class ButtonViewer {

    public static void main(String[] args) {
        JFrame frame = new JFrame("ボタン表示のテスト");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setSize(400, 300);
        
        // ウィンドウの ContentPane にボタンを追加する
        JButton button = new JButton("click");
        frame.getContentPane().add(button);
        
        // ウィンドウを表示する
        frame.setVisible(true);
    }
}

JButton の作成の仕方は JLabel とほとんど同じで、コンストラクタに表示する文字列を引数として渡すだけである。

上記のプログラムを実行すると、クライアントエリア上に大きなボタンが一つだけ貼り付けられる。


このボタン上にマウスカーソルを合わせ、マウスの左ボタンを押すと色が変わる。


ボタンはラベルと違い、標準でボタンの中央に文字列が表示される。この表示位置を変える場合には、JLabel の際と同様に setHorizontalAlignment メソッドを呼び出せばよい。

// ボタン上にある文字列の表示を左詰めに設定
button.setHorizontalAlignment(JButton.LEFT);

ボタンにアクションを設定する

GUI コンポーネントとしてのボタンの役割は、通常「押されたときに何らかのアクションを起こす」というものである。しかし、先ほどの例ではボタンを押してもあまり意味はない。

このボタンにアクションを持たせる方法はいくつか存在するが、その中でも比較的理解しやすい javax.swing.AbstractAction を用いた方法を紹介する。

AbstractAction とは、ボタンなど操作された際に何らかのアクションを起こすべきコンポーネントのアクションを記述するための骨格である。このクラスはアクションの骨格が実装されている抽象クラスで、actionPerformed(java.awt.event.ActionEvent) という抽象メソッドを持つ。このメソッドをオーバーライドすることにより、ボタンが押された際の動作を記述することができる (ボタンが押された際にこのメソッドが呼び出される)。

package j2.lesson10.example;

import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;

public class HelloAction extends AbstractAction {

    // 親クラス (AbstractAction) のコンストラクタに
    // アクションの名前 (String name) を渡すためのコンストラクタ
    public HelloAction(String name) {
        super(name);
    }

    // ボタンが押された際の処理を
    // actionPerformed(java.awt.event.ActionEvent) に記述する
    public void actionPerformed(ActionEvent e) {
        // ボタンが押された際に "Hello, world!" とコンソールに表示する
        System.out.println("Hello, world!");
    }
}

上記は、簡単なアクションの例として「ボタンが押された際に、"Hello, world!" とコンソールに表示する」ということを記述したクラス HelloAction である。

AbstractAction にはコンストラクタがいくつか用意されているが、そのうちアクションの名前を String 型で受け取るコンストラクタを子クラスに用意し、コンストラクタの最初の命令「super(name);」によって AbstractAction クラスのコンストラクタにこのアクションの名前を受け渡している。

次に、このアクションをボタンに関連付ける。下記のように、HelloAction のインスタンスを生成し、JButton のコンストラクタの引数に渡せばよい。

package j2.lesson10.example;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class HelloButton {

    public static void main(String[] args) {
        JFrame frame = new JFrame("アクション付きボタンのテスト");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setSize(400, 300);
        
        // HelloAction のインスタンス (アクションの実態) を作成
        // コンストラクタにはボタンに表示する文字列を置く
        HelloAction action = new HelloAction("click->hello");

        // ボタンを作成する際にアクションを渡す
        JButton button = new JButton(action);
        frame.getContentPane().add(button);
        
        // ウィンドウを表示する
        frame.setVisible(true);
    }
}

上記のプログラムを実行すると、次のようなウィンドウが表示される。


HelloAction のコンストラクタに渡した文字列がボタンに表示されている。

このボタンにマウスカーソルを合わせ、左クリックすると次のようにコンソール画面に表示される。

Hello, world!

この表示はボタンがクリックされるごとに行われるため、クリックされた回数だけ「Hello, world!」と表示される。

他にも GUI コンポーネントのアクションを記述する方法はいくつかあるが、詳しくは次回以降の講義で紹介することにする。

LayoutManager

ウィンドウのクライアントエリア (JFrame.getContentPane()) に GUI コンポーネントを配置すると、クライアントエリアを覆いつくす大きなコンポーネントが一つだけ貼り付けられる。

クライアントエリアに2つ以上のコンポーネントを貼り付けるには、それらのコンポーネントがどのように配置されるのか、細かな指定が必要になる。例えば、上下に並べたり、左右に並べたり、など様々なケースが考えられる。

このようにクライアントエリアの割付をすることをレイアウトと呼び、Java では java.awt.LayoutManager というレイアウトを管理するためのインターフェースを実装したクラスを使うことによって、複数のコンポーネントの配置を指定することができる。

他のコンポーネントを貼り付けるための領域を表す java.awt.Container は、add メソッドを呼び出すことによりその領域にコンポーネントを貼り付けることができた。このクラスには setLayout(java.awt.LayoutManager) というメソッドが用意されており、このメソッドの引数にレイアウトを管理する LayoutManager のインスタンスを渡すことにより、add メソッドでコンポーネントを貼り付けた際の割付を行うことができる。

東西南北に配置する

java.awt.LayoutManager を実装したクラスに、java.awt.BorderLayout というものがある。このレイアウトを使用すると、画面の上下左右、および中央にそれぞれコンポーネントを配置することができる。


上記のようなウィンドウを表示するプログラムは、次の通りである。

package j2.lesson10.example;

import java.awt.BorderLayout;

import javax.swing.JButton;
import javax.swing.JFrame;

public class DirectionViewer {

    public static void main(String[] args) {
        JFrame frame = new JFrame("BorderLayout のテスト");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setSize(400, 300);
        
        // LayoutManager を BorderLayout にする
        frame.getContentPane().setLayout(new BorderLayout());
        
        // add メソッド呼び出し時に、配置する位置も引数として渡す
        frame.getContentPane().add(new JButton("北"), BorderLayout.NORTH);
        frame.getContentPane().add(new JButton("南"), BorderLayout.SOUTH);
        frame.getContentPane().add(new JButton("東"), BorderLayout.EAST);
        frame.getContentPane().add(new JButton("西"), BorderLayout.WEST);
        frame.getContentPane().add(new JButton("中央"), BorderLayout.CENTER);
        
        // ウィンドウを表示する
        frame.setVisible(true);
    }
}

このプログラムでは、ウィンドウを表すオブジェクトを生成後、そのウィンドウのクライアントエリア (Content Pane) のレイアウトを設定している。

// LayoutManager を BorderLayout にする
frame.getContentPane().setLayout(new BorderLayout());

その後、クライアントエリアにボタンを追加しているが、add メソッドの第2引数に配置する位置を表す定数を指定している

// add メソッド呼び出し時に、配置する位置も引数として渡す
frame.getContentPane().add(new JButton("北"), BorderLayout.NORTH);
frame.getContentPane().add(new JButton("南"), BorderLayout.SOUTH);
frame.getContentPane().add(new JButton("東"), BorderLayout.EAST);
frame.getContentPane().add(new JButton("西"), BorderLayout.WEST);
frame.getContentPane().add(new JButton("中央"), BorderLayout.CENTER);

BorderLayout で指定できる位置は、以下の5つである。CENTER はコンテナの中央、NORTH はコンテナの上部を表し、SOUTH, EAST, WEST はそれぞれコンテナ上部を北とした際のそれぞれの方向を表している。

先ほどのプログラムの実行結果を確認しても、正しくそれぞれの方向にボタンが配置されていることが確認できる。


BorderLayout では、クライアントエリアを5分割してコンポーネントを配置できるが、必ず5分割しなければならないわけではない。下記のように、中央と下部にだけコンポーネントを配置することもできる。

package j2.lesson10.example;

import java.awt.BorderLayout;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class BorderViewer {
    
    public static void main(String[] args) {
        JFrame frame = new JFrame("レイアウトのテスト");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setSize(400, 300);
        
        // レイアウトを java.awt.BorderLayout に設定
        frame.getContentPane().setLayout(new BorderLayout());
        
        // 中央 (ウィンドウ中央) にラベルを表示
        frame.getContentPane().add(new JLabel("中央のラベル"), BorderLayout.CENTER);
        
        // 南 (ウィンドウ下部) にボタンを表示
        frame.getContentPane().add(new JButton("南のボタン"), BorderLayout.SOUTH);
        
        // ウィンドウを表示する
        frame.setVisible(true);
    }
}

BorderLayout を用いてコンポーネントを配置する場合、BorderLayout.CENTER さえ配置しておけば他は何も指定しなくてもよい。その場合、指定しなかった領域は CENTER に配置したコンポーネントが埋めてくれる。

上記の例では、CENTER と SOUTH にコンポーネントを配置した。下記のようなウィンドウが表示される。


格子状に配置する

java.awt.LayoutManager の例としては、他には java.awt.GridLayout というクラスが挙げられる。このグリッドというのは「マス目」という意味を持ち、その名の通りクライアントエリアを縦横に分割し、各マス目にコンポーネントを配置することができる。


上記のウィンドウでは、クライアント領域を6分割 (3行2列) して、それぞれの領域に 1..6 の数値が書かれたボタンを配置している。次のように GridLayout を指定することでできる。

package j2.lesson10.example;

import java.awt.GridLayout;

import javax.swing.JButton;
import javax.swing.JFrame;

public class GridViewer {

    public static void main(String[] args) {
        JFrame frame = new JFrame("GridLayout のテスト");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setSize(400, 300);
        
        // レイアウトを java.awt.GridLayout に設定
        // -> new GridLayout(行数=3, 列数=2)
        frame.getContentPane().setLayout(new GridLayout(3, 2));
        
        // ウィンドウにボタンを 6 個追加する
        frame.getContentPane().add(new JButton("1"));
        frame.getContentPane().add(new JButton("2"));
        frame.getContentPane().add(new JButton("3"));
        frame.getContentPane().add(new JButton("4"));
        frame.getContentPane().add(new JButton("5"));
        frame.getContentPane().add(new JButton("6"));
        
        // ウィンドウを表示する
        frame.setVisible(true);
    }
}

GridLayout を使用する場合、コンポーネントの追加時の add には配置する場所を指定できない。標準では最初に add をした際には分割された領域の一番左上に配置され、次にその右、一番右まで配置されたらその下の段の一番左…といった感じで配置されていく。

複雑なレイアウトを作る

java.awt.LayoutManager を実装するクラスは他にも多数ある。例を挙げると、以下のようなものがある。

上記のような LayoutManager を使用すれば様々なレイアウトを作成することができるが、多数覚えるのは大変であるしいくつかのレイアウト、例えば GridBagLayout などは複雑で使いにくい (細かい設定ができるので便利ではある)。

Swing の GUI コンポーネントの中には、javax.swing.JPanel という他の GUI コンポーネントを貼り付けるための汎用 GUI コンポーネントが存在する。

JPanel はコンテナである。そのため、レイアウトを設定して他の GUI コンポーネントを JPanel 上に貼り付けることができる。そして、JPanel は同時に GUI コンポーネントとして扱うことができるため、いくつかのコンポーネントが貼り付けられたパネルを他のコンテナに貼り付けることができる

この機能を使うと、BorderLayout の各領域の中をさらに GridLayout で分割したり、GridLayout で作成されたマス目を BorderLayout でさらに分割することなどができる。例を挙げると、次のようなレイアウトを持つウィンドウを作成することができる。


上記ウィンドウのクライアントエリアは、次のように分割されている。


「中央-左のボタン」「中央-右のボタン」は JPanel 上に貼り付けられていて、その JPanel のインスタンスはクライアントエリア (Content Pane) の BorderLayout.CENTER で指定される位置に貼り付けられている。これによって、BorderLayout で分割された領域の一部をさらに GridLayout で分割している。

上記のようなウィンドウを表示するプログラムは以下の通りである。

package j2.lesson10.example;

import java.awt.BorderLayout;
import java.awt.GridLayout;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class CenterGrid {
    
    public static void main(String[] args) {
        JFrame frame = new JFrame("複雑なレイアウトのテスト");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setSize(400, 300);
        
        // ContentPane のレイアウトを java.awt.BorderLayout に設定
        frame.getContentPane().setLayout(new BorderLayout());
        
        // 南 (ウィンドウ下部) にボタンを表示
        frame.getContentPane().add(new JButton("南のボタン"), BorderLayout.SOUTH);
        
        // 中央 (ウィンドウ中央) に貼り付けるパネル
        JPanel centerPanel = new JPanel();
        
        // パネルを GridLayout(行数=1, 列数=2) に設定
        centerPanel.setLayout(new GridLayout(1, 2));
        
        // パネルにボタンを二つ追加
        centerPanel.add(new JButton("中央-左のボタン"));
        centerPanel.add(new JButton("中央-右のボタン"));
        
        // 中央 (ウィンドウ中央) にボタンが二つ貼りついたパネルを表示
        frame.getContentPane().add(centerPanel, BorderLayout.CENTER);
        
        // ウィンドウを表示する
        frame.setVisible(true);
    }
}

下記の部分で JPanel のインスタンスを作成し、そこにボタンを二つ貼り付けている。

// 中央 (ウィンドウ中央) に貼り付けるパネル
JPanel centerPanel = new JPanel();

// パネルを GridLayout(行数=1, 列数=2) に設定
centerPanel.setLayout(new GridLayout(1, 2));

// パネルにボタンを二つ追加
centerPanel.add(new JButton("中央-左のボタン"));
centerPanel.add(new JButton("中央-右のボタン"));

そして、2つのボタンが貼り付けられたパネルをクライアントエリアに貼り付けている。

// 中央 (ウィンドウ中央) にボタンが二つ張り付いたパネルを表示
frame.getContentPane().add(centerPanel, BorderLayout.CENTER);

コンポーネントとコンテナ

Java で GUI を作成する場合、重要な概念となるのが「コンポーネント」と「コンテナ」である。コンポーネントは GUI の部品のことで、コンテナはコンポーネントを包括する (貼り付ける) ための領域である。

コンポーネントを表すクラスとして、java.awt.Component というものがある。全ての GUI コンポーネントは、このクラスを継承している。

また、コンテナを表すクラスとして java.awt.Container というものがある。このクラスには add(java.awt.Component) というメソッドが用意されており、このメソッドの引数にコンポーネントを指定することによってこのコンテナにコンポーネントを貼り付けることができる。

クラスの継承関係を見てみると、java.awt.Container の親クラスに java.awt.Component クラスが存在する。つまり、コンテナの機能を持つものは、それ自身がコンポーネントとしても扱えるという意味を持つ。

上記のコンポーネントとコンテナは、Swing の基盤技術である AWT のクラスである。Swing では、javax.swing.JComponent というクラスが全てのコンポーネント (JLabel, JButton, JPanel など) の親クラスに存在する。JComponent クラスは Component クラスと Container クラスを親に持つため、コンポーネントでありコンテナでもある。ただし、JLabel や JButton などは純粋なコンポーネントであり、コンテナの機能を持たないため add メソッドなどのコンテナ特有のメソッドは呼び出しても期待通りに動作しない。

テキストフィールドを貼り付ける

最後に、GUI コンポーネントの例として javax.swing.JTextField クラスを紹介する。このクラスは「一行のテキストを入力できるコンポーネント」を表す。

javax.swing.JTextField クラスは javax.swing.JComponent を親クラスに持つため、JLabel や JButton 同様にウィンドウのクライアント領域に貼り付けることができる。

package j2.lesson10.example;

import java.awt.BorderLayout;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;

public class TextFieldViewer {

    public static void main(String[] args) {
        JFrame frame = new JFrame("テキストフィールド");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        
        // レイアウトを java.awt.BorderLayout に設定
        frame.getContentPane().setLayout(new BorderLayout());
        
        // 中央 (ウィンドウ中央) にテキストフィールドを表示
        frame.getContentPane().add(new JTextField("テキストフィールド"), BorderLayout.CENTER);
        
        // 東 (ウィンドウ右部) にボタンを表示
        frame.getContentPane().add(new JButton("ボタン"), BorderLayout.EAST);
        
        // pack() メソッドは、サイズを自動的に調整してくれる
        frame.pack();
        frame.setVisible(true);
    }
}

上記の

// 中央 (ウィンドウ中央) にテキストフィールドを表示
frame.getContentPane().add(new JTextField("テキストフィールド"), BorderLayout.CENTER);

では、テキストフィールドを作成してクライアントエリアに貼り付けている。コンストラクタに設定した文字列が、テキストフィールドにあらかじめ表示される文字列となる。

また、最後のほうにある

// pack() メソッドは、サイズを自動的に調整してくれる
frame.pack();
frame.setVisible(true);

では、JFrame.pack() メソッドによりウィンドウのサイズを自動的に調整し、表示している。


「テキストフィールド」と書かれた部分は、マウスでクリック後にキーボードで文字列を打ち込めば編集できる。

上記のプログラムでは、テキストフィールドは「文字列を書き込むことができるだけ」のコンポーネントになってしまっている。ボタンにアクションを設定することにより、このテキストフィールドを操作するようなプログラムを考える。

まず、ボタンに設定するアクションを作成する。下図のように、「ボタンが押されたら、テキストフィールドの内容をラベルに貼り付ける」というようなアクションにする。


上図のアクションを実現するクラスを作成する。アクションを作成するには、javax.swing.AbstractAction クラスを継承すると便利であるため、それを利用する。

package j2.lesson10.example;

import java.awt.event.ActionEvent;

import javax.swing.AbstractAction;
import javax.swing.JLabel;
import javax.swing.JTextField;

public class TextFieldAction extends AbstractAction {

    private final JTextField textField;
    private final JLabel label;
    
    public TextFieldAction(String name, JTextField field, JLabel label) {
        super(name);
        this.textField = field;
        this.label = label;
    }

    // ボタンが押されたらテキストフィールドの内容をラベルに貼り付ける
    public void actionPerformed(ActionEvent e) {
        // テキストフィールドからラベルへ
        String text = this.textField.getText();
        this.label.setText(text);
        
        // テキストフィールドの内容を変更する
        this.textField.setText("clicked");
    }
}

AbstractAction を継承したクラスのインスタンスをボタンに渡すと、そのボタンが押された際に actionPerformed(ActionEvent) メソッドが呼び出される。アクションを記述する場合にはこのメソッド内に記述すればよい。

JTextField には、getText() メソッドと setText(String) メソッドが用意されている。前者はテキストフィールドに表示されている (入力された) 文字列を取得するためのメソッドで、後者はテキストフィールドに文字列を設定するためのメソッドである (JLabel にも同様のメソッドが用意されている)。

このアクションを利用したプログラムの例を考える。このプログラムに必要なコンポーネントは、次の3つである。

これらを使った例として、次のようなプログラムが書ける。

package j2.lesson10.example;

import java.awt.BorderLayout;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class EchoLabel {

    public static void main(String[] args) {
        JFrame frame = new JFrame("ラベルの操作");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        
        // レイアウトを java.awt.BorderLayout に設定
        frame.getContentPane().setLayout(new BorderLayout());
        
        // テキストフィールドを作成
        JTextField tf = new JTextField("テキストフィールド");
        
        // ラベルを作成
        JLabel label = new JLabel("ラベル");
        
        // ボタンを作成。ただし、アクションに TextFieldAction を設定する
        JButton button = new JButton(new TextFieldAction("ボタン", tf, label));

        // テキストフィールドとボタンを貼り付けたパネルを作成
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());
        panel.add(tf, BorderLayout.CENTER);
        panel.add(button, BorderLayout.EAST);
        
        // 中央 (ウィンドウ中央) にラベルを表示
        frame.getContentPane().add(label, BorderLayout.CENTER);
        
        // 南 (ウィンドウ下部) にボタンを表示
        frame.getContentPane().add(panel, BorderLayout.SOUTH);
        
        // ウィンドウを表示する
        frame.pack();
        frame.setVisible(true);
    }
}

今回の知識だけで次のようなプログラムが書けた。このプログラムを実行すると、下図のようなウィンドウが表示される。


テキストフィールドに "ほげ" と入力してボタンを押すと、次のようになる。