教育サーバーのページ
オンラインテキスト目次
ソフトウエア基礎演習

模範解答

GUIアプリケーション (Swing)

SwingはAWTの後継として1997年にリリースされた。 基本的な部分はAWTの機能を踏襲して作成されているが、 GUI部品の外見を実行時に変更できたり、多機能などの利点がある。

SwingのGUI部品には、以下のような特徴がある。

100% ピュアJavaである
Swingは全部Javaで記述されている。 それゆえに、クロスプラットホームを実現していると言える。 従来のAWTのGUI部品を使って書いたJavaプログラムは、 動作としてはどのOS上でも同じであったが、 「見かけ(ルック&フィール)」はOSごとにそれぞれ異なっていた。 SwingのGUI部品を使えば,動作だけでなく、 見かけも含めて統一可能である。

実行時にルック&フィールを切り替え可能である
ルック&フィールを統一できるだけではなく、 複数のルック&フィールを用意しておいて、 実行時に切り替えることができる。 この機能は「着脱可能な」(Pluggable)ルック&フィールと呼ばれる。
きめ細かい設定やカスタマイズが可能
AWTのGUI部品では、ボタンなどにはテキストしか表示できないが、 Swingではテキスト以外にも、比較的簡単に画像ファイルを貼り付けたり、 自分でグラフィックスを描画したりできる。 また、クラスライブラリは、 こうした柔軟な処理を体系的に行なえるような構成になっている。

以下、Swingを使ったGUIプログラミングについて解説するが、 SwingはAWTの全ての機能を置き変えたものではなく、 多くはAWTの機能をそのまま利用する。 このため、Swingを使うにはAWTを使う知識も必要になる。

JFrameクラスを使ってGUIアプリケーションを作成する

SwingによりGUIアプリケーションを作成する場合、 ボタンやラベル、メニューなどのGUI部品を自由に組み合わせる。 そのために、GUI部品を入れるための「器」を用意することが必要となり、 これをコンテナとよぶ。

Swingによりアプリケーションを作成する場合には、 土台となるコンテナには、JFrameクラスを利用することが一般的である。 JFrameは、Swingパッケージに含まれるクラスの一つであり、 アプリケーションのウィンドウを作るために利用されるクラスである。

JFrameクラスを使ったGUIアプリケーション作成の流れは以下のようになる。

  1. javax.swingパッケージのimport
  2. フレームクラスのインスタンスの作成
  3. コンテントペイン(中間コンテナ)の取得
  4. レイアウト方式の指定
  5. GUI部品(コンポーネント)のインスタンス(オブジェクト)の生成
  6. 生成されたGUI部品(コンポーネント)オブジェクトの配置
  7. 表示

1. 普通に終了できる機能をもたないウィンドウを表示するプログラムの説明

次のプログラム MyWinApp.java はフレームというウィンドウをベースとした普通のウィンドウを表示するプログラムである。 このプログラムを実行することで表示されるウィンドウは、 見た目は普通のウィンドウであるので、 その右上の終了ボタンで終了できそうだが、 実際には終了することはできない。 これを終了するためには、 Ctrl+Cなどで強制終了させる必要がある。

import java.awt.*;
import javax.swing.*;

public class MyWinApp {
    public static void main(String[] args) {
       JFrame f = new JFrame();
       f.setSize(300, 200);
       f.setVisible(true);
    }
}

実行例は、たとえば次のようになる。

% java MyWinApp
...
....
ウィンドウシステムを強制終了させる場合には、コマンドプロンプトウィンドウ上でCtrl+Cを入力する。

プログラムの説明

プログラム前半の

JFrame f = new JFrame();

では、新しいフレーム(基本的なウィンドウ(JFrame))オブジェクトを作成している。

f.setSize(300, 200);

では、ウィンドウの横幅を300、高さを200に設定している。

f.setVisible(true);

は、ウィンドウの表示命令を示している。

2. 普通に終了できる機能をもつウィンドウを表示するプログラムの説明

次のプログラム MyWinApp1.java はフレームというウィンドウをベースとした普通のウィンドウを表示するプログラムである。 このプログラムを実行することで表示されるウィンドウは、 その右上にある終了ボタンで終了できる。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

class MyFrame extends JFrame {
    public MyFrame() {
       setSize(300, 200);
       addWindowListener(new MyWindowAdapter());
    }
}


class MyWindowAdapter extends WindowAdapter {
    public void windowClosing(WindowEvent e) {
       System.exit(0);
    }
}

public class MyWinApp1 {
    public static void main(String[] args) {
       MyFrame f = new MyFrame();
       f.setVisible(true);
    }
}

