GUIのプログラミング (1)


GUIプログラムの種類

Javaでは標準APIを使って GUI (Graphical User Interface) プログラムを開発することができる。
初期からある AWT (Abstract Window Toolkit) を用いるものと、Java2 (Java 1.2以降) になって導入された Swing を用いるものがある。

JDK 1.1 以前の Java では Swing は標準として組み込まれておらず、AWT が主に使用されていた。しかし AWT は多くのGUI部品 (ボタン、ラベル等) についてプラットフォーム (コンピュータ、OS 等) で用意されたものを使用しており、

「動作するプラットフォームによってGUI部品の見栄えや細かい動作が異なる」  とか
「利用できるGUI部品の種類が少なく、アプリケーションとして十分な機能を満足できない」

といった問題があった。

それらの問題に対処すべく

「極力プラットフォームに依存しない」
「Javaで記述された軽量 (lightweight) な部品を使った」
「高機能な」

GUIパッケージである Swing が導入された。

それ以降、パソコンのデスクトップ用の Java によるGUIアプリケーションの多くは Swing を利用して作られてきた。
ただし、Swing は独立したGUIパッケージではなく、多くの基本的機能 (基本的なグラフィクスや低レベルなイベント処理など) は AWT のものを利用する形で作られている。そのため Swing の部品を使ったGUIプログラムを作成する場合にも AWT の基本部分を利用していることに注意する。

一頃の Java では、JavaFX という新しいGUIライブラリでリッチインターネットアプリケーション (RIA) を作るのが推奨されていた。JavaFX は Java SE 7 Update 2 (2011年) から開発キット JDK に組み込まれていたが、Java 11 (2018年) で JDK からはずされ、標準でなくオプションという位置づけで、以降は OpenJFX を利用することになった。ここでは、JavaFX および OpenJFX は、普及度が低いこともあり、触れないこととする。

また、SWT (Standard Widget Toolkit) という OS の GUI を直接使うライブラリもあり、Eclipseなどで利用されている。 しかしこれは標準APIではなく、また (Windows, Linuxなどメジャーなプラットフォームでは動作するものの) ライブラリ自体には機種依存性があるため、ここでは触れない。

また、Androidマシンも言語上は Java で書かれたプログラムが動作するが、GUI部分はパソコンデスクトップ用 Java SE とは全く互換がないので、別の勉強をする必要がある。ただし、イベントドリブンの考え方等は似ている部分も多いので、Swingの勉強も無駄にはならない。

以下、この授業では、パソコンデスクトップ用 Java SE の Swing を使ったGUIプログラムについてのみ言及する。


GUI部品一覧

部品内容AWTSwing
ラベル文字列の表示LabelJLabel
テキストフィールド文字列の1行入力TextFieldJTextField
パスワードフィールド文字列の1行入力。入力文字が記号で表示される-JPasswordField
テキストエリア複数行テキストの入力TextAreaJTextArea
ボタンコマンドボタンButtonJButton
トグルボタンチェック/非チェック、on/off などのトグル-JToggleButton
ラジオボタンチェック/非チェック、on/off などのトグル-JRadioButton
チェックボックスチェック/非チェック、on/off などのトグルCheckboxJCheckBox
チェックボックスグループチェックボックスの排他制御
CheckboxGroup
(Objectのサブクラス)
-
(ButtonGroup を使う)
ボタングループボタン選択の排他制御-
ButtonGroup
(Objectのサブクラス)
選択項目選択用Choice
-
(JComboBox, JList を使う)
コンボボックステキストフィールドとドロップダウンリストの組み合せ-JComboBox
スクロールバースクロール位置指定などに使われるバーScrollbarJScrollBar
スライダノブをスライドさせ値を設定できる部品-JSlider
スピナ値を調整できる小さい上矢印・下矢印ボタンつきのテキスト入力用部品-JSpinner
リスト項目一覧の表示・選択用ListJList
テーブル表形式の表示・編集-JTable
ツリーツリー構造の表示・編集-JTree
キャンバス描画エリアになる矩形領域Canvas
-
(一般にはJPanelを使う)
パネルコンテナになる矩形領域
Panel
(Containerのサブクラス)
JPanel
スクロールペインスクロールできる矩形領域。コンテナになる
ScrollPane
(Containerのサブクラス)
JScrollPane
コンポーネント一般的なGUI部品
Component
(抽象クラス)
(AWTの多くのGUI部品のスーパークラス)
(Objectのサブクラス)
JComponent
(抽象クラス)
(SwingのGUI部品のスーパークラス)
(Containerのサブクラス)
コンテナ一般的なGUI部品のコンテナ
Container
(Componentのサブクラス)
-
(AWTの Container を使う)
BoxコンテナBoxLayoutのコンテナ-Box
ウィンドウ(タイトル・ボーダーのない)ウィンドウ
Window
(Containerのサブクラス)
JWindow
(Windowのサブクラス)
フレームタイトル・ボーダーつきのウィンドウ
Frame
(Windowのサブクラス)
JFrame
(Frameのサブクラス)
ダイアログダイアログウィンドウ
Dialog
(Windowのサブクラス)
JDialog
(Dialogのサブクラス)
アプレットアプレット
Applet
(Panelのサブクラス)
JApplet
(Appletのサブクラス)

