简体   繁体   中英

How to across JTextField to next JTextField by hit Enter

When select check box to set enable(false) on second text field and hit enter need to focus at third text field
if not select any check box then hit ENTER it can be focus on text field as flow. I should add any code or how can I make it work

My GUI:

https://i.stack.imgur.com/sE997.png

private void chk1ActionPerformed(java.awt.event.ActionEvent evt) {                                     
    // Set action perform for check box:
    if(chk1.isSelected()){
        p1.setEnabled(false);
    } else{
        p1.setEnabled(true);
    }
}

private void chk2ActionPerformed(java.awt.event.ActionEvent evt) {                                     
    // Set action perform for check box:
    if(chk2.isSelected()){
        p2.setEnabled(false);
    } else{
        p2.setEnabled(true);
    }
}

private void chk3ActionPerformed(java.awt.event.ActionEvent evt) {                                     
    // Set action perform for check box:
    if(chk3.isSelected()){
        p3.setEnabled(false);
    } else{
        p3.setEnabled(true);
    }
} 

private void p_numKeyPressed(java.awt.event.KeyEvent evt) {                                 
    // TODO add your handling code here:
    if(evt.getKeyCode()==KeyEvent.VK_ENTER){
        p1.requestFocus();
    }
}

private void p1KeyPressed(java.awt.event.KeyEvent evt) {                                 
    // TODO add your handling code here:
    if(evt.getKeyCode()==KeyEvent.VK_ENTER){
        p2.requestFocus();
    }
}

private void p2KeyPressed(java.awt.event.KeyEvent evt) {                                 
    // TODO add your handling code here:
    if(evt.getKeyCode()==KeyEvent.VK_ENTER){
        p3.requestFocus();
    }
}

I think what you are looking for isthe Focus Subsystem . This is responsible for the order in which components are getting focus when you press a focus traversal key. For example you can define what is the order of the components to get focus, and also add the check to transfer focus only to enabled components. What you also seem to want to do is to add the ENTER key as a focus traversal key (ie when pressing it, the focus will be transfered to another component - according to the current focus traversal policy). All this can be done via the focus subsystem.

The following code seems to do what you are asking, by utilizing the focus subsystem:

import java.awt.Component;
import java.awt.Container;
import java.awt.DefaultFocusTraversalPolicy;
import java.awt.GridLayout;
import java.awt.KeyboardFocusManager;
import java.awt.event.KeyEvent;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;

public class FocusHopSystem {
    
    public static class AbsoluteFocusTraversalPolicy extends DefaultFocusTraversalPolicy {
        private final Component[] comps;
        
        public AbsoluteFocusTraversalPolicy(final Component... comps) {
            this.comps = comps.clone();
        }
        
        private int indexOf(final Component comp) {
            for (int i = 0; i < comps.length; ++i)
                if (comps[i] == comp)
                    return i;
            return -1;
        }

        @Override
        public Component getComponentAfter(final Container aContainer, final Component aComponent) {
            final int aIndex = indexOf(aComponent);
            if (aIndex < 0)
                return null;
            for (int i = 1; i < comps.length; ++i) {
                final Component after = comps[(aIndex + i) % comps.length];
                if (after != null && after.isDisplayable() && after.isVisible() && after.isEnabled())
                    return after;
            }
            return null;
        }

        @Override
        public Component getComponentBefore(final Container aContainer, final Component aComponent) {
            final int aIndex = indexOf(aComponent);
            if (aIndex < 0)
                return null;
            for (int i = 1; i < comps.length; ++i) {
                final Component before = comps[(aIndex - i + comps.length) % comps.length];
                if (before != null && before.isDisplayable() && before.isVisible() && before.isEnabled())
                    return before;
            }
            return null;
        }

        @Override
        public Component getFirstComponent(final Container aContainer) {
            for (int i = 0; i < comps.length; ++i) {
                final Component first = comps[i];
                if (first != null && first.isDisplayable() && first.isVisible() && first.isEnabled())
                    return first;
            }
            return null;
        }

        @Override
        public Component getLastComponent(final Container aContainer) {
            for (int i = comps.length - 1; i >= 0; --i) {
                final Component last = comps[i];
                if (last != null && last.isDisplayable() && last.isVisible() && last.isEnabled())
                    return last;
            }
            return null;
        }

        @Override
        public Component getDefaultComponent(final Container aContainer) {
            return getFirstComponent(aContainer);
        }
    }
    
