JComboBoxへのフォーカス移動がInputVerifierの検証で拒否されたらドロップダウンリスト表示をキャンセルする
Total: 1004
, Today: 1
, Yesterday: 1
Posted by aterai at
Last-modified:
概要
JComboBox
へのマウスクリックによるフォーカス移動が別コンポーネントに設定されているInputVerifier
の検証で拒否された場合、そのドロップダウンリストの表示をキャンセルします。
Screenshot
Advertisement
サンプルコード
class BasicComboPopup2 extends BasicComboPopup {
private transient MouseListener handler2;
@Override public void uninstallingUI() {
super.uninstallingUI();
handler2 = null;
}
// Java 9: protected BasicComboPopup2(JComboBox<Object> combo) {
protected BasicComboPopup2(JComboBox<?> combo) {
super(combo);
}
@Override protected MouseListener createMouseListener() {
if (Objects.isNull(handler2)) {
handler2 = new Handler2();
}
return handler2;
}
private class Handler2 extends MouseAdapter {
@Override public void mousePressed(MouseEvent e) {
if (!SwingUtilities.isLeftMouseButton(e) || !comboBox.isEnabled()) {
return;
}
boolean hasFocus = true;
if (comboBox.isEditable()) {
Component comp = comboBox.getEditor().getEditorComponent();
if (!(comp instanceof JComponent) || ((JComponent) comp).isRequestFocusEnabled()) {
hasFocus = comp.hasFocus() || comp.requestFocusInWindow();
}
} else if (comboBox.isRequestFocusEnabled()) {
hasFocus = comboBox.hasFocus() || comboBox.requestFocusInWindow();
}
Component c = e.getComponent();
if (!hasFocus && c instanceof AbstractButton) {
((AbstractButton) c).getModel().setPressed(false);
}
if (hasFocus) {
togglePopup();
}
}
@Override public void mouseReleased(MouseEvent e) {
Component source = (Component) e.getSource();
Dimension size = source.getSize();
Rectangle bounds = new Rectangle(0, 0, size.width - 1, size.height - 1);
if (!bounds.contains(e.getPoint())) {
MouseEvent newEvent = SwingUtilities.convertMouseEvent(e.getComponent(), e, list);
Point location = newEvent.getPoint();
Rectangle r = new Rectangle();
list.computeVisibleRect(r);
if (r.contains(location)) {
if (comboBox.getSelectedIndex() == list.getSelectedIndex()) {
comboBox.getEditor().setItem(list.getSelectedValue());
}
comboBox.setSelectedIndex(list.getSelectedIndex());
}
comboBox.setPopupVisible(false);
}
hasEntered = false;
stopAutoScrolling();
}
}
}
View in GitHub: Java, Kotlin解説
InputVerifier
JTextField
に少なくとも5
文字以上の入力が必要なInputVerifier
を設定5
文字以下の場合は他のコンポーネントへのフォーカス移動が不可となる
Default
Default
の編集不可JComboBox
はInputVerifier
でフォーカス移動が拒否されていてもクリックするとドロップダウンリストが表示される
setFocusable(false)
setFocusable(false)
を設定した編集不可JComboBox
はフォーカス移動前のInputVerifier
による検証は実行されないsetFocusable(false)
が設定されていてもJComboBox
をクリックしてドロップダウンリストを表示することは可能
setEditable(true)
Default
の編集可JComboBox
はInputVerifier
でフォーカス移動が拒否されてもArrowButton
クリックするとドロップダウンリストが表示されるComboBoxEditor
がクリックされた場合はフォーカス移動が拒否されるとドロップダウンリスト表示もキャンセルされる
Override BasicComboPopup
BasicComboPopup
でmousePressed
が実行されたときrequestFocus()
の戻り値が無視されているので、この戻り値がフォーカス変更要求が確実に失敗する場合(InputVerifier
の検証で拒否されるなど)のfalse
ならBasicComboPopup#togglePopup()
を実行しないよう修正ArrowButton
がクリックされた場合はその選択状態描画が残る場合がある?のでドロップダウンリストの表示がキャンセルされた場合はJButton#getModel()#setPressed(false)
で選択状態をクリア
参考リンク
- How to Use the Focus Subsystem (The Java™ Tutorials > Creating a GUI With Swing > Using Other Swing Features)
- java - Prevent a JComboBox popup from appearing. Passing InputVerifier - Stack Overflow
PopupMenuListener
をJComboBox
に設定してInputVerifier
でフォーカス移動が拒否されたらドロップダウンリスト表示をキャンセルする方法もある
- JPopupMenuを開く前に対象となるJTextFieldにFocusを移動する
- ComboBoxEditorにJLayerを設定し入力の妥当性を表示する
- [JDK-8285698] Create a test to check the focus stealing of JPopupMenu from JComboBox - Java Bug System