Swing/InputVerifierFocusOrder の変更点
- 追加された行はこの色です。
- 削除された行はこの色です。
- Swing/InputVerifierFocusOrder へ行く。
- Swing/InputVerifierFocusOrder の差分を削除
--- category: swing folder: InputVerifierFocusOrder title: InputVerifierを設定したコンポーネントのフォーカスナビゲーションをテストする tags: [JTextField, InputVerifier, FocusTraversalPolicy, FocusListener] author: aterai pubdate: 2016-08-15T02:09:37+09:00 description: InputVerifierを設定したコンポーネントの入力の検証とフォーカス移動イベントの順番をテストします。 image: https://drive.google.com/uc?id=19ojUQl6rF4StwHNdQO_xPRlqnkOognwULw --- * 概要 [#summary] `InputVerifier`を設定したコンポーネントの入力の検証とフォーカス移動イベントの順番をテストします。 #download(https://drive.google.com/uc?id=19ojUQl6rF4StwHNdQO_xPRlqnkOognwULw) * サンプルコード [#sourcecode] #code(link){{ JTextField textField = new JTextField(24); textField.setInputVerifier(new InputVerifier() { @Override public boolean verify(JComponent c) { if (c instanceof JTextComponent) { JTextComponent tc = (JTextComponent) c; String str = tc.getText().trim(); return !str.isEmpty() && MAX_LEN - str.length() >= 0; } return false; } @Override public boolean shouldYieldFocus(JComponent input) { System.out.println("shouldYieldFocus"); if (isAllValid()) { button.setEnabled(true); // EventQueue.invokeLater(() -> button.requestFocusInWindow()); } else { button.setEnabled(false); } return super.shouldYieldFocus(input); } }); setFocusTraversalPolicy(new LayoutFocusTraversalPolicy() { @Override public Component getComponentAfter( Container focusCycleRoot, Component aComponent) { System.out.println("getComponentAfter"); button.setEnabled(isAllValid()); return super.getComponentAfter(focusCycleRoot, aComponent); } @Override public Component getComponentBefore( Container focusCycleRoot, Component aComponent) { System.out.println("getComponentAfter"); button.setEnabled(isAllValid()); return super.getComponentBefore(focusCycleRoot, aComponent); } }); setFocusCycleRoot(true); }} * 解説 [#explanation] 上記のサンプルでは、パネル内の`JTextField`がすべて入力検証に成功した場合、`JButton`をクリック可能に更新する`UI`のテストを行っています。 - KBD{Tab}キーを押してフォーカス移動するとき、すべての`JTextField`がすべて入力検証に成功する場合は、`JButton`をクリック可能に更新し、`JButton`にフォーカスを移動し、すぐにKBD{Space}キーなどでクリックしたい - `InputVerifier#shouldYieldFocus(...)`や`FocusListener#focusLost(...)`で、`JButton#setEnabled(true)`としても、フォーカスは`JButton`に移動しない(初めて`JButton`がクリック可能になったときは、先頭の`JCheckBox`にフォーカスが移動する) -- これらの実行より先に`LayoutFocusTraversalPolicy#getComponentAfter(...)`で、次にフォーカスが移動するコンポーネントが決定されるため、この時点で`JButton#setEnabled(true)`になっていない`JButton`はスキップされる - KBD{Tab}キーを押してフォーカス移動するときすべての`JTextField`がすべて入力検証に成功する場合は、`JButton`をクリック可能に更新、`JButton`にフォーカスを移動、直後にKBD{Space}キーなどでクリックしたい - `InputVerifier#shouldYieldFocus(...)`や`FocusListener#focusLost(...)`で`JButton#setEnabled(true)`としても、フォーカスは`JButton`に移動しない(初めて`JButton`がクリック可能になったときは先頭の`JCheckBox`にフォーカスが移動する) -- これらの実行より先に`LayoutFocusTraversalPolicy#getComponentAfter(...)`で次にフォーカスが移動するコンポーネントが決定されるため、この時点で`JButton#setEnabled(true)`になっていない`JButton`はスキップされる - 回避方法: -- `InputVerifier#shouldYieldFocus(...)`や`FocusListener#focusLost(...)`内で`EventQueue.invokeLater(() -> button.requestFocusInWindow() );`などを実行し、一番後でフォーカスを強制的に`JButton`に移動する -- または、`LayoutFocusTraversalPolicy#getComponentAfter(...)`をオーバーライドして、事前に`JButton#setEnabled(true)`を実行する -- または`LayoutFocusTraversalPolicy#getComponentAfter(...)`をオーバーライドして事前に`JButton#setEnabled(true)`を実行する * 参考リンク [#reference] - [https://docs.oracle.com/javase/jp/8/docs/api/javax/swing/InputVerifier.html#shouldYieldFocus-javax.swing.JComponent- InputVerifier#shouldYieldFocus(JComponent) (Java Platform SE 8)] * コメント [#comment] #comment #comment