    private static void createAndShowGUI() {
        final String text = "0";
        final int width = 12;
        
        final JTextField tf1 = new JTextField(text, width),
                         tf2 = new JTextField(text, width),
                         tf3 = new JTextField(text, width),
                         tf4 = new JTextField(text, width);
        
        final JCheckBox ck2 = new JCheckBox("jTextField2", true),
                        ck3 = new JCheckBox("jTextField3", true),
                        ck4 = new JCheckBox("jTextField4", true);
        
        final JButton save = new JButton("Save");
        
        ck2.addActionListener(e -> tf2.setEnabled(ck2.isSelected()));
        ck3.addActionListener(e -> tf3.setEnabled(ck3.isSelected()));
        ck4.addActionListener(e -> tf4.setEnabled(ck4.isSelected()));
        
        final JPanel frameContents = new JPanel(new GridLayout(0, 5, 5, 5));
        
        //First row:
        frameContents.add(new JPanel());
        frameContents.add(ck2);
        frameContents.add(ck3);
        frameContents.add(ck4);
        frameContents.add(new JPanel());
        
        //Second row:
        frameContents.add(tf1);
        frameContents.add(tf2);
        frameContents.add(tf3);
        frameContents.add(tf4);
        frameContents.add(save);
        
        //Make the other components unfocusable:
        for (final Component comp: new Component[]{ck2, ck3, ck4, save})
            comp.setFocusable(false);
        
        //Make frameContents the focus cycle root:
        frameContents.setFocusCycleRoot(true);
        
        //Install our FocusTraversalPolicy to the cycle root:
        frameContents.setFocusTraversalPolicy(new AbsoluteFocusTraversalPolicy(tf1, tf2, tf3, tf4));
        
        //Add KeyEvent.VK_ENTER key to the focus traversal keys of the frameContents:
        final Set forwardKeys = frameContents.getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
        final Set newForwardKeys = new HashSet(forwardKeys);
        newForwardKeys.add(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0));
        frameContents.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, newForwardKeys);
        
        final JFrame frame = new JFrame("Focus traversal test.");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(frameContents);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        
        //Start focus on the first text field:
        tf1.requestFocusInWindow();
    }
    
    public static void main(final String[] args) {
        SwingUtilities.invokeLater(FocusHopSystem::createAndShowGUI);
    }
}

In the above example, I am adding the key ENTER as an alternative focus traversal key, aside from TAB .

Edit 1: It's even simpler...

As I found out, it's even simpler than the first sample code, and that's because the default focus traversal policy does what you are asking, ie allows only focusable-and-enabled components to gain focus and in the desired order. So we only need to make the unneeded components to non-focusable (ie the check-boxes and the button) and leave enabled the text-fields. Just add/set the ENTER key as a focus traversal key and you are good to go:

import java.awt.Component;
import java.awt.GridLayout;
import java.awt.KeyboardFocusManager;
import java.awt.event.KeyEvent;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;

public class FocusHopSystem2 {
    
    private static void createAndShowGUI() {
        final String text = "0";
        final int width = 12;
        
        final JTextField tf1 = new JTextField(text, width),
                         tf2 = new JTextField(text, width),
                         tf3 = new JTextField(text, width),
                         tf4 = new JTextField(text, width);
        
        final JCheckBox ck2 = new JCheckBox("jTextField2", true),
                        ck3 = new JCheckBox("jTextField3", true),
                        ck4 = new JCheckBox("jTextField4", true);
        
        final JButton save = new JButton("Save");
        
        ck2.addActionListener(e -> tf2.setEnabled(ck2.isSelected()));
        ck3.addActionListener(e -> tf3.setEnabled(ck3.isSelected()));
        ck4.addActionListener(e -> tf4.setEnabled(ck4.isSelected()));
        
        final JPanel frameContents = new JPanel(new GridLayout(0, 5, 5, 5));
        
        //First row:
        frameContents.add(new JPanel());
        frameContents.add(ck2);
        frameContents.add(ck3);
        frameContents.add(ck4);
        frameContents.add(new JPanel());
        
        //Second row:
        frameContents.add(tf1);
        frameContents.add(tf2);
        frameContents.add(tf3);
        frameContents.add(tf4);
        frameContents.add(save);
        
        //Make the other components unfocusable:
        for (final Component comp: new Component[]{ck2, ck3, ck4, save})
            comp.setFocusable(false);
        
        //Make frameContents the focus cycle root:
        frameContents.setFocusCycleRoot(true);
        
        ////Install the DefaultFocusTraversalPolicy to the cycle root:
        //frameContents.setFocusTraversalPolicy(new DefaultFocusTraversalPolicy()); //This is not necessary in this case.
        
        //Add KeyEvent.VK_ENTER key to the focus traversal keys of the frameContents:
        final Set forwardKeys = frameContents.getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
        final Set newForwardKeys = new HashSet(forwardKeys);
        newForwardKeys.add(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0));
        frameContents.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, newForwardKeys);
        
        final JFrame frame = new JFrame("Focus traversal test.");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(frameContents);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        
        //Start focus on the first text field:
        tf1.requestFocusInWindow();
    }
    
    public static void main(final String[] args) {
        SwingUtilities.invokeLater(FocusHopSystem2::createAndShowGUI);
    }
}

You may also read The AWT Focus Subsystem .

This is the way the Tab key works by default. When you press Tab focus will move to the next enabled component.

If you want to duplicate this functionality for the Enter key then first you can create a custom Action

Action transfer = new AbstractAction()
{
    @Override
    public void actionPerformed(ActionEvent e)
    {
        Component c = (Component)e.getSource();
        c.transferFocus();
    }
};

By default the "Enter" key will invoke the ActionListener added to the text field. So, now you can add this Action to specific text fields:

...
textField1.addActionListener( transfer );
textField2.addActionListener( transfer );

Or you can replace the default Enter Action of all the text fields by adding your custom Action to the ActionMap :

...
ActionMap am = (ActionMap)UIManager.get("TextField.actionMap");
am.put("notify-field-accept", transfer);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM