ダイアログボックスなどでは、ボタンやテキスト枠、ドロップダウンリストを使って、ユーザーの操作を受け付けるようになっています。こうした素材はJavaのシステムで用意されているので、それを決まりに従って利用するだけで、自分で作ったプログラムでボタンなどが使えます。今日はまず、これら「コンポーネント」と呼ばれるものをアプレットに配置してみましょう。
この章のプログラムを作成するためのプロジェクトを新たに用意します。そこにアプリケーションを追加します。プロジェクト名は、SwingGUIとします。アプリケーション名はUseComponentsとします。以下、ウィザードでのキータイプを伴うダイアログボックスを示しますが、手順はこれまでも何度も出てきているので、同じように作業をしてください。なお、ウインドウのタイトルは「設計機能で作ったウインドウ」にし、クラス名は「FrameByDesigner」にします。自分が手を加えるクラスはそのときの目的にあわせた名前にした方がいいでしょう。
Javaではプログラムを、1文字1文字タイプして入力していくのが基本ではあります。しかしながら、JBuilderには、プログラム作成をもっと簡単にしてくれる機能「ビジュアルデザイナ」があります。これを利用することで、ボタンやテキストボックスといったものを、最終的に実行したプログラムで画面で見える形式で、設定もできてしまいます。以下具体的に説明をしますが、ウインドウ内にボタンやテキストボックスをマウス操作で配置します。そうすると、そこで見えているのと同じ動作を行なうJavaのプログラムを自動的に生成するのです。そのため、単にボタンなどを配置するだけなら、プログラムは1行も書かなくてもできてしまうとも言えるのです。こうした機能を利用することで、効率的にプログラム作業ができてしまいます。
ボタンやテキストボックスなどのユーザーインタフェースのための部品は「コンポーネント」と総称されます。ウィンドウなどをはじめ、画面を構成するような素材もまとめてコンポーネントと呼んでいますが、一般にはコンポーネントはソフトウェアの部品のことを指します。さらに、こうした部品集的なものを、Javaでは「パッケージ」と呼んでいます。正確には、Javaの実行環境で用意されたクラスの集合がパッケージです。コンポーネントやウィンドウとして表示する機能などをまとめたパッケージとして、AWT(Abstract Windowing Toolkit)というものがあります。Javaのプログラムでは、必須のパッケージだと言ってよいでしょう。また、より高性能なユーザーインタフェースを作成するためのパッケージとしてSwingがあります。Swingを積極的に使うことにしましょう。
では、用意したプロジェクトで以下のように作業をして、ウインドウにコンポーネントを配置してみます。
1JBuilderのウインドウの右側では、ウインドウの中身を作成するプログラムが入ったソースファイルFrameByDesigner.javaのプログラム内容のテキストが見えているとします。(見えていない場合には、ウインドウ左側のFrameByDesigner.javaの項目をダブルクリックします。)
2右側のFrameByDesignerの表示部分の下端にある「設計」のタブをクリックします。右側の表示が変化します。パネルが出てきたり、上部にコンポーネントのアイコンが並んでいたり、さらに右側には設定項目などが出てきます。ここでは、グラフィックスソフトのような感覚で作業を行なうことができます。アイコンが並んでいる部分を「パレット」と呼ぶことにします。
3中央に大きく見える白いボックスが、ウインドウそのものを示しています。ここで、このボックスの周囲に黒い小さな四角形、すなわちハンドルが見えています。これは現在、このパネルが選択されていることを示しています。(もし、ハンドルが見えていない場合には、ボックスをクリックして選択して下さい。)また、左側の1つのペインにウインドウの中身を階層表示する部分があります。現在選択されているものがそちらのペインの項目としても選択されていることを確認してください。
4左側のペインで「ContentPane」を選択します。ボックスの表示が若干かわります。ContentPaneの意味については後で説明をします。右側のプロパティ表示されている部分にあるlayoutの項目に注目してください。ここでは、2列にリスト表示されていますが、左側が項目名(プロパティ名)、右側が設定値になっています。layoutのプロパティを「null」に設定します。設定値の部分がドロップダウンリストになっているので、そこから「null」を選択します。(このnullの意味は次の章で説明します。)
5「設計」ペインの上部にあるパレットにで、「Swing」のタブが選択されていることを確認し、「OK」の部分をクリックして選択します。この部分は、ボタンを配置するツールを意味します。
6「設計」ペインのウインドウを示すボックスの内部の適当な位置をドラッグします。
7ドラッグ範囲にボタンが新たに作成されました。ボタンの周囲にはハンドルが見えており、ボタンが選択されていることが分かります。また、左側の表示をみると、ContentPaneの下位項目としてボタンが作成されたことが示されています。
8右側のプロパティ表示領域には、選択されているボタンのプロパティ(属性ないしは設定と考えればよい)が表示されています。そこにあるtextプロパティの設定値を、ここでは「ボタン」に変更します。textと書かれた右側の領域をクリックして、「ボタン」とキータイプすればいいでしょう。
9ここでは設定値を反映させるために、いったん、ボタンの外部をクリックしました。(そうしなくてもすぐに反映されます。)そして、再度ボタンをクリックして選択したところです。textプロパティに設定した文字列が、ボタンの中に表示されるボタン名になることを確認してください。
10次は、チェックボックスのアイコン(図の中で選択しているもので、チップヒントには「javax.swing.JCheckBox」と表示されます)をクリックして選択して、ウインドウの表示領域をドラッグします。
11チェックボックスが作成されました。
12作成されたチェックボックスが選択している状態であることを確認し、右側でtextプロパティを「チェックボックス」に変更します。すると、チェックボックスの名前がウインドウの表示領域内でも変更されました。
13テキストボックスのアイコン(図の中でマウスポインタが指しているもので、チップヒントには「javax.swing.JTextArea」と表示されます)をクリックして選択します。
14ウインドウの表示領域をドラッグします。テキストの表示領域が作成されますが、これについては特にプロパティは変更しないでもいいでしょう。
15さらにドロップダウンリスト(コンボボックス)を作成します。パレットにあるアイコン(図の中でマウスポインタが指しているもので、チップヒントには「javax.swing.JComboBox」と表示されます)を選択します。
16ウインドウの表示領域内をドラッグして、コンポーネントを配置します。
17ドロップダウンリストが作成されました。
18ツールバーの「プロジェクト実行」のボタンをクリックします。すると、作成したプログラムが実行されます。実行結果は、「設計」の画面で設計した通りのものがほぼ再現されています。クリックしたり、チェックボックスが切り替わったり、あるいはテキストの入力ができたり、ドロップダウンリストの選択ができたりします。実際にプログラムとして動作する点を確認して下さい。
以上のように、ボタンやテキストボックスなどをドラッグして配置するだけで、その設計画面と同じ機能のウインドウが作成されて実行されています。プログラムを1行も記述していないことに注意してください。それでも、Javaのアプリケーションが作成できています。
JBuilderのウインドウの右側で「ソース」のタブをクリックして、実際に作られたJavaのプログラムを見てみましょう。一見すると分かりにくいですが、JButtonクラスのインスタンス変数jButton1などが新たに定義されているのが分かります。
package swinggui; import java.awt.*; import java.awt.event.*; import javax.swing.*; public class FrameByDesigner extends JFrame { private JPanel contentPane; private JButton jButton1 = new JButton(); private JCheckBox jCheckBox1 = new JCheckBox(); private JTextArea jTextArea1 = new JTextArea(); private JComboBox jComboBox1 = new JComboBox(); private FlowLayout flowLayout1 = new FlowLayout(); //フレームのビルド public FrameByDesigner() { enableEvents(AWTEvent.WINDOW_EVENT_MASK); try { jbInit(); } catch(Exception e) { e.printStackTrace(); } } //コンポーネントの初期化 private void jbInit() throws Exception { //setIconImage(Toolkit.getDefaultToolkit().createImage(FrameByDesigner.class.getResource("[アイコン]"))); contentPane = (JPanel) this.getContentPane(); jButton1.setText("ボタン"); contentPane.setLayout(flowLayout1); this.setSize(new Dimension(400, 300)); this.setTitle("設計機能で作ったウインドウ"); jCheckBox1.setText("チェックボックス"); jTextArea1.setText("jTextArea1"); contentPane.add(jButton1, null); contentPane.add(jCheckBox1, null); contentPane.add(jTextArea1, null); contentPane.add(jComboBox1, null); } //ウィンドウが閉じられたときに終了するようにオーバーライド protected void processWindowEvent(WindowEvent e) { super.processWindowEvent(e); if (e.getID() == WindowEvent.WINDOW_CLOSING) { System.exit(0); } } }
ビジュアルデザイナで作業することで、上記のようなプログラムが作成できました。自分でプログラムは1行もキータイプしていませんが、画面で見える通りに動作するプログラムができてしまいました。このプログラムは、ビジュアルデザイナが生成したものですが、操作で指定した通りにコンポーネントが画面に並ぶようなプログラムとなっています。このプログラムのポイントとなる部分を追っかけてみましょう。
Javaは単にプログラムとしてデータの処理ができるだけでなく、こうしたボタンやテキストボックスなどを利用できるようにしてくれています。もちろん、アプリケーションそのものも最小限のプログラムで利用できるようになっています。こうしたさまざまな機能をサポートするソフトウエア部分は「ライブラリ」などと呼ばれています。Javaが標準で用意したライブラリに、ボタンなどを扱う機能があるというわけです。ライブラリは一般的な言い方で、Javaでは具体的にはパッケージと呼んでいます。そして、たとえばボタンは1つのクラスとしてパッケージの中で定義されています。それはソフトウエアを構成する部品の様に利用できるわけです。ボタンをいちいち自分で作るわけではなく、クラスとしてすでに用意されているボタンを使ってプログラムを作成するわけです。
ここで、Javaのパッケージの1つにAWT(Abstract Windowing Toolkit)というものがあります。これは、Javaの初期の頃から存在するパッケージで、ウインドウ表示やボタンなどの基本的な画面処理を行なう機能がまとまったライブラリです。現在のJavaもAWTが基礎になっています。
このAWTの機能をプログラムで使うときに、このパッケージを使うことをプログラムの最初に宣言しておく必要があります。それが以下の部分の記述です。
import java.awt.*;
たとえば、AWTの中でボタンはButtonというクラスで定義されていますが、パッケージ名を含んだ正式な名前は、java.awt.Buttonなのです。このようにプログラムに書いてもよいのですが、通常はButtonだけをプログラム中に書き、importステートメントで指定した名前で*をワイルドカードと解釈して、java.awtで始まるすべてのクラスを利用できるようになっています。
ただし、AWTは機能的には最低限のものだけだったのです。そこで、Java 1.1の時代に付加パッケージとして、Swingというものが作られました。Swingは、JFC(Java Foundation Components)というライブラリ群の1つですが、多彩なユーザインタフェースを構築できる点で華やかな存在であると言っていいでしょう。このSwingはJava2では標準ライブラリとなっています。
Swingを利用するには、やはりSwingのパッケージをプログラムで利用するということを宣言しなければなりません。それが、以下の部分に相当します。
import javax.swing.*;
AWTで使うユーザーインタフェースのためのコンポーネントとSwingのコンポーネントの一部を、表にまとめました。どのようなクラスがあるのかということがまず重要で、ボタンとしてのButtonや、複数行のテキストはTextAreaだというあたりを見てください。ちなみに、AWTはどちらかといえば必要最低限のコンポーネントに限られています。たとえば、タブやスライダー、HTMLテキスト編集など多彩な部品を使いたい場合には、Swingを使うことになるでしょう。
種類 | AWTでのクラス名 | Swingでのクラス名 |
---|---|---|
ボタン | Button | JButton |
JToggleButton | ||
チェックボックス | CheckBox | JCheckBox |
オプションボタン | CheckBox | JRadioButton |
オプションボタン管理 | CheckBoxGroup | ButtonGroup |
1行のテキストボックス | TextField | JTextField |
JPasswordField | ||
複数行のテキストボックス | TextArea | JTextArea |
JEditorPane | ||
文字列表示 | Label | JLabel |
JTextPanel | ||
ドロップダウンリスト | Choice | JComboBox |
選択リスト | List | JList |
テーブル | JTable | |
ツリー表示 | JTree | |
スクロールバー | Scrollbar | JScrollBar |
スライダ | JSlider | |
プログレスバー | JProgressBar |
ボタンを利用したいのであれば、SwingのパッケージにJButtonクラスが定義されているので、それを利用します。クラスは設計図であって、ボタンそのものではありません。そこで、ボタンを実際に使うときには、newキーワードを使ってJButtonクラスのインスタンスを生成しなければなりません。そのときに使われる特別なメソッドがコンストラクタなのですが、むしろ既に用意されているクラスを使う場合には、コンストラクタをどう使うかということが問題になるでしょう。
コンストラクタは、クラスの中では、ある種特別なメソッドのように定義されています。メソッド名はクラス名と同一であり、戻り値はそのクラスへの参照であることが明確なので記載しません。そして、引数を指定できますが、引数の取り方を複数種類用意しておくことができます。
いろいろな方法があるのですが、まずは「new JButton()」として、新たにJButtonクラスのインスタンスを作成します。そしてJButtonクラスのインスタンスへの参照を戻すので、一般にはこれを何かの変数に代入しておきます(その値を特に使わない場合には変数に代入しなくてもかまいません)。これにより、JButtonのコンストラクタの1つを呼び出しています。引数を取らないコンストラクタを呼び出しています。ただし、プログラムでは、インスタンス変数の定義とJButtonのインスタンス生成は同時に行なわれているので、
JButton jButton1 = new JButton();
となっています。これで、FrameByDesignerクラス内では、jButton1という変数が、生成したJButtonのインスタンスを参照することになります。なお、インスタンス変数の確保は、オブジェクトがインスタンス化されたときに行なわれ、それへの代入プロセスも、インスタンス化した段階で行なわれます。つまり、アプレットが実行された最初の段階で、すでにJButtonのインスタンスもどこかに作られて利用可能になると考えればよいでしょう。
そして、JButtonクラスには、ボタン名を設定するメソッドとして、setTextが用意されています。setTextの引数に指定した文字列を、ボタン名にします。この処理は、jbInitメソッドにあります。以下の部分です。これで、jButton1変数が参照するJButtonクラスのインスタンスに対して、「ボタン」という名前を割り当てます。
jButton1.setText("ボタン");
jbInitメソッドは、FrameByDesignerクラスのコンストラクタから呼び出されています。すなわち、ウインドウを最初に表示しようとしたときにこの部分が呼び出されることになります。
ここで、ビジュアルデザイナではtextプロパティで設定したことを思い出して下さい。考え方としては、JButtonにはtextというプロパティがあって、それがボタン名になるというのが内部的な仕様です。ビジュアルデザイナではそうした内部状態を、参照や変更しやすいように組み立てられた機能なのです。しかしながら、プログラム上ではプロパティを直接いじるということは避けます。そのため、プロパティの値を設定する「set<プロパティ名>」という名前のメソッドを定義し、それを利用するということを行ないます。また、プロパティの値を取り出すのもメソッドが用意されていて、それは「get<プロパティ名>」という命名規則になっています。
いずれにしても、こうしたボタンやテキストボックスが、前に示したような非常に簡単なプログラムで作成できます。ボタンはコンストラクタで生成をして、必要に応じてメソッドを利用するだけで使えるようになるというわけです。これは、ソフトウェアの部品がJavaの実行環境で用意されていて、それを利用しているのだというイメージを思い浮かべてください。
JButtonには、Stringクラスの引数を1つだけ指定するコンストラクタも用意されています。これを利用すると、インスタンスを生成すると同時に、ボタン名を生成します。たとえば、インスタンス変数の定義の部分を次のように変更し、jbInitのsetTextメソッドのステートメントをコメントの中に入れることでもかまいません。
JButton jButton1 = new JButton("ボタン");
AWTやSwingには限らないことですが、クラスからインスタンスを生成するためのポイントは次の通りです。
ウインドウに配置したコンポーネントは自由な位置に配置することができるようになっています。実は必ずしもそうではないのですが、ここでは分かりやすいようにその方法が取れるように設定しました。アプレットのlayoutプロパティをnullにするというのがポイントです。
この状態の時、コンポーネントの位置を設定してやらないといけません。その位置情報は、ボタンなどどのコンポーネントも共通にboundsプロパティで管理しています(ただし、boundsプロパティはビジュアルデザイナのプロパティ表示部分では設定できません。コンポーネントそのものをドラッグするなどして設定されます)。プログラムでsetBoundsメソッドを使うことで、任意の位置や大きさに設定することができます。ここでのボタンは、jbInitメソッドにある以下のステートメントで設定されています。
jButton1.setBounds(new Rectangle(29, 25, 101, 31));
boundsプロパティは、Rectangleクラスで記述されますが、4つの引数を取ったコンストラクタでRectangleクラスのデータは生成できます。こうしたいくつかの処理をまとめて書くのは最初は分かりにくいのですが、慣れるとかえってこうした書き方の方がいいと思うようになるものです。
ここでは、ボタンの左上の座標値が (x, y) = (29, 25) の位置であり、幅が101、高さが31であるといった設定がなされます。
こうした数値で場所を設定するというのは、実用面では実はいろいろ問題が出ることがあります。たとえば、文字列のコンポーネントで数値で幅をぎりぎりに指定したとします。しかしながら、実行環境によってはフォントが違うので、もしかすると、文字ははみだすかもしれません。そこで、一般には、なりゆきでうまくコンポーネントが配置されるという手法を取ります。これは別のところで説明をしましょう。
こうしてインスタンス化し、必要なプロパティを設定したコンポーネントをアプレットに組み込む必要があります。これまでの部分では、確かにボタンというものを管理するオブジェクトを生成はしていますが、それは「パソコン内のどこか」にあるに過ぎないわけです。それをアプレットの表示領域に組み込む必要があるのです。言い換えれば、そうした組み込み作業はプログラムでは明示してやらないといけないわけです。
そのための処理は、以下のような記述を行ないます。ボタンに関わる部分だけを抜き出します。
contentPane = (JPanel) this.getContentPane(); contentPane.setLayout(null); contentPane.add(jButton1, null);
まず、getContentPaneというメソッドで、実際の描画領域を取り出すと思って下さい。これを「ContentPane」と呼びますが、特に日本語に翻訳したりはしないので、そのまま英語で記述することにしましょう。取り出したクラスの詳細はここではあまり気にしないで、「ウインドウの中でコンポーネントを受け入れるものとして」抽象的に理解してください。JPanel型として定義された変数contentPaneがあって、その変数から「描画領域」を参照できるということです。そして、その描画領域に対して、addメソッドを利用することで、その描画領域にコンポーネントを組み込みます。組み込むコンポーネントは1つ目の引数に指定をします。2つ目の引数はlayoutがnullの場合は、nullでかまいません。
ウインドウには、「チェックボックス」というチェックボックスがありますが、これも、ボタンの場合と同じように追って行ってください。ダイジェストして抜き出すと次の通りです。
チェックボックスはJCheckBoxというクラスで利用できるようになっていますが、インスタンス変数としてjCheckBox1を定義し、同時にコンストラクタを呼び出してインスタンス化し、生成したオブジェクトへの参照をjCheckBox1変数に代入しています。
チェックボックスの名前を設定するのは、setTextメソッドを使います。これはボタンと共通です。また、チェックボックスの位置やサイズを指定するのにsetBoundsメソッドを使います。これもやはりボタンと同様です。
こうして必要な設定を行なったチェックボックスはウインドウに組み込むためにContentPaneに対してaddメソッドで追加を行います。概して、ボタンもチェックボックスも、基本的な手順は同じだと言えるでしょう。
テキストボックスについても、以下のようにプログラムをダイジェストしてみました。もう説明の必要はないと思います。ボタンやチェックボックスと、この範囲内の事ではまったく同じになっています。
JTextAreaやJTextFieldでは、getTextメソッドを利用することで、アプレットに表示されたテキストボックスに入力されている文字列を、プログラム上で取り出すことができます。getTextメソッドは引数は必要ありません。
一覧から選択して使うコンポーネントとして、リストやコンボボックスがあります。今日のサンプルプログラムでも、さっそくコンボボックスを作っています。コンボボックスを配置するだけなら、ツールバーを使って簡単に行えます。また、生成されたプログラムのダイジェストは以下の通りです。
つまり、JComboBoxでインスタンスを生成して、変数に記録しておきます。そして、setBoundsで位置や大きさを指定し、addメソッドでウインドウの表示領域を設定しているだけです。ここでは、setTextはありません。コンボボックスにはtextプロパティがないのです。
だけども、こうやって表示されたコンボボックスは、特に何も選択肢が用意されていません。いくつかの選択肢をたとえば文字列などで与えると、それらしいプルダウンメニューが出てくるのですが、その方法を説明しておきましょう。
JComboBoxには、addItemというメソッドが用意されています。このメソッドの引数に指定した文字列がプルダウンメニューに登録されます。複数の項目をプルダウンメニューに入れたい場合には、何度かこのメソッドを使いますが、addItemで設定した順にプルダウンメニューでは一覧されます。
以下のプログラムを、jbInitメソッドの途中に入れます。図を参考にして、場所を御覧ください。
jComboBox1.addItem("りんご"); jComboBox1.addItem("みかん"); jComboBox1.addItem("なし");
ツールバーの「プログラムの実行」ボタンをクリックすると、プログラムが実行されます。今度は、コンボボックス部分の▼マークをクリックすると、プルダウンメニューが出てきます。プログラムで指定した文字が出てくることを確認してください。
JComboBoxでは、選択した項目を取り出すのに、getSelectedItem()というメソッドを利用することができます。また、何番目の項目を選択したかを取り出すのに、getSelectedIndex()というメソッドを利用できます。いずれも、引数は指定しなくてもかまいません。
9-1:JComboBoxコンポーネントに、「日本」「アメリカ」「イギリス」「ドイツ」の4つの選択項目が出るようにする。そして、最初は「イギリス」が選択されているようにする。(ヒント、setSelectedItem("項目名") メソッドを使う)
9-2:JTextAreaコンポーネントに、「ここに文字を入力」という文字が、アプレットを起動したら最初から表示されているようにすること。(ヒント:setTextメソッドを使う、あるいはプロパティの設定をやってみる?)
ところでメソッドはどう調べるか? 講義のトップページにあるリンク集からの見方を説明しましょう。