ウィンドウのクローズボタンをクリックすることで、 ウィンドウシステムを正常に終了させることができる

プログラムの説明

プログラム前半の

class MyFrame extends JFrame

では、新しいフレームクラスMyFrameをJFrameクラスを継承して定義している。

addWindowListner(new MyWindowAdapter());

では、イベントソースであるウィンドウシステムとイベントリスナであるMyWindowAdapterとを関連付けている。 これによって、WindowEventを受け取るイベントリスナを指定している。 つまり、イベントソースであるウィンドウのクローズボタンをクリックしたときには、 ウィンドウクローズを通知するイベントがイベントリスナに伝えられる。 アプリケーションはそのイベントリスナで定義されているメソッド windowClosing(WindowEvent e)を起動し、終了処理を行う。

class MyWindowAdapter extends WindowAdapter

では、イベントリスナーである MyWindowAdapterクラスはWindowAdapterクラスを継承して作成されている。

public void windowClosing(WindowEvent e){
       System.exit(0);} 

では、プログラムを正常終了するための処理が記述されている。

3. タイトルをもつウィンドウを表示するプログラムの説明

次のプログラム MyWinApp1n.java は、上記のMyWinApp1n.javaに対してさらに、 タイトルを表示できるようにしたプログラムである。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

class MyFrame extends JFrame {
    public MyFrame() {
       setTitle("My Window Application");
       setSize(300, 200);
       addWindowListener(new MyWindowAdapter());
    }
}

class MyWindowAdapter extends WindowAdapter {
    public void windowClosing(WindowEvent e) {
       System.exit(0);
    }
}

public class MyWinApp1n {
    public static void main(String[] args) {
       MyFrame f = new MyFrame();
       f.setVisible(true);
    }
}
プログラムの説明

プログラム前半の

setTitle("My Window Application");

では、フレームにタイトルを表示している。

4. 1つのボタンが配置されたウィンドウを表示するプログラムの説明

GUI部品の組み込み

GUIアプリケーションの構築では、アプリケーションの土台となる「入れ物」 (コンテナ)の中に必要なGUI部品を組み込んでいく。

通常、コンテナとなるGUI部品には他のGUI部品を組み込むことができるが、 今回利用したJFrameクラス(JDialog, Jwindow, JAppletも)では、 コンテナに直接GUI部品を組み込むことはできない。 ここでは、GUI部品の追加は、 コンテナから取得したcontentPaneに対しておこなう。

GUIアプリケーションを作成する際に、 重要なことはGUI部品をコンテナ上にうまくレイアウト(配置)して、 使いやすいユーザインターフェイスとすることが必要である。 Swingを利用したGUIアプリケーションでは、 GUI部品を配置する場合、レイアウトマネージャを使用する。

次のプログラム MyButtonTest.java は、 GUIでよく使われるコンポーネントであるボタンが配置されたウィンドウを表示できるようにしたプログラムである。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

class MyFrame extends JFrame {
    JButton b1;
    public MyFrame(){
       Container contentPane = getContentPane();
       setTitle("My Button Application");
       setSize(300, 200);
       contentPane.setLayout(new FlowLayout());
       b1 = new JButton("Button1");
       contentPane.add(b1);
       addWindowListener(new MyWindowAdapter());
    }
}

class MyWindowAdapter extends WindowAdapter {
    public void windowClosing(WindowEvent e) {
       System.exit(0);
    }
}

public class MyButtonTest {
    public static void main(String[] args) {
       MyFrame f = new MyFrame();
//       f.show();
       f.setVisible(true);
    }
}
プログラムの説明

プログラム前半の

Container contentPane = getContentPane();

では、JFrameオブジェクトからコンテントペインと呼ばれるコンテナを取得することを示す。

プログラム前半の

content.Pane.setLayout(new FlowLayout());

では、FlowLayoutレイアウトマネージャのインスタンスを生成し、 作成したレイアウトのインスタンスをコンテナにセットすることで、 左から右方向にボタンを配置することを示す。

b1 = new JButton("Button1");

では、"Button1"というラベルのボタンオブジェクトを生成することを示す。

contentPane.add(b1);

では、生成されたボタンオブジェクトをコンテナオブジェクトに追加することを示す。

5. 複数のボタンが配置されたウィンドウを表示するプログラムの説明

次のプログラム MyButtonTest1s.java は、 GUIでよく使われるコンポーネントであるボタンが配置されたウィンドウを表示できるようにしたプログラムである。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