※ 一般に、AWT のGUI部品は java.awt パッケージのクラスに、Swing のGUI部品は javax.swing パッケージのクラスになる。
ただし、Applet は java.applet.Applet であるのに対し、そのサブクラスである JApplet は javax.swing.JApplet となっている。

一般に、AWT用のGUI部品とSwing用のGUI部品を混ぜて使うことは推奨されていない。プログラム作成時にどちらを使うかをはっきり決めて、一方のGUI部品だけを使うようにする。(ただし、コンテナはAWTの Container が共通で使われる。)
アプレットを開発していて 古い Microsoft の JVM 上で確実に動作させる必要がある場合 (古いWindowsマシンを対象とするときなど) は AWT を使わなければならないが、それ以外は高機能な Swing を使うほうがよい。
現在では AWT のGUI部品を使ったプログラムを作る必要性はないので、専ら Swing のGUI部品を使って画面を構築する。

以下では、Swing を使った GUI プログラムの開発を学習する。


イベントクラスの概要 (AWT, Swing 共通)

一般にGUIアプリケーションはマウスクリックやキーの押下などイベントによって動作が決められる イベント駆動型 (event-driven) のプログラムになる。
AWT および Swing で利用されるイベントを表すクラスは java.awt.event パッケージにある。

AWT および Swing で利用されるイベントには、

の二種類がある。セマンティックイベントはGUI部品が(一般的には複数の)低レベルイベントを消費し処理した結果発生する「より高次な」イベントである。

以下に主要なイベントクラスを挙げる。


主要なイベントクラスの説明
セマンティックイベント
クラス内容
ActionEventコンポーネント定義のアクションが発生したことを示すボタンがクリックされた。テキスト入力でEnterキーが押された。等
AdjustmentEventAdjustable インタフェースを実装した部品が発行する調整イベントスクロールバーの位置が変更された。等
ItemEvent項目が選択または選択解除されたことを示すチェックボックスがチェックされた・チェックをはずされた。等
低レベルイベント
クラス内容
ContainerEventコンテナの内容が変更されたことを示すコンポーネントが追加された・削除された。
KeyEventキーボード関係のイベントが発生したことを示すキーがタイプされた。キーが押された・離された。
MouseEventマウス関係のイベントが発生したことを示すマウスボタンがクリックされた。マウスボタンが押された・離された。マウスカーソルが入ってきた・出ていった。マウスがドラッグされた・移動した。
WindowEventウィンドウ関係のイベントが発生したことを示すウィンドウがオープン・クローズ・アイコン化・非アイコン化・アクティブ化・非アクティブ化・フォーカス化・非フォーカス化・状態変更された。

イベントが発生すると、登録されたイベントリスナ (event listener) インタフェース のしかるべきメソッド (イベントハンドラメソッド) が呼び出される。
イベントリスナは java.awt.event パッケージに定義されているが、以下に主要なものを挙げる。


主要なイベントリスナの説明
インタフェースイベント呼び出されるイベントハンドラメソッド
(public void)
ActionListenerアクションの発生actionPerformed(ActionEvent e)
AdjustmentListener調整イベントの発生adjustmentValueChanged(AdjustmentEvent e)
ItemListener項目が選択または選択解除されたitemStateChanged(ItemEvent e)
ContainerListenerコンテナにコンポーネントが追加されたcomponentAdded(ContainerEvent e)
コンテナからコンポーネントが削除されたcomponentRemoved(ContainerEvent e)
KeyListenerキーがタイプされたkeyTyped(KeyEvent e)
キーが押されたkeyPressed(KeyEvent e)
キーが離されたkeyReleased(KeyEvent e)
MouseListener部品上でマウスボタンがクリックされたmouseClicked(MouseEvent e)
部品上でマウスボタンが押されたmousePressed(MouseEvent e)
部品上でマウスボタンが離されたmouseReleased(MouseEvent e)
部品上にマウスカーソルが入ってきたmouseEntered(MouseEvent e)
部品上からマウスカーソルが出ていったmouseExited(MouseEvent e)
MouseMotionListener部品上でマウスがボタンを押されたままドラッグされたされたmouseDragged(MouseEvent e)
部品上でマウスがボタンが押されない状態で移動したmouseMoved(MouseEvent e)
WindowListenerウィンドウがオープンされた (最初に可視になった)windowOpened(WindowEvent e)
ウィンドウが閉じられようとしている (閉じる前)windowClosing(WindowEvent e)
ウィンドウが閉じられたwindowClosed(WindowEvent e)
ウィンドウがアイコン化されたwindowIconified(WindowEvent e)
ウィンドウがアイコン化状態から通常の状態に変更されたwindowDeiconified(WindowEvent e)
ウィンドウがアクティブ化されたwindowActivated(WindowEvent e)
ウィンドウがアクティブでなくなったwindowDeactivated(WindowEvent e)
WindowFocusListenerウィンドウがフォーカスされたwindowGainedFocus(WindowEvent e)
ウィンドウがフォーカスされた状態でなくなったwindowLostFocus(WindowEvent e)
WindowStateListenerウィンドウがアイコン化や最大化などで状態変更されたwindowStateChanged(WindowEvent e)

