Reputation: 2483
I'm currently having an issue with implementing a FocusTraversalPolicy
.
I would like for the Tab
/Shift+Tab
keyboard shortcuts to allow for navigating top-bottom/left-right. This will allow for simpler navigation when filling in a form.
The policy should only impact all elements in the mainPanel
of my JFrame
.
I have implemented the policy using the following class:
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);
}
}
I then instantiate the class with the following inside the constructor of my view (e.g. main JFrame
):
ArrayList<Component> order = new ArrayList<>();
order.add(this.ecmID);
order.add(this.modeID);
// ...
DefaultViewFocusTraversalPolicy policy =
new DefaultViewFocusTraversalPolicy(order);
this.mainPanel.setFocusTraversalPolicy(policy);
However, when I try to Tab through the elements, nothing has changed and the previous policy is still in place. I've already tried going through the Java tutorial: link
Any help would be much appreciated.
Upvotes: 0
Views: 5558
Reputation: 15418
I am not sure why you are even extending the FocusTraversalPolicy
for your case while default FocusTraversalPolicy
should do the job for you.
However, you need to set this.mainPanel.setFocusCycleRoot(true)
: which sets whether this Container is the root of a focus traversal cycle. Once focus enters a traversal cycle, typically it cannot leave it via focus traversal unless one of the up- or down-cycle keys is pressed. Normal traversal is limited to this Container, and all of this Container's descendants that are not descendants of inferior focus cycle roots.
You can look into the ContainerOrderFocusTraversalPolicy
:
Container.getComponents()
It has a nice function: boolean accept(Component aComponent)
: Determines whether a Component is an acceptable choice as the new focus owner. just override this function by extending this class, with your corresponding component list you don't want to be focused of the Container
. No need to override all of the function and implement them.
Upvotes: 3
Reputation: 109813
ArrayList<Component> order = new ArrayList<>();
I think that you looking for
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();
}
});
}
}
Upvotes: 1