▼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ファイルも含む二次生成ファイルが削除されます。
| 固定リンク

