このページは、学部2年生向け授業である、「マルチメディアプログラミング実習」 のために用意しました。
(Wikiの仕様で大文字小文字が混在した英単語に疑問符?が追加されるところがありますが、無視してください。)
SwingはJavaのパッケージで、GUIを構築するための数多くのclassが含まれています。例えば、ウィンドウを作成するためのクラス、ボタンを作成するためのクラス、メニューを作成するためのクラスなどがあります。
初期のJavaでは、AWT (Abstract Window Toolkit) というパッケージが使われていました(今でも使えます)。AWTを使っても、ウィンドウ、ボタン、メニューなどを全部作ることができます。でも、Swingに移行しています。AWTとSwingでは作れるGUIの見た目が違います。AWTは、Java独特のGUIになります。それに対して、Swingでは、稼働しているOSのGUIに近い形のアプリケーションが作れます。例えば、AWTでメニューバーを作ると、Windows風に、ウィンドウ上部にメニューバーが現れます。他のmacOSのアプリと一緒に使うと、違和感があります。それに対して、Swingでは、画面上部にメニューバーが現れます。
まずはJFrameというSwingのクラスを使います。Frameは枠のことで、ウィンドウです。 JはJavaのJです。
以下のリンクからJFrameクラスを選択して、何ができるかざっと見ておきましょう。
https://docs.oracle.com/javase/jp/8/docs/api/index.html
授業の最初で作ったウィンドウを出すプログラムです。
import javax.swing.JFrame; public class SimpleWindow { public static void main(String argv[]) { JFrame f = new JFrame("私が作った最初の窓"); f.setSize(200,100); f.setVisible(true); } }
このままだと、ウィンドウを閉じてもプログラムは終了しません。 ウィンドウを閉じた時に、プログラムを終了するかしないかは、アプリの設計でどちらでも可能です。がシンプルなプログラムでは、ウィンドウを閉じた時に終了する方式が多いようです。 ウィンドウを閉じるとプログラムが終了するようにしてみましょう。以下のように1行追加します。
import javax.swing.JFrame; public class SimpleWindow { public static void main(String argv[]) { JFrame f = new JFrame("私が作った最初の窓"); f.setSize(200,100); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setVisible(true); } }
このプログラムをよくみていきましょう。 mainの最初の行で、JFrameのコンストラクタを呼び出して、インスタンスを作っています。 引数付きのコンストラクタを使っています。Stringの引数を使うと、その内容がウィンドウのタイトル名になります。 作ったインスタンスはJFrameを参照する変数 f に代入されています。
mainの2行目では、JFrameのインスタンスメソッドであるsetSize()を呼んでいます。文字通り、ウィンドウのサイズを設定するメソッドです。
mainの最後の行では、setVisible()メソッドを呼んでいます。これは、ウィンドウを目に見えるように表示する機能です。作っただけでは表示されないです。
アプリケーションで使うウィンドウを作る時の流儀の一つに、素のウィンドウクラスを継承して、使いたいウィンドウをサブクラスで作る方法があります。Javaではそのような方法が、一般的です。ということで、JFrameを継承して、ウィンドウを作ってみます。上のプログラムと同じことを行いますが、やり方が違っています。以下です。
import javax.swing.JFrame; public class SimpleWindow extends JFrame { public void initialize () { this.setTitle("私が作った最初の窓"); this.setSize(200,100); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setVisible(true); } public static void main (String argv[]) { SimpleWindow sw = new SimpleWindow(); sw.initialize(); } }
このプログラムでは、JFrameを継承して、サブクラスとしてSimpleWindowを定義しています。 なので、SimpleWindowのインスタンスは、JFrameの機能を全て使えます。 別のプログラムからSimpleWindowのインスタンスを作って表示しても良いのですが、面倒なので、自信を動かすプログラムをmainで書きました。今まで、クラスを作ってそれを動かすプログラムをmainに書いていたのと同じです。
mainでは、自分自身のインスタンスを作って、それへの参照をswという変数に代入しています。 そしてinitialize()というインスタンスメソッドを呼んでいます。
initialize()は今の所SimpleWindowで新たに定義した唯一のメンバーです。 その名の通り、自分自身の初期化を行うつもりで命名しました。 コンストラクタとして実装しても良いのですが、結構複雑な仕事をするので、 別のメソッドにしました。ちなみに、他のオブジェクト指向言語では、 newした後に、init()とかinitialize()とかのメソッドを呼ぶ方式も多いです。(例えばSmallTalk言語)。 ここではそれを真似しました。
initialize()の中で、ウィンドウのタイトルを決めて、サイズを決めて、終了オプションを指定して、setVisibleしています。
このままではウィンドウが空っぽなので、文字を表示してみましょう。 文字を表示するクラスにJLabelがあります。その名の通りラベルです。
以下のリンクからJLabelクラスを選択して、何ができるかざっと見ておきましょう。
https://docs.oracle.com/javase/jp/8/docs/api/index.html
基本的な使い方は以下です。まずは、インスタンスを作ります。コンストラクタの引数で、表示させる文字を指定することもできます。
Label label = new Label("Hello!");
ところで、JFrameで作ったインスタンスは、Containerというクラスのインスタンスを持っています。その名前の通り、「何かを格納するもの」です。つまりウィンドウに情報を格納する機能を持ったインスタンスです。JFrameのインスタンスに、getContentPane()というメソッドを送ると、ウィンドウに表示したい情報を格納するインスタンスを返してくれます。
Container content = this.getContentPane();
で、自分自身のコンテントペーンを返してくれます。 これに対して、上記で作ったラベルインスタンスをaddすることができます。
content.add(label);
上記の、継承を使ったプログラムによるウィンドウの中に、 Hello!という文字を出してみよう。 上で紹介した3行を、initialize()メソッドに加えれば文字を出せます。
解答例:
import javax.swing.*; import java.awt.*; public class SimpleWindow extends JFrame { public void initialize () { this.setTitle("私が作った最初の窓"); JLabel label = new JLabel("Hello!"); Container content = this.getContentPane(); content.add(label); this.setSize(200,100); this.setVisible(true); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public static void main(String argv[]) { SimpleWindow sw = new SimpleWindow(); sw.initialize(); } }
コンテンツの大きさに合わせてウィンドウサイズを変更する機能があります。 上記のプログラムではsetSize()で変更していますが、これの代わりに、
this.pack();
というメソッドを呼び出してみましょう。以下のようになるはずです。
解答例:
import javax.swing.*; import java.awt.*; public class SimpleWindow extends JFrame { public void initialize () { this.setTitle("私が作った最初の窓"); JLabel label = new JLabel("Hello!"); Container content = this.getContentPane(); content.add(label); this.pack(); this.setVisible(true); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public static void main(String argv[]) { SimpleWindow sw = new SimpleWindow(); sw.initialize(); } }
今度はウィンドウにボタンを表示してみましょう。 ボタンなので、多分JButtonというクラスがありそうです。 以下から探して、何ができるかざっと見ておきましょう。
https://docs.oracle.com/javase/jp/8/docs/api/index.html
上記のプログラムのJLabelのところをJButtonにすればだいたい良いようです。試してみましょう。
解答例:
import javax.swing.*; import java.awt.*; public class SimpleWindow extends JFrame { public void initialize () { this.setTitle("私が作った最初の窓"); JButton button = new JButton("Hello!"); Container content = this.getContentPane(); content.add(button); this.pack(); this.setVisible(true); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public static void main(String argv[]) { SimpleWindow sw = new SimpleWindow(); sw.initialize(); } }
http://www.siio.jp/index.php?plugin=attach&pcmd=open&file=button.png&refer=How2JavaProgramming
プログラム12.2をみてください。 getContentPane()で得られたContainerに直接ボタンを貼付けることもできますが、 貼付けられるのは一つのボタンだけのようです。 そこで、JPanel (パネル) に2個のボタンを貼付け、それをContainerに貼付けることで複数のボタンを表示しています。
プログラム12.2を参考にして、継承を使ったプログラムによるウィンドウの中に、 2個のボタンを出してみよう。
解答例:
import javax.swing.*; import java.awt.*; public class SimpleButton extends JFrame { public void initialize () { this.setTitle("私が作った最初の窓"); JPanel panel = new JPanel(); JButton button1 = new JButton("button1"); JButton button2 = new JButton("button2"); panel.add(button1); panel.add(button2); Container container = this.getContentPane(); container.add(panel); this.pack(); this.setVisible(true); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public static void main(String argv[]) { SimpleButton sw = new SimpleButton(); sw.initialize(); } }
このプログラムでは,ボタンを押しても何もおこりません.
ボタンが押されたイベントを受け取るためには,
プログラム12.3を参考に,ボタンを押したらprintlnで次のようなメッセージを表示するプログラムを作ってみましょう.
ヒント(最初の6行です)
import javax.swing.*; import java.awt.*; import java.awt.event.*; public class SimpleButton extends JFrame implements ActionListener { JButton button1, button2; public void initialize () {
解答例
import javax.swing.*; import java.awt.*; import java.awt.event.*; public class SimpleButton extends JFrame implements ActionListener { JButton button1, button2; public void initialize () { this.setTitle("私が作った最初の窓"); JPanel panel = new JPanel(); button1 = new JButton("button1"); button2 = new JButton("button2"); button1.addActionListener(this); button2.addActionListener(this); panel.add(button1); panel.add(button2); Container container = this.getContentPane(); container.add(panel); this.pack(); this.setVisible(true); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public void actionPerformed (ActionEvent e) { if(e.getSource()==button1) System.out.println("Hello"); else System.out.println("Goodbye"); } public static void main(String argv[]) { SimpleButton sw = new SimpleButton(); sw.initialize(); } }
ここではボタンを区別するために、インスタンス(への参照)を比較した。それ以外の方法もある。 一つは、ボタンのテキストを入手することである。ボタンのテキストを入手してそれを比較しても良い。 ボタンのテキストを表示するだけなら以下のようにしても良い。
public void actionPerformed(ActionEvent e){ System.out.println(((JButton)e.getSource()).getText()); }
もう一つは、ボタンにコマンドを書く方法である。 ボタンにsetActionCommand(String)を定義しておくと、getActionCommand()で知ることができる。
button1.setActionCommand("hello");
としておけば、actionPerformedの中で
e.getActionCommand();
で文字列を得られる。例えば、
public void actionPerformed(ActionEvent e){ System.out.println(e.getActionCommand()); }
でコマンド部分を印刷できる。
上で作った二つのボタンのプログラムに対して、レイアウトマネージャのFlowLayoutを使って、左寄せ、センタリング、右寄せを試してください。
演習のヒント
bt1 = new JButton("button1"); bt2 = new JButton("button2"); panel.setLayout(new FlowLayout(FlowLayout.RIGHT)); bt1.setActionCommand("this is b1"); bt2.setActionCommand("this is b2");
FlowLayoutにはCENTER, LEFT, RIGHTなどの揃え方の指定がありますが、これをコンストラクタの引数で指定できるようです。addのところではレイアウト指定しないようです。