class MyFrame extends JFrame {
    JButton b1, b2, b3;
    public MyFrame(){
       Container contentPane = getContentPane();
       setTitle("My Button Application");
       setSize(300, 200);
       contentPane.setLayout(new FlowLayout());
       b1 = new JButton("Button1");
       contentPane.add(b1);
       b2 = new JButton("Button2");
       contentPane.add(b2);
       b3 = new JButton("Button3");
       contentPane.add(b3);
       addWindowListener(new MyWindowAdapter());
    }
}

class MyWindowAdapter extends WindowAdapter {
    public void windowClosing(WindowEvent e) {
       System.exit(0);
    }
}

public class MyButtonTest1s {
    public static void main(String[] args) {
       MyFrame f = new MyFrame();
//       f.show();
       f.setVisible(true);
    }
}
プログラムの説明
b1 = new JButton("Button1");
b2 = new JButton("Button2");
b3 = new JButton("Button3");

では、"Button1"、"Button2"、"Button3"という3つのラベルのボタンオブジェクトを生成することを示す。

contentPane.add(b1);
contentPane.add(b2);
contentPane.add(b3);

では、生成された3つのボタンオブジェクトをコンテナオブジェクトに追加することを示す。

6. イベントに対応したボタンを伴うウィンドウを表示するプログラムの説明

Swingにおいてイベントの扱いは、AWTと同様である。 イベントソースでイベントが発生するとあらかじめ登録しておいた イベントリスナーに定義されているメソッドを実行する。

イベント処理を実装する場合には、以下のような手続きを実行することになる。

  1. イベントソースで発生したイベントオブジェクトを、 どのイベントリスナーで処理するかを定義する
  2. イベントリスナーでどのような処理をおこなうかを定義する
  3. イベントソースへのイベントリスナーを登録する

次のプログラム MyButtonTest2n.java は、ボタンが押されたことに対してイベント処理を施したプログラムである。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

class ButtonTestFrame extends JFrame implements ActionListener {
    JButton b1, b2, b3;
    public ButtonTestFrame() {
       Container contentPane = getContentPane();
       setTitle("My Button Application");
       setSize(300, 200);
       addWindowListener(new MyWindowAdapter());
       contentPane.setLayout(new FlowLayout());

       b1 = new JButton("Button1");
       b2 = new JButton("Button2");
       b3 = new JButton("Button3");

       b1.addActionListener(this);
       b2.addActionListener(this);
       b3.addActionListener(this);

       contentPane.add(b1);
       contentPane.add(b2);
       contentPane.add(b3);

    }

    public void actionPerformed(ActionEvent ae){
       if (ae.getSource() == b1) 
          System.out.println("Button1がクリックされました");
       else if (ae.getSource() == b2)
          System.out.println("Button2がクリックされました");
       else if (ae.getSource() == b3)
          System.out.println("Button3がクリックされました");
    }

}

class MyWindowAdapter extends WindowAdapter {
    public void windowClosing(WindowEvent e) {
       System.exit(0);
    }
}

public class MyButtonTest2n {
    public static void main(String[] args) {
       ButtonTestFrame f = new ButtonTestFrame();
//       f.show();
       f.setVisible(true);
    }
}
プログラムの説明

このプログラムのイベント処理では、 イベントソースであるJButtonクラスから発生したイベントを、 イベントリスナであるButtonTestFrameクラスとMyWindowAdapterクラスに伝達することで処理がおこなわれる。

 class ButtonTestFrame extends JFrame implements ActionListner 

では、ボタンが押されたというイベントを受け付け、 それに対する処理を実行するために、 ButtonTestFrameクラスがActionListnerインタフェースを実装していることを表す。

public void actionPerformed(ActionEvent ae){ 
       if (ae.getSource() == b1) 
          System.out.println("Button1がクリックされました");
       else if (ae.getSource() == b2)
          System.out.println("Button2がクリックされました");
       else if (ae.getSource() == b3)
          System.out.println("Button3がクリックされました");
    }

は、ActionListnerインタフェースにおいて実装されねばならないメソッドであり、 ボタンが押された際に実行される処理が記述されている。 この場合には、ボタンが押された場合には、"Button がクリックされました" という文字列が標準出力に表示されことを示している。 actionPerformed()メソッドの引数aeにはボタンがクリックされたイベント情報が入っている。 このオブジェクトaeはボタンがクリックされてときに生成される。 getSource()メソッドはイベントソースを見つけるために利用する。

       b1.addActionListener(this);
       b2.addActionListener(this);
       b3.addActionListener(this);

では、ボタンに対してイベントリスナーを登録している。 これによって、ボタンをクリックされたことにより発生するイベントを感知してactionPerformed()メソッドを呼び出すことができるようになる。

 class MyWindowAdapter extends WindowAdapter {
    public void windowClosing(WindowEvent e) {
       System.exit(0);
    }
}

