▼Swingでボタンイベントを"CLICK"から"DOWN"に変える
JAVAのGUIライブラリSwingにはボタン'JButton'があります。ところがこのボタンは
- 押しても機能せず
- 離すと機能する
沢山のボタンをすばやく操作しようとすると、押したあと離すまで の間にマウスが動いてしまい、うまく機能しないことが良くあります。
これを「押すと機能する」という当たり前のボタンにします。
(以前の記事◇クリック廃止論のアプリケーション側での実践法のJAVA版です)
JButtonの派生クラスを作る
既存のアプリケーションを簡単に「押したら動く」ボタン化する方法を考えます。
JButtonの派生クラスを作り、JButtonの代わりにそのクラスを使う形に変える以外
の変更が無い様にします。
JButtonは外部インターフェースとしては「ボタンを押した」ことを無視しますが、 内部的には「ボタンを押した」イベントと「ボタンを離した」イベントを取得して います。
そこで、作成する派生クラスでは
- 内部的に検出される「ボタンを押した」イベント に対し「ボタンを離した」というイベントを擬似的に発生させる
オーバーロードする関数はマウスのボタンイベントを処理するproseccMouseEvent()です。
構築子は継承されませんので全ての構築子を作ります。
コード(HiJButton.java)を示します。
// 押せば機能するSwingのJButton派生 //package xx.yy.zz.hi; import javax.swing.JButton; import javax.swing.Action; import javax.swing.Icon; import java.awt.event.MouseEvent; /** * 押せば機能するSwingのJButton派生クラス<br> * インターフェース詳細はJButtonを参照のこと */ public class HiJButton extends javax.swing.JButton { //----- 構築子群 ------ HiJButton() { super(); } HiJButton(Action a_) { super(a_); } HiJButton(Icon i_) { super(i_); } HiJButton(String t_) { super(t_); } HiJButton(String t_,Icon i_){ super(t_,i_); } //----- マウスボタンイベント処理 protected void processMouseEvent(MouseEvent e_){ if( (e_.getID() != MouseEvent.MOUSE_RELEASED) ||(e_.getID() != MouseEvent.MOUSE_CLICKED ) ){ // 不要となるイベント以外はベースクラスに通知 super.processMouseEvent(e_); } if( e_.getID() == MouseEvent.MOUSE_PRESSED ){ // 「押した」イベントで「離した」イベントを擬似発生 super.processMouseEvent( new MouseEvent( e_.getComponent() ,MouseEvent.MOUSE_RELEASED ,e_.getWhen() ,e_.getModifiers() ,e_.getX() ,e_.getY() ,e_.getClickCount() ,e_.isPopupTrigger() ) ); } } };
アプリケーションの修正はJButtonの代わりにHiJButtonを使うように 変更するのみですみます。
アプリケーションの例
「離すと動く」JButtonと「押すと動く」HiJButtonを使った単純な例を
示します。
ボタン2つと数字が並び、ボタンを押す/離すとビープ音を出し
数字がカウントupされます。
2種のボタンのクラス名が違う以外アプリケーション・コーディングは同じ
であり置き換え可能です。
(プログラムは実機能部とmain部に分けてあります) // BtnTstEngn.java:押すと動くボタンテスト、実機能クラス import javax.swing.*; import java.awt.*; import java.awt.event.*; public class BtnTstEngn implements ActionListener { int count; JLabel label; public void actionPerformed(ActionEvent e){ // ボタンが機能したら label.setText(Integer.toString(++count)); // カウントupする java.awt.Toolkit.getDefaultToolkit().beep();// ビープ音を出す } BtnTstEngn(JPanel pane_){ pane_.setLayout(new FlowLayout()); JButton _btn; pane_.add(_btn = new JButton("click-button")); // 「離す」ボタン _btn.addActionListener(this); pane_.add(_btn = new HiJButton("press-button"));// 「押す」ボタン _btn.addActionListener(this); pane_.add(label= new JLabel("0")); label.setPreferredSize(new Dimension(80,20)); label.setHorizontalAlignment(JLabel.RIGHT); } } // BtnTst:押すと動くボタンテストのmainプログラム import javax.swing.*; public class BtnTst extends JFrame { BtnTstEngn engn; BtnTst(String name_){ super(name_); engn=new BtnTstEngn((JPanel)getContentPane()); } public static void main(String[] args_){ BtnTst _btnTst= new BtnTst("Button-test"); _btnTst.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//必須! _btnTst.pack(); // 内部要素のサイズにする _btnTst.setVisible(true); // 表示する } }
Applet版の「mainプログラム」を以下に示します。(実機能部は前出の JAVA版と共通です)
// BtnTst:押すと動くボタンテストのAppletプログラム import javax.swing.*; public class BtnTstAplt extends JApplet { BtnTstEngn engn; public void init(){ engn=new BtnTstEngn((JPanel)getContentPane()); } }
アプリケーション(Applet版)
Applet版を載せます。
単に押すだけだとあまり差が分からないかもしれませんが、
マウスをすばやく動かしながら押すと、「click-button」の
方は時々機能しないことがあるはずです。
また、「タン・タタン」といったリズムですばやく押すと、
「click-button」の不自然さが分かるはずです。
次をクリックするとApplet版が動きます。
TIPs
実際のプログラムは色々な要素が絡みます。
今回の本筋ではない小技を説明しておきます。
- ウィンドウの[×]ボタン処理(必須)
[X]ボタンでexitする処理を入れないと、javaが資源を 持ったままに画面から消えてしまう場合があります。
通常、簡単なプログラムでは主画面のJFrameには次の設定 をする必要があります。(JFrame).setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- ウィンドウのサイズを数値指定しない方法
setSize(横サイズ,縦サイズ)で指定する代わりにpack()を使えば ウィンドウの内部要素によって大きさが決まります。
単純な試験プログラムの場合お勧めです。(JFrame).pack();
- 試験用の単純レイアウトのFrameにする
SwingのJFrameのデフォルトのレイアウトはBorderLayoutと なっています。
BorderLayoutでは要素をどんどんと追加することはできず、 試験向きではありません。(本番向きでもありませんけど)
試験用にはFlowLayoutを使います。(JPanel).setLayout(new FlowLayout());
- JLabelの大きさ・右寄せ/左寄せ
内容の変更があるJLabelは大きさを指定しておかないと、内容が 変わるたびに画面レイアウトが変わってしまいます。
大きさは次のように設定します。Dimension d= new Dimension(横サイズ,縦サイズ); (JLabel).setPreferredSize(d); // これだけでよい場合もある (JLabel).setMaximumSize(d); (JLabel).setMinimumSize(d);
本来は文字数指定ができるといいのですけどね。
なお、JLabelは大概の場合setPreferredSize(d)だけでよいのですが、 JPanelその他MaximunSize/MimimumSizeも指定しないとサイズ が変わらないものもありますので、通常この手続きをとった 方が安全です。
右寄せにするにはsetHorizontalAlignment(JLabel.RIGHT)を 使います。setAlignmentXといった関数やALIGNMENT_RIGHTなど 色々無効な指定が沢山ありますので間違わないよう
- ビープ音をならす
単純なビープ音(クリック音?)は次の1文で出すことができます。java.awt.Toolkit.getDefaultToolkit().beep();
- スタンドアロンJAVAとApplet
ほぼ絶滅状態のAppletですが、今回のような単純 サンプルを示すためには重宝します。
スタンドアロンJAVAプログラムをApplet化するには次の変更を 施します。- 主窓をJFrameでなくJAppletの派生にする
- 主窓でsuper()は呼ばない
- main()を無くしinit()で初期化する
- destroy()で終了処理
スレッド起動などを行っている場合destroyで停止する必要があります。 (本記事の例では不必要なため記述していません)
- HTMLにAppletを組み込む
jarに纏められたappletをHTMLに組み込むには次のような記述 をします。<applet code="BtnTstAplt" archive="BtnTst.jar" width=350 height=40> </applet>
ただ、Applet版は直接組み込まず、別HTMLにして、クリック時に 参照/起動される形にしておく必要があります。HTMLに直接記述 すると環境によってはブラウザが異常を起こします。
本記事も当初は直接記述していましたが、別HTML化しました。
- 拡張for文
今回は使っていませんが、ついでなのでメモしておきます。
拡張for文によるコンテナ要素アクセスです。実用的で優れた機能ですが センスの悪い記述形式です。iterator()メソッドでIterator<T>が 得られるコンテナクラスであればどんなクラスでも適用可能です。String[] a = new String[0]; ArrayList<String> al= new ArrayList<String>(); HashSet<String> hs= new HashSet<String>(); HashMap<String,Integer> hm= new HashMap<String,Integer>(); // なんだかんだ値セット for(String s:a) System.out.println(s); for(String s:al) System.out.println(s); for(String s:hs) System.out.println(s); for(String s:hm.keySet()) { System.out.println(s+":"+hm.get(s)); }
ダウンロード
プログラムを纏めて、BtnTstPrjct.lzhに置きました。
展開するとBtnTstPrjctフォルダと、その下にプログラムファイル および幾つかのバッチファイルができます。BtnTst_mk.batでコンパイルされ、BtnTst.jarが作成されます。 BtnTst.jarは実行可能なjarファイルです。
BtnTstAplt.htmでappletを動かすことができます。
clean.batで*.classが消去されます。
cleanAll.batでjarファイルも含む二次生成ファイルが削除されます。
| 固定リンク