※なお、JSlider, JSpinner, JTable, JTree など Swing で導入された部品には、javax.swing.event パッケージで新しく導入されたイベントやリスナが利用される。本講義では全部には触れないので興味のある人は各自調べてみるとよい。


今回の演習課題で利用するイベント-イベントリスナ-イベントハンドラは、

イベントイベントリスナイベントハンドラ
ActionEventActionListeneractionPerformed
ItemEventItemListeneritemStateChanged

だけである。


統合開発環境 (IDE) によるVisualプログラミング

Java のプログラム開発では

テキストファイルエディタでソースファイルを編集し、
Oracle の開発ツールである JDK を使って
     コンパイル
     実行

という古くからあるスタイルもあるが、開発の現場では 統合開発環境 (Integrated Development Environment: IDE と略記される) を利用することが多い。

Javaプログラム開発の分野で人気があり、ずっと使われてきた IDE は以下の二つである。

これらは、実際の開発現場で、Webアプリケーションなど専門的で複雑なソフトウェア開発に利用されている。

講義では、講義で使用している演習室PCにインストールされている

All-in-one Eclipse

から起動できる Eclispe を使用して学習していく。
遠隔講義期間または各自のPCで演習を行いたい場合は、各自の責任で、myFITドキュメントにある説明などを参考にして各自のPCに Eclipse をインストールし、さらに自分で調べて、Eclipse に Swingデザイナー を導入して使用する。

統合開発環境はどれも似たような手順で操作を行えるので、今回の学習が NetBeans など他環境での開発においても生かされると思う。


GUIプログラムの画面をGUI操作で設計して作ることを Visualプログラミング という。一般には Visual Basic が普及し有名になった。
Eclipse でもプラグインである Swing デザイナー (Swing Designer) を使ってGUI操作による画面設計が可能である。

プロジェクトを開き、該当するソースファイルを開いた状態では、ソースファイルの表示窓の下部にある「ソース」タブが選択されている。この部分で「デザイン」タブを選択するとGUI設計のためのデザイナが起動する。

デザイナでは、あたかもDraw系の作画ツールのように、GUI部品を画面に貼り付けていくことにより設計できる。
設計用画面にGUI部品を貼り付け、プロパティを設定し、また、必要ならばイベント処理のプログラムコード (イベントハンドラ) を記述する。

イベントはボタンをクリックしたり、テキストフィールドでEnterキーを押したときなどに発生する。その際、登録してあるイベントリスナにあるイベントハンドラメソッドが自動的に呼び出される。

Eclipseでデザイナを使った場合、GUI部品の生成やイベントリスナの登録コードはコンストラクタの中に自動的に出力され、イベントは

無名クラスの中のイベントハンドラ

によって処理される仕組みになっている。無名クラスは特殊な内部クラスで、外側のクラスのインスタンスに結びついているため、外側のインスタンス変数にもアクセスできる。


グラフィクスの基本

グラフィクスの表示は、抽象クラス Graphics (java.awt.Graphics) のメソッドを呼んで行なう。

Swing のGUI部品に対して独自のグラフィクスを表示させるには、それぞれの部品クラスを継承したクラスを定義し、その中で

protected void paintComponent( Graphics g )

で表される、表示を担当するメソッド paintComponent をオーバーライドする。
paintComponent に 描画・表示対象となる Graphics クラスのオブジェクトがパラメータ (上の場合 g ) として渡されるので、この g に対して各種メソッドを呼び出して働きかければよい。

※ Graphics は抽象クラスなので、実際にはそのサブクラスのインスタンスが渡されている。

例えば

g.setColor( new Color(150, 50, 200) );

g.drawLine( 20, 10, 120, 60 );

などのように、変数に . を付けてメソッドを呼び出す形で使う。


色は クラス Color (java.awt.Color) のオブジェクトで指定する。
※ Color は厳密には java.awt.Color クラスなので、

import java.awt.Color;

として Color という単純名で使用する。importしていないときは完全限定名で指定する必要がある。

描画色の指定
(Graphicsのメソッド)
setColor( Color c )
名前による色の指定
Color.RED   Color.YELLOW   Color.DARK_GRAY など。
Color.red   Color.yellow   Color.darkGray など小文字指定もある。
RGBによる色の指定
new Color(r, g, b)
r (赤), g (緑), b (青) の強さを 0 ~ 255 の範囲の整数で指定
new Color(r, g, b)
r (赤), g (緑), b (青) の強さを 0.0F ~ 1.0F の範囲のfloat型浮動小数点数で指定


Javaに限ることではないが、コンピュータの2D画面はピクセル単位のデジタル画面であり、座標はX方向のピクセル座標とY方向のピクセル座標の組で指定する。
一般に、X方向は左端が 0 で、右に行くに従い1ずつ大きくなる。一方、Y方向は上端が 0 で下に行くに従い1ずつ大きくなる。
幅(X方向のサイズ) width ピクセル、高さ(Y方向のサイズ) height ピクセルのウィンドウの座標は図のようになる。左上端が (x, y) = (0, 0) となり、右下端が (width - 1, height - 1) となる。

幅 width ピクセル、高さ height ピクセルのウィンドウの座標

以下の点は注意しておく必要がある。



Graphics には、以下のような基本図形を描画するメソッドがある。

文字列drawString(文字列, 左X, ベースラインY)
文字配列drawChars(文字配列, オフセット, 長さ, 左X, ベースラインY)
直線drawLine(点1X, 点1Y, 点2X, 点2Y)
四角形drawRect(左上X, 左上Y, 幅, 高さ)
fillRect(左上X, 左上Y, 幅, 高さ)
角の丸い四角形drawRoundRect(左上X, 左上Y, 幅, 高さ, コーナー丸X直径, コーナー丸Y直径)
fillRoundRect(左上X, 左上Y, 幅, 高さ, コーナー丸X直径, コーナー丸Y直径)
楕円drawOval(左上X, 左上Y, 幅, 高さ)
fillOval(左上X, 左上Y, 幅, 高さ)
弧、扇形drawArc(左上X, 左上Y, 幅, 高さ, 開始点角度, 描画角度)
fillArc(左上X, 左上Y, 幅, 高さ, 開始点角度, 描画角度)
多角形drawPolygon(X座標配列, Y座標配列, 頂点数)
fillPolygon(X座標配列, Y座標配列, 頂点数)

draw...系は輪郭のみ描画、fill...系は中も塗る。


※ 楕円の描画指定の説明


※※※※※


Graphics には他の描画用メソッドもあるので、詳しいことを知りたい人は JDK の API ドキュメントの Graphics のところを調べるとよい。例えばここ


Java SEの描画では、描画用に渡される Graphics オブジェクトは、そのサブクラスの Graphics2D (抽象クラス java.awt.Graphics2D) のオブジェクトでもある。
Graphics2D では、Graphics よりも高機能なグラフィクス操作が用意されている。Graphics 型の変数を Grpahics2D 型にキャストすれば、それら高機能なメソッドが利用できる。詳しいことを知りたい人は JDK の API ドキュメントを当たるとよい。例えばここからいろいろたどって調べればよい。


以下の演習は提出は不要だが、次回のGUI課題の際の基礎になるものなので、一生懸命やってプログラムを作り上げること。


演習16   図形種・塗りつぶし有無・XY位置・サイズ・描画色・背景色を指定して基本図形を描画するアプリケーション

下図のような画面のように、図形種・塗りつぶし有無・XY位置・サイズ・描画色・背景色を指定して基本図形を描画するアプリケーションを作る。

実行中の画面

ドロップダウンリストで図形種を選択・チェックボックスで塗りつぶし有無を指定・テキストフィールドでXY位置とサイズを指定・ボタンで描画色・背景色を指定し、中央のパネルに図形を描画することができる。


Eclipse を起動する。演習室PCでは、デスクトップの All-in-one Eclipse のアイコンなどから起動できる。

起動すると、最初にワークスペースを聞いてくる。Eclipseはプロジェクト単位でプログラム開発をするが、ワークスペースはプロジェクトの置かれるフォルダのことである。

演習室PCの場合、ワークスペースはデフォルトでは H:\workspace フォルダになっている。原則、このままで利用することを勧める。
授業別にワークスペースを設定する場合などは、別フォルダを設定する。Hドライブ等、演習室PCが再起動しても消えてしまわない場所に、授業用のフォルダを作り、設定すること。一応、USBディスクのフォルダに設定することも可能だと思われるが、別の日に同じUSBディスクを持参していないと作業が続けられないので注意が必要となる。

※ 起動時にワークスペースを授業用のフォルダに設定できなかった場合は、

