第 3 回 複雑なレイアウトのイベント処理 画像 データの読込み テーブルの使用 キーポイント レイアウトについて 前回までのレイアウト レイアウトの補足機能 固定座標を用いたレイアウト Grid Layout CardLayout について Card Layout Card Layout による複数ページ表示 ファイルの読み込み JFileChooser クラス java.awt.filedialog 画像データの読み込みと表示 テーブルの利用 JTable クラス テーブルデータの初期設定 Vector 型データの使用 1
前回までに学んだ GUI のレイアウト BorderLayout FlowLayout などの標準的なレイアウトを学んだ BorderLayout FlowLayout 今回は 更に複雑なデザインの GUI を作るためのレイアウト またそれに伴うイベント処理について学習していく 2
フレームのサイズを固定する 基本的なレイアウトの補足 setresizable() メソッドを用いて 引数に false を与えることでフレームのサイズを固定する public class Practice03 extends JFrame implements ActionListener { JPanel jp1; public static void main(string[] args){ new Practice03("Teaching3 Test Layout"); Practice03(String title){ jp1 = new JPanel(); jp1.add(new JLabel( "This is a JPanel with default layout in page 1")); jp1.add(new JButton("I'm a button")); jp1.add(new JLabel("I'm a label")); add(jp1); setdefaultcloseoperation(jframe.exit_on_close); setsize(400, 300); setresizable(false); settitle(title); setvisible(true); setresizable(falese) でサイズが固定される 3
基本的なレイアウトの補足 (2) BorderLayout の記述の仕方 BorderLayout の位置指定には絶対指定と相対指定がある どちらを使っても良いが 混在できない JPanel jp1,jp2; Practice03(String title){ jp2 = new JPanel(new BorderLayout()); jp2.add(new JLabel( This is a JPanel with BorderLayout in page 2"), "Center"); jp2.add(new JButton("North"), "North"); jp2.add(new JButton("South"), "South"); jp2.add(new JButton("West"), "West"); jp2.add(new JButton("East"), "East"); 絶対指定 相対指定 位置 BorderLayout.CENTER BorderLayout.CENTER 中央 BorderLayout.NORTH BorderLayout.PAGE_START 上 BorderLayout.SOUTH BorderLayout.PAGE_END 下 BorderLayout.WEST BorderLayout.LINE_START 左 BorderLayout.EAST BorderLayout.LINE_END 右 // 以下のように記述することもできる //jp2.add(new JButton("North"), BorderLayout.PAGE_START); //jp2.add(new JButton("South"), BorderLayout.PAGE_END); //jp2.add(new JButton("West"), BorderLayout.LINE_START); //jp2.add(new JButton("East"), BorderLayout.LINE_END); add(jp2); //add(jp1); 4
レイアウトマネージャを用いないレイアウト レイアウトマネージャを無効にする レイアウトマネージャを無効にした場合は 固定座標によってコンポーネントを配置する Java アプリケーションは色々な環境で実行される可能性があるため 基本的にはレイアウトマネージャの使用が推奨されるが 座標指定でアプリケーションを作成した場合などは固定座標を用いる JPanel jp1,jp2,jp3; Practice03(String title){ 60 (10,10,300,20) jp3 = new JPanel(); jp3.setlayout(null); 110 150 (10,60,150,20) JLabel jlabel = new JLabel( "This is a JPanel without layout in page 3"); jlabel.setbounds(10, 10, 300, 20); jp3.add(jlabel); JButton jbutton1 = new JButton("I'm a button"); jbutton1.setbounds(10, 35, 150, 20); jp3.add(jbutton1); JButton jbutton2 = new JButton("I'm another button"); jbutton2.setbounds(10, 60, 200, 20); jp3.add(jbutton2); 200 (10,110,200,20) 座標サイズ add(jp3); //add(jp2); 5
GridLayout の作成 GridLayout クラスを用いて画面を作成する GridLayoutは対象となる領域全体を指定した行数と列数に分割する 配置されたコンポーネントは全て同じサイズに調節される import java.awt.gridlayout; JPanel jp1,jp2,jp3,jp4; Practice03(String title){ // 行と列数を指定 ( 行, 列 ) -> (2x2) // 指定がない場合はコンポーネントが横に配置される jp4 = new JPanel(new GridLayout(2, 2)); 行 2 jp4.add(new JButton("This is")); jp4.add(new JButton("a JPanel with")); jp4.add(new JButton("2*2 GridLayout")); jp4.add(new JButton("in page 4")); add(jp4); //add(jp3); 列 2 6
CardLayout について CardLayout クラスは複数コンポーネントを切り替えて表示できるレイアウトマネージャー それぞれのカードにコンポーネントを登録した複数のカードを内部的に保持し 表示するカードを切り替えることで表示するコンポーネントを切り替える CardLayout クラスの持つメソッドは以下の通り next() next() next() previous() previous() previous() first() last() first() - コンテナの最初のカードに切り替える last() - コンテナの最後のカードに切り替える next() - 指定されたコンテナの次のカードに切り替える previous() - 指定されたコンテナの前のカードに切り替える 7
CardLayout について (2) レイアウトの動作の確認のために簡単なサンプルプログラムを作る import javax.swing.*; import java.awt.cardlayout; import java.awt.event.*; public class CardLayoutTest extends JFrame implements ActionListener{ JPanel jpmain; CardLayout cl; public static void main(string[] args){ CardLayoutTest frame = new CardLayoutTest2(); CardLayoutTest(){ // Card1 JPanel c1 = new JPanel(); c1.add(new JLabel("card1")); c1.add(new JButton("button")); // Card2 JPanel c2 = new JPanel(); c2.add(new JLabel("card2")); c2.add(new JTextField("", 10)); // Card3 JPanel c3 = new JPanel(); c3.add(new JLabel("card3")); c3.add(new JCheckBox("checkbox1")); c3.add(new JCheckBox("checkbox2")); jpmain = new JPanel(); cl= new CardLayout(); // パネルに CardLayout を設定する jpmain.setlayout(cl); // 作成したカードをパネルに設定する // この時点では card1 のみ表示される jpmain.add(c1, "card1"); jpmain.add(c2, "card2"); jpmain.add(c3, "card3"); add(jpmain,borderlayout.center); setdefaultcloseoperation(jframe.exit_on_close) setsize(300,200); settitle("cardlayouttest"); setvisible(true); 8
CardLayout について (3) カード移動用のボタンとイベントの追加を行う CardLayoutTest(){ // カード移動用ボタン JButton firstbtn = new JButton("First"); firstbtn.addactionlistener(this); firstbtn.setactioncommand("first"); JButton prevbtn = new JButton("Prev"); prevbtn.addactionlistener(this); prevbtn.setactioncommand("prev"); JButton nextbtn = new JButton("Next"); nextbtn.addactionlistener(this); nextbtn.setactioncommand("next"); ( イベント処理 ) public void actionperformed(actionevent e) { String cmd = e.getactioncommand(); if (cmd.equals("first")) { cl.first(jp); else if (cmd.equals("last")) { cl.last(jp); else if (cmd.equals("next")) { cl.next(jp); else if (cmd.equals("prev")) { cl.previous(jp); JButton lastbtn = new JButton("Last"); lastbtn.addactionlistener(this); lastbtn.setactioncommand("last"); JPanel btnp = new JPanel(); btnp.add(firstbtn); btnp.add(prevbtn); btnp.add(nextbtn); btnp.add(lastbtn); add(btnp, BorderLayout.SOUTH); プログラムを実行して動作を確認して下さい 9
CardLayout について (4) 先ほど作ったレイアウトを用いて画面を作成する public class CardLayoutTest 2 extends JFrame implements ActionListener { JPanel jpmain; CardLayout cl; JPanel[] jps; JButton jb; public static void main(string[] args) { new CardLayoutTest 2(" CardLayoutTest 2"); public CardLayoutTest2(String title){ cl = new CardLayout(); jpmain = new JPanel(); jpmain.setlayout(cl); add(jpmain, "Center"); // 各ページ用のパネルを配列に置きなおす jps = new JPanel[4]; // 画面下部のボタンは CardLayoutTest() で作成した // ボタン用の JPanel を使用 JPanel btnp = new JPanel(); btnp.add(firstbtn); add(btnp, BorderLayout.SOUTH); settitle(title); setsize(400,300); setlocation(400,300); setresizable(false); setdefaultcloseoperation(jframe.exit_on_close); setvisible(true); // 今回のレイアウトの演習 jp1~jp4 で作成したパネルを // そのまま使用して下さい jps[0] = new JPanel(); jps[0].add(new JLabel("This is a JPanel with default layout in page 1")); jps[0].add(new JButton("I'm a button")); jps[0].add(new JLabel("I'm a label")); // メインのパネルに add する際に カードの名前をつける jpmain.add(jps[0], "page1"); // 同じように jp2~jp4 の部分も作成 // ( イベント処理 ) public void actionperformed(actionevent e) { String cmd = e.getactioncommand(); // イベント処理部も CardLayoutTest() で作成した // ボタン用のイベント処理を記述 10
CardLayout について (5) 実行して画面の動作を確認 next Prev jps[0] First jps[1] jps[2] jps[3] Last 11
ファイルの読み込み (1) JFileChooser クラスを用いたファイルの読み込み 画面上でファイル名を選択できるダイアログを表示する場合に利用する public class JFileChooserTest extends JFrame implements ActionListener { JLabel label; public static void main(string[] args) { JFileChooserTest frame = new JFileChooserTest("JFileChooserTest"); JFileChooserTest(String title) { JButton button = new JButton("Select File"); button.addactionlistener(this); JPanel btnpanel = new JPanel(); btnpanel.add(button); label = new JLabel(); JPanel lbpanel = new JPanel(); lbpanel.add(label); add(lbpanel, BorderLayout.CENTER); add(btnpanel, BorderLayout.PAGE_END); public void actionperformed(actionevent e) { JFileChooser filechooser = new JFileChooser(); int selected = filechooser.showopendialog(this); if (selected == JFileChooser.APPROVE_OPTION) { File file = filechooser.getselectedfile(); label.settext(file.getname()); ダイアログを開くボタンをクリックし 動作を確認して下さいファイルを選択し 画面内のラベルに選択した情報が適用されるのを確認して下さい setdefaultcloseoperation(jframe.exit_on_close); setsize(300, 200); settitle(title); setvisible(true); 12
ファイルの読み込み (2) JFileChooser クラスを用いたファイルの読み込み 画面上でファイル名を選択できるダイアログを表示する場合に利用する public void actionperformed(actionevent e) { JFileChooser filechooser = new JFileChooser(); // ダイアログを開く // 引数に指定した文字列をボタンに使用できる -> 実行 int selected = filechooser.showopendialog(this, 実行 ); // 選択された操作に対応するイベントを選択する if (selected == JFileChooser.APPROVE_OPTION) { File file = filechooser.getselectedfile(); label.settext(file.getname()); else if (selected ==JFileChooser.CANCEL_OPTION){ label.settext(" キャンセルされました "); else if (selected ==JFileChooser.ERROR_OPTION){ label.settext(" エラー又は取消しがありました "); 定義値値ボタンの種類 JFileChooser.APPROV E_OPTION 0 引数で指定した文字列が表示されたボタンが選択された場合 JFileChooser.CANCEL _OPTION JFileCHooser.ERROR_ OPTION 1 取消し ボタンが選択された場合 -1 エラー発生時 13
ファイルの読み込み (3) java.awt.filedialog を使ってファイルの読み込みをする // 画面のデザインは先ほどのプログラムを利用して下さい public void actionperformed(actionevent e) { // FileDialog を開く // 第一引数 : ターゲットとなるフレーム // 第二引数 : ダイアログのタイトル // ( 第三引数 : ダイアログのモード ) FileDialog fd = new FileDialog(this, "File Select"); // FileDialog を表示する fd.setvisible(true); 適当なファイルを選択して 画面の表示を確認して下さい // getdirectory() : 選択したファイルのパスを取得 // getfile() : 選択したファイルの名前を取得 String fullpath = fd.getdirectory() + fd.getfile(); label.settext(fullpath); 14
ファイルの読み込み (4) java.awt.canvas を継承した MyCanvas クラスを用いて画像の表示をする public class PictureViewer extends JFrame implements ActionListener { JPanel jp; MyCanvas mc; String fpath,fname; JButton JBselect; FileDialog fd_load; //main メソッド省略 public PictureViewer(String title) { settitle(title); jp = new JPanel(); JBselect = new JButton("Select a picture"); JBselect.addActionListener(this); jp.add(jbselect); // 画像表示用に MyCanvas オブジェクトを作成 mc = new MyCanvas(); add(jp, "North"); add(mc, "Center"); setsize(360, 360); setlocation(400, 200); // ウィンドウが閉じられた時の処理 addwindowlistener(new WindowAdapter(){ public void windowclosing(windowevent e) { System.exit(0); ); setvisible(true); fd_load = new FileDialog(this, "Open file", FileDialog.LOAD); public void actionperformed(actionevent arg0) { fd_load.setvisible(true); fpath = fd_load.getdirectory(); fname = fd_load.getfile(); if((fpath!= null) && (fname!= null)) { // display() メソッドに指定したファイルのパスを持った // File オブジェクトを渡す this.display(new File(fpath + fname)); public void display(file f) { try{ // 読み込んだファイルの画像データをセット BufferedImage bi = ImageIO.read(f); mc.setimage(bi); this.settitle("pictureviewer - [" + f.getname() + "]"); catch (Exception e) { e.printstacktrace(); mc.repaint(); MyCanvas クラス MyCanvas.java 15
ファイルの読み込み (5) java.awt.canvas を継承した MyCanvas クラスを用いて画像の表示をする 適当な画像ファイルを選択して動作を確認して下さい ( 余裕のある人は MyCanvas クラスの内部の動作を確認してみて下さい ) 16
テーブルの利用 JTable クラスを利用して デザインにテーブルを利用する JTableクラスは表形式の形でデータを表示する際に使用する データベースのデータのように扱うために 同じ列のデータはデータ形式を統一する必要がある public class TableViewer extends JFrame { // テーブルデータ String[][] tdata = { {" りんご ","150","7500","50", {" みかん ","50","4000","20", {" ぶどう ","200","8000","60", {" バナナ ","250","15000","40" ; // テーブルの要素名 String[] columnnames = {" 商品 ", " 価格 ( 円 )", " 売上 ( 円 )", " 在庫 ( 個 )"; public static void main(string[] args){ new TableViewer(" Teaching 5 Table Viewer "); public TableViewer(String title){ JPanel p = new JPanel(); // テーブルの作成 JTable table = new JTable(tdata, columnnames); // サイズの自動設定 table.setautoresizemode(jtable.auto_resize_off); // JScrollPane オブジェクト上にテーブルを配置 JScrollPane sp = new JScrollPane(table); sp.setpreferredsize(new Dimension(300, 100)); p.add(sp); JTable table2 = new JTable(4,4); table2.setautoresizemode(jtable.auto_resize_off); JScrollPane sp2 = new JScrollPane(table2); sp2.setpreferredsize(new Dimension(300, 100)); p.add(sp2); add(p, BorderLayout.CENTER); settitle(title); setsize(400,250); setdefaultcloseoperation(jframe.exit_on_close); setvisible(true); 設定したテーブルのデータは後から編集もできる 17
初期データの設定 テーブルの利用 (2) テーブルのデータからJTableオブジェクトを作成すると データを後から追加することができない DefaultTableModelクラスのオブジェクトを用いることで それが可能となる import javax.swing.table.defaulttablemodel; public TableViewer(String title){ JPanel p = new JPanel(); // 引数には テーブルのデータを与える DefaultTableModel tm = new DefaultTableModel(tdata,columnNames); // DefaultTableModel のオブジェクトを引数として与える JTable table = new JTable(tm); //JTable table = new JTable(tdata, columnnames); table.setautoresizemode(jtable.auto_resize_off); JScrollPane sp = new JScrollPane(table); sp.setpreferredsize(new Dimension(300, 100)); p.add(sp); 表示は変わらない 18
テーブルのデータの扱い テーブルの利用 (3) 前項では配列を用いてテーブルを作成した 配列ではなく Vector 型のオブジェクトを用いてテーブルを作成することもできる public TableViewer(String title){ Vector person1 = new Vector(); person1.add("john"); person1.add("male"); person1.add("20"); Vector person2 = new Vector(); person2.add("mary"); person2.add("female"); person2.add("18"); Vector data = new Vector(); data.add(person1); data.add(person2); Vector columnnames = new Vector(); columnnames.add("name"); columnnames.add("sex"); columnnames.add("age"); DefaultTableModel DTM = new DefaultTableModel(data, columnnames); JTable table = new JTable(DTM); table.setautoresizemode(jtable.auto_resize_off); JScrollPane pane = new JScrollPane(); pane.setviewportview(table); JTable のコンストラクタ JTable() - デフォルトの JTable を構築 JTable(int numrows, int numcolumns) - numrows numcolumns で JTable を構築 JTable(Object[][] rowdata, Object[] columnnames) - 2 次元配列 rowdata の値をデータ columnnames を列名とする JTable を構築 JTable(TableModel dm) - データモデル dm を基にした JTable を構築 JTable(TableModel dm, TableColumnModel cm) - データモデル 列モデルを基とした JTable を構築 JTable(TableModel dm, TableColumnModel cm, ListSelectionModel sm) - データモデル 列モデル 選択モデルを基とした JTable を構築 JTable(Vector rowdata, Vector columnnames) - Vector 型の rowdata columnnames を基として JTable を構築 p.add(pane); add(p, BorderLayout.CENTER); 19
テーブルデータを追加する テーブルの利用 (4) addrow() メソッドを使ってテーブルにデータを追加することができる 以下の記述を付け足して実行し 動作を確認して下さい public TableViewer(String title){ // テーブルにデータを与えるための引数として // Vector 型のオブジェクトを作成する Vector tabledata = new Vector(); tabledata.add("hoseitaro"); tabledata.add("male"); tabledata.add("24"); // DefaultTableModel クラスの addrow() クラスを使って // データを後から追加することができる DTM.addRow(tabledata); DefaultTableModel クラスの addrow() メソッドを使って後から追加したデータが 実際に追加されていることを確認することができる このようにして 初期値を与えたテーブルに後からデータを追加することができる 20