ラジオボタン(固定された選択肢の中から1つを選ぶ)はSwingではJRadioButtonクラスを使う。
1つのラジオボタンにつき1つのJRadioButtonインスタンスを用意し、選択肢としてのグルーピングはButtonGroupに登録することで管理される。
|
import javax.swing.ButtonGroup; import javax.swing.JRadioButton;
/** * ラジオボタン・グループの初期化 */ private void initPane(Container c) { JRadioButton r1 = new JRadioButton("選択肢1"); JRadioButton r2 = new JRadioButton("選択肢2"); JRadioButton r3 = new JRadioButton("選択肢3"); // ボタングループへの登録 ButtonGroup bg = new ButtonGroup(); bg.add(r1); bg.add(r2); bg.add(r3); // ラジオボタンの表示 c.setLayout(new FlowLayout()); c.add(r1); c.add(r2); c.add(r3); }
ButtonGroup自体はJComponent等のコンポーネントではないので、表示したりするものではない。
デフォルトでは、マウスで選択肢をクリックした場合やスペースキーを押した場合に選択されている選択肢が移動する。
他のアプリではカーソルキーを押すことで選択肢が移動できるものがあるが、その動作を行うには独自実装する必要がある。
各ラジオボタンのキーイベントでカーソルキーの押下を捕捉し、新しいラジオボタンを選択状態に変えればよい。
グループに所属しているラジオボタンの一覧はボタングループが保持しているので、新しいラジオボタンを探すのはそちらでないと出来ない。
選択状態に変えるにはボタンのsetSelected(true)を呼べばよい。(これで、以前の選択肢は選択解除される。)
ただし、これだけではフォーカスは移らないので、別途フォーカスも移しておかないと変になる。
class MyButtonGroup extends ButtonGroup implements KeyListener { @Override public void add(AbstractButton b) { super.add(b); b.removeKeyListener(this); b.addKeyListener(this); } @Override public void remove(AbstractButton b) { b.removeKeyListener(this); super.remove(b); }
@Override public void keyPressed(KeyEvent e) { int size = buttons.size(); //グループに登録されているボタンの個数 if (size <= 0) { return; } int z; switch (e.getKeyCode()) { case KeyEvent.VK_UP: case KeyEvent.VK_LEFT: z = size - 1; break; case KeyEvent.VK_DOWN: case KeyEvent.VK_RIGHT: z = +1; break; default: return; } AbstractButton b = (AbstractButton) e.getSource(); //カーソルキーが押された際にフォーカスのあったラジオボタン for (int i = 0; i < size; i++) { if (buttons.get(i) == b) { int n = (i + z) % size; AbstractButton nb = buttons.get(n); //新しいラジオボタン nb.setSelected(true); //選択状態に変える nb.requestFocusInWindow(); //フォーカスを移す e.consume(); return; } } } @Override public void keyReleased(KeyEvent e) { } @Override public void keyTyped(KeyEvent e) { } }
上記のロジックは、インデックスの増分を変数zで保持している。
マイナス方向の場合、単純に-1とすると、「加算したインデックスが負の数になった場合の処理」を別途入れる必要が出てくる。
そこで増分を「size - 1」にして、新しいインデックスは「増分加算後にsizeで割った余り」にすると、特別なロジックは不要になる。
例えばインデックスが1だったら「(1 + size - 1) % size」で余りは0、インデックスが0だったら「(0 + size - 1) %
size」で余りはsize-1となる。
増分が+1でも全く同じ計算式で問題ない。
これはMSX-BASIC時代の定番アルゴリズム(方角(上が0で右上が1、右が2、…、左上が7)を1ずつずらす)そのもの。