メニューの 「ファイル(F)」-「ワークスペースの切り替え(W)」-「その他(O)...」

を選択し、設定すること。


演習室PCのEclipse設定では、起動時の画面の配色は暗い基調 (ダークモード) となっている。
後述のデザイナーによる画面設計ではダークモードだとアイコンの内容が識別しにくいことがあるので、下記手順で配色を変更した方がよい。

メニューの 「ウィンドウ(W)」
「設定(P)」
を開き、
> 一般
の部分を開き、さらに、その中の
> 外観
をクリックする。「ルック&フィール」の右端の ∨ をクリックして選択肢を出し、「ダーク」以外、例えば
クラシック
に設定し、ダイアログ下部の
適用して閉じる
をクリックして終了する。

テーマの変更を有効にするため、Eclipseを再起動する。
再起動後は新しい配色に変更される。


Eclipse を起動し、プロジェクトが何も開いていない状態とし、

メニューの 「ファイル(F)」-「新規(N)」 の中の 「Java プロジェクト」 を選択

し、プロジェクト名を

Draw

とする。

また、画面の下の方に

module-info.javaファイルの作成

というチェックボックスがある。もしこれにチェックが入っていたら、クリックしてチェックを外す。

以上が設定出来たら、「完了(F)」 をクリックしてプロジェクト作成を完了させる。

次に、フレームウィンドウを作成する。

メニューの 「ファイル(F)」-「新規(N)」 の中の 「その他(O)...」 を選択

WindowBuilder の中の Swing デザイナー にある
「JFrame」

を選択する。これにより JFrame を拡張した独自クラスのフレームウィンドウが作成される。

「パッケージ(K)」 を   ap1.draw
「名前(M)」 を   Draw

として、「完了(F)」 をクリックする。これにより、プロジェクトフォルダの

src\ap1\draw

フォルダに、JFrame を拡張したクラス Draw が入ったファイル Draw.java が生成されることになる。

ソース Draw.java が開いているはずである。ソースウィンドウの下部にある

デザイン

タブをクリックするとデザインモードに移る。
フレームの title プロパティを

GUI部品と基本グラフィクス (自分の学籍番号と氏名)

とする。これはフレームウィンドウのタイトルバーに表示される。

AWT/Swing では、各GUI部品はレイアウトマネージャの方針に従って配置される。レイアウトマネージャは多数の種類があり、用途に応じて使用される。最もシンプルなレイアウトマネージャとして、FlowLayout と BorderLayout がある。

FlowLayout (完全修飾名は java.awt.FlowLayout) は、部品をそのままのサイズ (推奨サイズ) で順番に左から右へ・上から下へ並べていくだけで配置する。

BorderLayout (完全修飾名は java.awt.BorderLayout) は、部品を CENTER (中央), NORTH (上辺), EAST (右辺), SOUTH (下辺), WEST (左辺) 位置を指定して配置する。各部品は最大限広げられて領域を埋める。

GUI部品の区画で contentPane を選択し、その下に表示されるプロパティ一覧の中にある

layout

プロパティを選択し

BorderLayout

に設定する。

この contentPane にGUI部品として JPanel を2つ追加するが、BorderLayout に従って NORTH と CENTER に部品を配置し、下記の通り変数名を変更する。
変数名はプロパティの一番上の行にある Variable の箇所で変更できる。

NORTH (上辺) に追加したものを controlPanel と言う変数名に変更
CENTER (中央) に追加したものを drawPanel と言う変数名に変更

初期状態では、Swing Designerで追加したGUI部品はコンストラクタの中のローカル変数となる。コンストラクタの外部 (イベントハンドラも含む) でその変数にアクセスしたい場合は、そのままではまずい。
そこで、GUI部品をローカル変数でなく、フレームクラスのインスタンス変数 (フィールド) に変更する。変更したい部品を選んだ状態で、図の

ローカル変数をフィールド変数に

ボタンをクリックすればよい。
上の2つの JPanel の内では、drawPanel はフィールド変数にする必要がある。
すべての部品をフィールド変数にする必要はないが、判断が自分で出来ない人は全部フィールド変数としてしまって構わない。

一旦フィールド変数に変更したら、同じ位置のボタンが逆の操作「Convert field to local」(矢印が下向きのアイコン) になるので、二度目のクリックをしてはいけない。

※ JTextField の場合は、配置したままの状態で、フィールド変数として定義されている。従って、「Convert local to field」の操作は必要ない。同じ位置のボタンが反対の操作「Convert field to local」になっているので、その位置のボタンをクリックしてはいけない。

JPanel は、無設定の状態で、FlowLayout に従って部品を配置する。
controlPanel にGUI部品として JLabel, JComboBox, JCheckBox, JPanel①, JPanel②, JButton①, JButton② を順に追加し、JLabelの text プロパティを設定した上、一部を図のように名前変更する。