では、リスナーインターフェイスを実装しないで、 WindowAdapterを継承したMyWindowAdapterを定義している。

その他のコンポーネント

AWTで説明したテキストフィールド、チェックボックスなどのコンポーネントは、 SwingではAWTのクラス名の先頭にJを付けたクラス名で用意されている。 以下の表を見よ。

種類AWTのクラス名Swingのクラス名備考
フレームFrameJFrame
アプレットAppletJApplet
ボタンButtonJButton
ラベルLabelJLabel
テキストフィールドTextFieldJTextField
チェックボックスCheckboxJCheckBoxJCheckBoxとBが大文字になっていることに注意!
ラジオボタンCheckbox,
CheckboxGroup
JRadioButton,
ButtonGroup
大幅に異なる(下記参照)
テキストエリアTextAreaJTextArea

ただし、ラジオボタンだけは異なっている。以下の SwingRadioButtonTest.javaは、 Swingでラジオボタンを実現する例である。

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class MyFrame extends JFrame implements ActionListener {
    JButton b1;
    ButtonGroup g;
    JRadioButton rb1, rb2, rb3;
    public MyFrame() {
	Container contentPane = getContentPane();
        setSize(300,200);
        addWindowListener(new MyWindowAdapter());
        contentPane.setLayout(new FlowLayout());
	g = new ButtonGroup();
	rb1 = new JRadioButton("1", false);
	g.add(rb1);
	contentPane.add(rb1);
	rb2 = new JRadioButton("2", false);
	g.add(rb2);
	contentPane.add(rb2);
	rb3 = new JRadioButton("3", false);
	g.add(rb3);
	contentPane.add(rb3);
	b1 = new JButton("Push");
	contentPane.add(b1);
	b1.addActionListener(this);
    }
    public void actionPerformed(ActionEvent ae) {
	// JRadioButtonの現在の値を標準出力に表示する
	System.out.println("radiobutton1 is " + rb1.isSelected());
	System.out.println("radiobutton2 is " + rb2.isSelected());
	System.out.println("radiobutton3 is " + rb3.isSelected());
    }
}
class MyWindowAdapter extends WindowAdapter {
    public void windowClosing(WindowEvent e) {
       System.exit(0);
    }
}
public class MySwingRadioButtonTest {
    public static void main(String[] args) {
	MyFrame f = new MyFrame();
	f.setVisible(true);
    }
}

AWTでは、Checkboxクラスを使用したが、Swingでは JRadioButtonを使う。 また、いくつかのラジオボタンをまとめるには、ButtonGroupを使う。 ラジオボタンをまとめる時は、ButtonGroupオブジェクトに対しaddメソッドを 使いラジオボタンを追加する。また、ラジオボタンが選択されているかどうかを 調べるメソッドはAWTでは getStateだったが、SwingではisSelectedとなる。 これは、チェックボックス(JCheckBox)でも同様である。

課題6-1

上のプログラム MyWinApp1.java を書いて実行してみよ。さらに、ウィンドウサイズを480 x 300に変えて実行してみよ。

課題6-2

上のプログラム MyButtonTest.java を書いて実行してみよ。さらに、GUI部品であるボタンの名前を「ボタン」に変えて実行してみよ。

課題6-3

上のプログラム MyButtonTest1s.java を書いて実行してみよ。さらに、GUI部品である4つのボタンを2X2の格子上に配置して表示してみよ。この場合には、setLayout(new FlowLayout());の代わりにsetLayout(new GridLayout(2,2));を使うこと。

課題6-4

上のプログラム MyButtonTest.java をボタンを押すと、ボタンに書かれた文字が"Pressed"に変わるように プログラムを修正せよ。ボタンに書かれた文字を変更するメソッドは、 API仕様などで調べよ。

課題6-5

Swingのルック&フィールの特徴を確認するために、上のプログラム MyButtonTest1s.java(Swing版)と、 AWTの説明にあった、MyButtonTest1.java(AWT版)をそれぞれ、 WindowsとLinux上で実行せよ。そして、違いを説明せよ。

課題6-6

AWTのテキストフィールドを使う例であるMyTextFieldTest.java をSwingを使うように書き変えよ。

課題6-7

AWTのチェックボックスを使う例であるMyCheckboxTest.java をSwingを使うように書き変えよ。

課題6-8

AWTのテキストエリアを使う例であるMyTextAreaTest.java をSwingを使うように書き変えよ。


ソフトウエア基礎演習
nagai@rsch.tuis.ac.jp (Based upon mizutani@rsch.tuis.ac.jp's style sheet)
ohmi@rsch.tuis.ac.jp (加筆修正: 2004年5月24日〜2004年5月26日)