Java Swing FocusTraversalPolicy问题

Java Swing FocusTraversalPolicy Issue

我目前在实现FocusTraversalPolicy时遇到问题。

我想使用Tab / Shift+Tab键盘快捷键来浏览上下/左右。填写表格时,这将使导航更简单。

该策略应仅影响JFramemainPanel中的所有元素。

我已经使用以下类别实施了该政策:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
public class DefaultViewFocusTraversalPolicy
        extends FocusTraversalPolicy
{
   ArrayList<Component> order;

   public DefaultViewFocusTraversalPolicy(ArrayList<Component> order)
   {
      this.order = order;
   }

   @Override
   public Component getComponentAfter(Container aContainer, Component aComponent)
   {
      int index = (order.indexOf(aComponent) + 1) % order.size();
      Component after = order.get(index);
      while (index < order.size() && !(after.isEnabled() && after.isVisible()))
      {
         index++;
         after = order.get(index);
      }
      return after;
   }

   @Override
   public Component getComponentBefore(Container aContainer, Component aComponent)
   {
      int index = order.indexOf(aComponent) - 1;
      if (index < 0)
      {
         index = order.size() - 1;
      }
      Component before = order.get(index);
      while (index >= 0 && !(before.isEnabled() && before.isVisible()))
      {
         index--;
         before = order.get(index);
      }
      return before;
   }

   @Override
   public Component getFirstComponent(Container aContainer)
   {
      int index = 0;
      Component first = order.get(index);
      while (index < order.size() && !(first.isEnabled() && first.isVisible()))
      {
         index++;
         first = order.get(index);
      }
      return first;
   }

   @Override
   public Component getLastComponent(Container aContainer)
   {
      int index = order.size() - 1;
      Component last = order.get(index);
      while (index >= 0 && !(last.isEnabled() && last.isVisible()))
      {
         index--;
         last = order.get(index);
      }
      return last;
   }

   @Override
   public Component getDefaultComponent(Container aContainer)
   {
      return getFirstComponent(aContainer);
   }
}

然后,在我的视图的构造函数(例如main JFrame)中使用以下实例化该类:

1
2
3
4
5
6
7
ArrayList<Component> order = new ArrayList<>();
order.add(this.ecmID);
order.add(this.modeID);
// ...
DefaultViewFocusTraversalPolicy policy =
        new DefaultViewFocusTraversalPolicy(order);
this.mainPanel.setFocusTraversalPolicy(policy);

但是,当我尝试使用Tab键浏览元素时,没有任何变化,并且以前的策略仍然存在。我已经尝试过Java教程:link

任何帮助将不胜感激。


我不确定您为什么还要为您的案例扩展FocusTraversalPolicy,而默认FocusTraversalPolicy应该为您完成这项工作。

但是,您需要设置this.mainPanel.setFocusCycleRoot(true):它设置此Container是否为焦点遍历循环的根。焦点进入遍历周期后,通常除非按下向上或向下周期键之一,否则无法通过焦点遍历离开焦点。正常遍历仅限于此Container,并且该Container的所有后代都不是下聚焦周期根的后代。

您可以查看ContainerOrderFocusTraversalPolicy

  • 根据以下顺序确定遍历顺序:Container.getComponents()返回
  • 该策略从特定焦点循环的根开始对Component层次结构进行预遍历。
  • 它具有一个不错的功能:boolean accept(Component aComponent):确定组件是否可以作为新的焦点所有者被接受。只需通过扩展此类来覆盖此功能,并使用您不想关注的Container对应组件列表即可。无需重写所有功能并实现它们。


    1
    ArrayList<Component> order = new ArrayList<>();

    我认为您正在寻找

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    import java.awt.Component;
    import java.awt.Container;
    import java.awt.FocusTraversalPolicy;
    import java.awt.GridLayout;
    import java.awt.KeyEventDispatcher;
    import java.awt.KeyboardFocusManager;
    import java.awt.event.KeyEvent;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JTextField;
    import javax.swing.SwingUtilities;

    public class Testing {

        private static final long serialVersionUID = 1L;
        private Component[] focusList;
        private int focusNumber = 0;
        private JFrame frame;

        public Testing() {
            JTextField tf1 = new JTextField(5);
            tf1.setName("tf1");
            JTextField tf2 = new JTextField(5);
            tf2.setName("tf2");
            JTextField tf3 = new JTextField(5);
            tf3.setName("tf3");
            JButton b1 = new JButton("B1");
            b1.setName("b1");
            JButton b2 = new JButton("B2");
            b2.setName("b2");
            tf2.setEnabled(false);
            focusList = new Component[]{tf1, b1, tf2, b2, tf3};
            JPanel panel = new JPanel(new GridLayout(5, 1));
            panel.add(tf1);
            panel.add(b1);
            panel.add(tf2);
            panel.add(b2);
            panel.add(tf3);
            frame = new JFrame();
            frame.setFocusTraversalPolicy(new MyFocusTraversalPolicy());
            frame.add(panel);
            frame.pack();
            frame.setLocation(150, 100);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);
            KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new KeyEventDispatcher() {
                @Override
                public boolean dispatchKeyEvent(KeyEvent ke) {
                    if (ke.getID() == KeyEvent.KEY_PRESSED) {
                        if (ke.getKeyCode() == KeyEvent.VK_TAB) {
                            Component comp = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
                            System.out.println(comp.getName());
                            if (comp.isEnabled() == false) {
                                if (ke.isShiftDown()) {
                                    KeyboardFocusManager.getCurrentKeyboardFocusManager().focusPreviousComponent();
                                } else {
                                    KeyboardFocusManager.getCurrentKeyboardFocusManager().focusNextComponent();
                                }
                            }
                        }
                    }
                    return false;
                }
            });
        }

        private class MyFocusTraversalPolicy extends FocusTraversalPolicy {

            @Override
            public Component getComponentAfter(Container focusCycleRoot, Component aComponent) {
                focusNumber = (focusNumber + 1) % focusList.length;
                return focusList[focusNumber];
            }

            @Override
            public Component getComponentBefore(Container focusCycleRoot, Component aComponent) {
                focusNumber = (focusList.length + focusNumber - 1) % focusList.length;
                return focusList[focusNumber];
            }

            @Override
            public Component getDefaultComponent(Container focusCycleRoot) {
                return focusList[0];
            }

            @Override
            public Component getLastComponent(Container focusCycleRoot) {
                return focusList[focusList.length - 1];
            }

            @Override
            public Component getFirstComponent(Container focusCycleRoot) {
                return focusList[0];
            }
        }

        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    Testing testing = new Testing();
                }
            });
        }
    }