コントロールパネル全体

名前指定のある comboShape, checkFill, buttonDrawColor, buttonBgColor は、すべて上記の「Convert local to field」ボタンを押してフィールド変数にしておくこと。

JPanel①, JPanel② は、「拡張プロパティの表示」アイコン

拡張プロパティの表示

をクリックして拡張プロパティを表示させ、その中の border プロパティを

LineBorder (黒 1ピクセル)

として、黒線で枠を付ける。

JButton① ≡ buttonDrawColor は、text プロパティは空とし、背景色 (background プロパティ) を黒とする。
JButton② ≡ buttonBgColor は、text プロパティは空とし、背景色 (background プロパティ) を白とする。
いずれも、拡張プロパティを表示させ、preferredSize プロパティを 横 30 ピクセル、縦 20ピクセル 程度に設定して大きさを調整する。

Panel① にGUI部品として JLabel, JLabel, JTextField, JLabel, JTextField を順に追加し、JLabelの text プロパティを設定した上、一部を図のように名前変更する。

位置設定パネル

JTextField では、text プロパティによって入力文字を前もって設定でき、また、columns プロパティによって入力文字のための幅の目安を設定できる。
Panel① の tfX, tfY では、text プロパティはそれぞれ 20, 30 にする。columns プロパティはどちらも 4 程度が適当である。

Panel② にGUI部品として JLabel, JLabel, JTextField, JLabel, JTextField を順に追加し、JLabelの text プロパティを設定した上、一部を図のように名前変更する。

サイズ設定パネル

Panel② の tfWidth, tfHeight では、text プロパティはそれぞれ 300, 200 にする。columns プロパティはどちらも 5 程度が適当である。

描画図形のタイプは JComboBox で設定するが、その選択候補として、下のような enum 型 Shape を用意する。ソースに戻り、フレームクラスの内部に以下のコードを入れる。

import不足でエラーが出るときは、エラー箇所でimportを補う処理をすること。エラーマークをクリックしてマウスで処理を選択できる。
ここのコードではクラス Graphics (パッケージ java.awt) の import を補う必要がある。


次に、上記enumを使って、候補図形が JComboBox ≡ comboShape のリストに表示されるように、comboShape を生成している

comboShape = new JComboBox();

という行を

と変更する。

ソースコード上でエラーがあるとデザイン画面に移行できない。デザインに行くためには、まずソース上でエラーを取る必要がある。

ソース上でエラーがなくなってもデザインに行けない場合は、Eclipse側の問題である可能性がある。その時は Eclipse を一旦終了し再起動すると直る場合がある。

描画のコードを入れる前に、描画色および背景色を表す Color 型の変数 drawColor および bgColor をフレームクラスのフィールド変数として定義しておく。クラスの最初の辺りで、以下を定義する。描画色を黒・背景色を白としている。

描画は drawPanel インスタンスの paintComponent メソッドで行う。drawPanel を JPanel を拡張した無名クラス として、その中で paintComponent をオーバーライドする。具体的には、コンストラクタにある

drawPanel = new JPanel();

という部分を、

のように変更する。

※ 注意
paintComponent と似た名前で、同じくGraphicsオブジェクトをパラメータとする、紛らわしい以下のようなメソッドがあるので、間違わないようにすること。
     paintComponents
     printComponent
     printComponents

import不足でエラーが出るときは、エラー箇所でimportを補う処理をすること。エラーマークをクリックしてマウスで処理を選択できる。
JComboBox の comboShape から該当する Shape型の shape を得て、また、JCheckBox から fill、各 JTextField から x, y, width, height の値を得た後、shape の draw メソッドを呼び出している。実際の描画処理は、各enum定数で実装 (定数固有メソッド実装) されている draw メソッドが担当している。

なお、JTextField では、

public String getText()

というメソッドにより、入力された文字列を String 型のオブジェクトとして得ることができる。
文字列から整数値への変換には Integer.parseInt メソッドを使えばよい。

続いて、各GUI部品に対するイベント処理を設定していく。
controlPanel の部品に働きかけることによって各設定が変わったときに、drawPanel を再描画するようにする。

JComboBox である comboShape では、項目が選択されたときに発生し呼び出される actionPerformed イベントハンドラを設定する。デザインモードで Event の action から performed を選択して

空白部分をダブルクリックすると、actionPerformed イベントハンドラ部分のソース入力に変わるので、

のように中を入力する。drawPanel の repaint メソッドを呼び出すことによって、drawPanel の再描画をGUIシステムに要求することになる。その後、GUIシステム側から drawPanel の paintComponent メソッドなどを呼び出し、実際の描画処理を行わせることになる。

入力するのは赤色部分だけで、デザインモードから Event 設定をすることによって、外側は自動生成させなければならない。以下のイベント設定でも同様である。

