How to define the order in which the components will receive focus through the TAB?

7

To organize the focus order of the components up to version 1.4 of java, we used the setNextFocusableComponent() ". However, it was discontinued as of the cited version.

I would like to know how I can do this in the latest versions so that I can control the focus order of components on the screen with the TAB key. For example, the code below has 4 distinct components, and they get focus on the order they were added on the screen:

import java.awt.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;

public class NextFocusTest extends JFrame {

    private static final long serialVersionUID = 1L;
    private JPanel contentPane;
    private JPanel panel;
    private JTextField firstComp;
    private JComboBox<String> thirdComp;
    private JTextField secondComp;
    private JButton fourthComp;

    public static void main(String[] args) {
        EventQueue.invokeLater(() -> {
            NextFocusTest frame = new NextFocusTest();
            frame.setVisible(true);
        });
    }

    public NextFocusTest() {
        initComponents();
    }

    private void initComponents() {

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setPreferredSize(new Dimension(350, 200));
        this.contentPane = new JPanel();
        this.contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        this.contentPane.setLayout(new BorderLayout(0, 0));
        setContentPane(this.contentPane);

        this.panel = new JPanel();
        this.panel.setBorder(new EmptyBorder(0, 20, 0, 20));
        this.panel.setLayout(new GridLayout(2, 2, 20, 5));
        this.contentPane.add(this.panel, BorderLayout.NORTH);

        this.firstComp = new JTextField();
        this.firstComp.setPreferredSize(new Dimension(100, 20));
        this.panel.add(this.firstComp);

        this.thirdComp = new JComboBox<String>();
        this.thirdComp.setModel(new DefaultComboBoxModel<String>(new String[] { "teste 1", "teste 2", "teste 3" }));
        this.thirdComp.setPreferredSize(new Dimension(100, 20));
        this.panel.add(this.thirdComp);

        this.secondComp = new JTextField();
        this.secondComp.setPreferredSize(new Dimension(100, 20));
        this.panel.add(this.secondComp);

        this.fourthComp = new JButton("OK");
        this.fourthComp.setPreferredSize(new Dimension(90, 23));
        this.panel.add(this.fourthComp);

        pack();
    }
}

Switching focus with TAB :

How do I manually set the focus order of the components, for example by following the order below?

  • first text field
  • second text field
  • combobox
  • button
asked by anonymous 11.09.2017 / 14:00

1 answer

4

Use the FocusTraversalPolicy class to set the order of focus of the components of a container . To do so, extend the FocusTraversalPolicy class, implement the focus policy, and assign using setFocusTraversalPolicy . The code based on your example would look something like this:

import java.awt.*;
import java.util.LinkedList;
import javax.swing.*;
import javax.swing.border.EmptyBorder;

public class NextFocusTest extends JFrame {

  private static final long serialVersionUID = 1L;
  private JPanel contentPane;
  private JPanel panel;
  private JTextField firstComp;
  private JComboBox<String> thirdComp;
  private JTextField secondComp;
  private JButton fourthComp;

  public static void main(String[] args) {
    EventQueue.invokeLater(() -> {
      NextFocusTest frame = new NextFocusTest();
      frame.setVisible(true);
    });
  }

  public NextFocusTest() {
    initComponents();
  }

  private void initComponents() {

    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setPreferredSize(new Dimension(350, 200));
    this.contentPane = new JPanel();
    this.contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
    this.contentPane.setLayout(new BorderLayout(0, 0));
    setContentPane(this.contentPane);

    this.panel = new JPanel();
    this.panel.setBorder(new EmptyBorder(0, 20, 0, 20));
    this.panel.setLayout(new GridLayout(2, 2, 20, 5));
    this.contentPane.add(this.panel, BorderLayout.NORTH);

    this.firstComp = new JTextField();
    this.firstComp.setPreferredSize(new Dimension(100, 20));
    this.panel.add(this.firstComp);

    this.thirdComp = new JComboBox<>();
    this.thirdComp.setModel(new DefaultComboBoxModel<String>(new String[]{"teste 1", "teste 2", "teste 3"}));
    this.thirdComp.setPreferredSize(new Dimension(100, 20));
    this.panel.add(this.thirdComp);

    this.secondComp = new JTextField();
    this.secondComp.setPreferredSize(new Dimension(100, 20));
    this.panel.add(this.secondComp);

    this.fourthComp = new JButton("OK");
    this.fourthComp.setPreferredSize(new Dimension(90, 23));
    this.panel.add(this.fourthComp);

    pack();
    setFocusTraversalPolicy(new PoliticaFoco());
  }

  class PoliticaFoco extends FocusTraversalPolicy {

    private final java.util.List<Component> componentes;
    private int focado = 0;

    public PoliticaFoco() {
      this.componentes = new LinkedList<>();
      this.componentes.add(thirdComp);
      this.componentes.add(firstComp);
      this.componentes.add(fourthComp);
      this.componentes.add(secondComp);
    }

    @Override
    public Component getComponentAfter(Container focusCycleRoot, Component aComponent) {
      this.focado = (this.focado + 1) % this.componentes.size();

      return this.componentes.get(focado);
    }

    @Override
    public Component getComponentBefore(Container focusCycleRoot, Component aComponent) {
      this.focado = (this.componentes.size() + this.focado - 1) % this.componentes.size();

      return this.componentes.get(focado);
    }

    @Override
    public Component getDefaultComponent(Container focusCycleRoot) {
      return this.componentes.get(0);
    }

    @Override
    public Component getLastComponent(Container focusCycleRoot) {
      return this.componentes.get(this.componentes.size() - 1);
    }

    @Override
    public Component getFirstComponent(Container focusCycleRoot) {
      return this.componentes.get(0);
    }
  }
}

In the implementation of FocusTraversalPolicy , we implement the methods getComponentAfter , getComponentBefore , getDefaultComponent and getLastComponent that determine the component that will receive the focus in each of the situations. To control the order I used a List that receives the components in order to control the focus. The disadvantage is that, for each component added, it will also be necessary to include it in the implemented class.

You can also create the generic focus policy, as follows:

import java.awt.Component;
import java.awt.Container;
import java.awt.FocusTraversalPolicy;
import java.util.LinkedList;

public class PoliticaFocoGenerica extends FocusTraversalPolicy {

  protected final java.util.List<Component> componentes = new LinkedList<>();
  private int focado = 0;

  @Override
  public Component getComponentAfter(Container focusCycleRoot, Component aComponent) {
    this.focado = (this.focado + 1) % this.componentes.size();

    return this.componentes.get(focado);
  }

  @Override
  public Component getComponentBefore(Container focusCycleRoot, Component aComponent) {
    this.focado = (this.componentes.size() + this.focado - 1) % this.componentes.size();

    return this.componentes.get(focado);
  }

  @Override
  public Component getDefaultComponent(Container focusCycleRoot) {
    return this.componentes.get(0);
  }

  @Override
  public Component getLastComponent(Container focusCycleRoot) {
    return this.componentes.get(this.componentes.size() - 1);
  }

  @Override
  public Component getFirstComponent(Container focusCycleRoot) {
    return this.componentes.get(0);
  }
}

Only by defining the components in their respective orders, as follows:

class PoliticaFoco extends PoliticaFocoGenerica {

  public PoliticaFoco() {
    this.componentes.add(thirdComp);
    this.componentes.add(firstComp);
    this.componentes.add(fourthComp);
    this.componentes.add(secondComp);
  }
}

And in its container :

...
setFocusTraversalPolicy(new PoliticaFoco());
...
    
11.09.2017 / 14:24