JCheckBox である checkFill では、上と同様に actionPerformed イベントハンドラ (クリックされたときに発生し呼び出される) で設定してもよい。
ここでは、チェック状態が変わったときに発生し呼び出される itemStateChanged イベントハンドラを設定してみる。デザインモードで Event の item から stateChanged を選択して

空白部分をダブルクリックすると、itemStateChanged イベントハンドラ部分のソース入力に変わるので、

のように中を入力する。

JTextField である tfX, tfY, tfWidth, tfHeight では、Enterキーが押されたときに発生し呼び出される actionPerformed イベントハンドラで同様の設定を行う。デザインモードで Event の action から performed を選択して空白部分をダブルクリックすると、actionPerformed イベントハンドラ部分のソース入力に変わる。例えば、tfX では、以下のようなコードを入力する。

描画色・背景色の設定では、先に定義した描画色・背景色を表す変数 drawColor および bgColor を使用する。
描画色を設定する buttonDrawColor (JButton) では、ボタンが押されたときに発生し呼び出される actionPerformed イベントハンドラを設定し、

のように描画色の変更ができるようにする。
描画色の変更に応じて、setBackground メソッドにより buttonDrawColor の背景色も変更する。JButton のスーパークラス (2つ上) である JComponent で、setBackground メソッドで色が変更されるときは repaint メソッドが呼び出されるようになっているので、buttonDrawColor の背景色を変更しても repaint メソッドを明示的に呼び出す必要はない。
drawPanel の方は明示的に repaint を呼び出し再描画させる必要がある。

※ JColorChooser でエラーが出る場合は、エラー箇所にカーソルを持っていき、クイック・フィックスとして表示される「JColorChooser をインポートします (javax.swing)」という項目を選択する。

背景色を設定する buttonBgColor でも、buttonDrawColor と同様にする。ただし、「描画色」部分は「背景色」とし、buttonDrawColor と drawColor の代りに buttonBgColor と bgColor を設定する。

以上で、目的の動作が実現できているはずである。
アプリケーションを起動した初期状態で、コントロール用GUI部品や描画図形がウィンドウからはみ出していないようにフレームのサイズを調整すること。

サイズ変更は、デザイン画面でフレームウィンドウ (JFrame) を選択し外枠をマウスでドラッグすることにより行える。


Eclipse上で正しく動いたのを確認したら、プログラムの「実行可能jarファイル Draw.jar」を作成して実行してみること。

※ Eclipseプロジェクトでの実行可能jarファイルの作成

Eclipseで Draw プロジェクトを開いた状態で、

「ファイル(F)」
「エクスポート(O)」

で、

「Java」

の中にある

「実行可能JARファイル」

を選択し、

「次へ(N)」

をクリックする。

次の画面で、

「起動構成(L)」に「Draw - Draw」が設定されていなければ、ドロップダウンリストで設定する。
「エクスポート先(D)」の「参照(R)」ボタンをクリックし、保存場所と名前を指定する。
ファイル名は Draw.jar とする。
「ライブラリー処理」は「生成されるJARに必須ライブラリを抽出(E)」とする。

と入力・設定した上で、

下部にある「完了(F)」ボタンをクリック

すれば、指定した場所に実行可能jarファイル Draw.jar が作成される。


実行可能jarファイルの実行方法

PowerShell または コマンドプロンプト を起動する。まず、下記のようにjarファイルのあるフォルダに移動する。

(PowerShell の場合)

cd    jarファイルのあるフォルダ

(コマンドプロンプト の場合)

cd    /D    jarファイルのあるフォルダ

※ 名前にスペースを含むフォルダがある場合は上記のフォルダ指定で

"jarファイルの ある フォルダ"

のように、フォルダ指定全体をダブルクォーテーションで囲むこと。

次に以下のコマンドでjarファイルを実行する。

java    -jar    jarファイルの名前

今回は、jarファイルの名前は Draw.jar なので、以下のコマンドとなる。

java    -jar    Draw.jar

上を参考に、作ったjarファイル Draw.jar が正常に実行されることを確認する。


多く見られる間違い


※【補足】 コンパイル時に表示される warning への対応

Swing の JComboBox クラスは、Java 7 以降、型パラメータ付きになった。しかし、現在、演習室PCの Eclipseで利用できる Swing コンポーネントの画面デザイナが JComboBox の型パラメータに非対応のコードを生成する。そのため、上記手順でプログラムを完成させても、コンパイル時に warning (警告) が表示される。

warning を無くすためには、Java 7に対応させ、JComboBoxの変数 comboShape の定義の際および生成の際に型パラメータを付けた以下のコードにすればよい。

定義の際は、配列要素とする Shape を型パラメータとして、

JComboBox<Shape> comboShape;

生成の際は、ダイアモンド演算子 (型パラメータの省略記法) を使って、

comboShape = new JComboBox<>(Shape.values());

上記で warning は無くなる。新しいバージョンのSwingデザイナーでは、この状態でもデザイン画面に移行できる。

ただし、少しバージョンの古いSwingデザイナーが入っていると、Swing コンポーネントの画面デザイナがこの書き方に非対応でデザイン画面に移行できなくなってしまう。
その場合にデザイン画面に移行できる状態のまま warning を無くすには、Eclipseの警告メッセージのガイドで示されている、警告抑制のためのアノテーション(注釈) @SuppressWarnings の "rawtypes" および "unchecked" を入れる方法で対応できる。


課題6   五角形・星形・独自図形2つの追加 (発展課題・任意提出)

上の演習アプリケーションに、五角形・星形および自分が独自で考えた図形2つの描画を追加する。

まず、上の演習プロジェクトをコピーする。
Eclispe の左上端窓で、プロジェクト名部分をクリックした状態で

「編集(E)」 - 「コピー(C)」

に続いて、

「編集(E)」 - 「貼り付け(P)」

とすれば、コピーされたプロジェクトが出来るので、プロジェクト名を

Draw2

としておく。以下では、元のプロジェクト Draw を閉じ、Draw2 のみ開いた状態で作業を行う。

クラス Draw の前に、下記のような頂点データを表すクラス Vertices を定義する。

クラス Vertices 前半
クラス Vertices 後半

クラス Draw の中の enum Shape に、五角形と星形を追加し、それぞれの draw メソッドで、クラス Vertices の static 変数

regularPentagon正五角形の頂点データ (原点中心の半径1の円に内接)
regularStar星形の頂点データ (原点中心の半径1の円に内接)

を使って、位置 (x, y) に 幅 width・高さ height の多角形を表示させる。
サイズは、X方向に (width/2.0) 倍、Y方向に (height/2.0) 倍する。ただし、数学座標とコンピュータ画面はY方向が逆向きなので、Y座標の値には -1 を掛ける。
位置はX方向に (width/2.0) + x、Y方向に (height/2.0) + y だけずらせばよい。
多角形の描画には drawPolygon および fillPolygon を用いるが、これらのメソッドで必要とする頂点データ配列は int 型なので、

int[] 整数X配列 = new int[頂点数];
int[] 整数Y配列 = new int[頂点数];

として、for 文によってインデックス i を 0 から 頂点数未満まで1ずつ増加させたループを作り、ループの中で、

整数X配列[i] = (width/2.0) * 五角形または星形の頂点データ.x[i] + (width/2.0) + x;
整数Y配列[i] = -(height/2.0) * 五角形または星形の頂点データ.y[i] + (height/2.0) + y;

とする。実際には、int 型に変換した値を代入する必要がある。int への変換は、簡単には、

式の値に 0.5 を加え、 (int)(   式   ) によって int にキャストする

方法がある。これを使うと以下のようなコードになる。

整数X配列[i] = (int)( (width/2.0) * 五角形または星形の頂点データ.x[i] + (width/2.0) + x + 0.5);
整数Y配列[i] = (int)( -(height/2.0) * 五角形または星形の頂点データ.y[i] + (height/2.0) + y + 0.5);

他に、Math.floor、Math.round、Math.ceil、Math.rint などのメソッドと int キャストを使う方法もある。

求めた整数X配列と整数Y配列を使って、fill の値に応じて drawPolygon あるいは fillPolygon を呼べば、五角形あるいは星形が描画できるようになる。

星型と五角形以外に、自分で独自の図形2つを考え、アプリケーションで描画できるように組み込むこと。ただし、元のコードを少しだけ直してできる単純な多角形は含めないものとする。
独自の2図形追加がないものは提出しないこと。


課題プログラムのすべての動作に問題がないと確認出来たら、下記の「プロジェクトのアーカイブ作成方法」を参考にして、プロジェクトのファイルをすべてまとめたzipファイルを作る。

プロジェクトのzipファイルを講義のWebページから提出。


※ プロジェクトのアーカイブ (zipファイル) 作成方法

Eclipseで、まとめファイルを作りたいプロジェクトを開いた状態で、

「ファイル(F)」
「エクスポート(O)」

で、

「一般」

の中にある

「アーカイブ・ファイル」

を選択し、

「次へ(N)」

をクリックする。

次の画面では、

該当のプロジェクトだけにチェックが入っているはず。
「宛先アーカイブ・ファイル(A)」の「参照(R)」ボタンをクリックし、保存場所と名前を指定する。
ファイル名は、例えば「プロジェクト名Pack.zip」のように、拡張子を .zip とする。
オプションは「zipフォーマットで保管(Z)」がセットされているはず。

と入力・設定した上で、

下部にある「完了(F)」ボタンをクリック

すれば、指定した場所にzipファイルが作成される。