Hot questions for Using JTextField in focus

Question:

How can I get rid of the sound when I give focus to an uneditable JTextField or JTextPane?

Whenever I transfer focus to a JTextPane which is uneditable and hit Enter, a sound plays which is equals to the "beep" of the Toolkit class:

Toolkit.getDefaultToolkit.beet();

How can I make it play no sound?


Answer:

You might be able to try the idea from this question, quoted:

The idea is to get the beep action for the text field and disabling it.

JTextField field = new JTextField();
Action action;
action = field.getActionMap().get(DefaultEditorKit.beepAction);
action.setEnabled(false);

If that does not work, you can try to add a KeyListener, that would consume the KeyEvent that causes the beep.

JTextField textField = new JTextField();
textField.addKeyListener(new KeyAdapter() {
  @Override
  public void keyTyped(KeyEvent e) {
    if(e.getKeyCode() == KeyEvent.VK_ENTER){
      // will consume the event and stop it from processing normally
      e.consume();
    }        
  }
});

Question:

I am using KeyBindings and am using the condition WHEN_IN_FOCUSED_WINDOW so the keys always work. However, it seems that specifically arrow key (left, right, up, down) KeyBindings stop working if a JTextField has been selected.

Simply put, I would like the KeyBindings to always work no matter what JComponent has focus.

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;

import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.WindowConstants;

public class Test extends JPanel implements ActionListener {
    private static final long serialVersionUID = 1L;

    private static JTextField field;

    private static JFrame frame;

    private static boolean up = false, down = false, left = false, right = false;

    private static int x = 275, y = 275;

    public static void main(String[] args) {
        Test t = new Test();
        t.setBounds(0, 0, 1200, 600);
        t.setVisible(true);

        field = new JTextField();
        field.setBounds(20, 20, 100, 20);

        Timer repaintTimer = new Timer(2, t);

        frame = new JFrame();
        frame.setSize(600, 600);

        setUpKeyActions(t);

        frame.add(field);
        frame.add(t);

        Dimension dim = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setLocation((dim.width - frame.getWidth()) / 2, (dim.height - frame.getHeight()) / 2);
        frame.getContentPane().setLayout(null);
        frame.setAlwaysOnTop(true);
        frame.setResizable(false);

        repaintTimer.start();

        frame.setVisible(true);
        frame.requestFocus();
    }

    private static void setUpKeyActions(Test t) {
        int condition = WHEN_IN_FOCUSED_WINDOW;

        new KeyAction(t, condition, KeyEvent.VK_UP, 0, false) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                up = true;
            }

        };

        new KeyAction(t, condition, KeyEvent.VK_UP, 0, true) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                up = false;
            }

        };

        new KeyAction(t, condition, KeyEvent.VK_LEFT, 0, false) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                left = true;
            }

        };

        new KeyAction(t, condition, KeyEvent.VK_LEFT, 0, true) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                left = false;
            }

        };

        new KeyAction(t, condition, KeyEvent.VK_RIGHT, 0, false) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                right = true;
            }

        };

        new KeyAction(t, condition, KeyEvent.VK_RIGHT, 0, true) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                right = false;
            }

        };

        new KeyAction(t, condition, KeyEvent.VK_DOWN, 0, false) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                down = true;
            }

        };

        new KeyAction(t, condition, KeyEvent.VK_DOWN, 0, true) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                down = false;
            }

        };

    }

    private static abstract class KeyAction extends AbstractAction {
        private static final long serialVersionUID = 1L;

        KeyAction(JComponent component, int condition, int keyCode, int modifiers, boolean onKeyRelease) {
            InputMap inputMap = component.getInputMap(condition);
            ActionMap actionMap = component.getActionMap();
            KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode, modifiers, onKeyRelease);
            inputMap.put(keyStroke, keyStroke.toString());
            actionMap.put(keyStroke.toString(), this);
        }

    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        if(up)
            y -= 1;
        if(down)
            y += 1;
        if(right)
            x += 1;
        if(left)
            x -= 1;
        if(x < 0)
            x = 0;
        else if(x > frame.getWidth() - 30)
            x = frame.getWidth() - 30;
        if(y < 0)
            y = 0;
        else if(y > frame.getHeight() - 50)
            y = frame.getHeight() - 50;
        g.drawRect(x, y, 30, 30);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        frame.repaint();
    }

}

In the above code, the box moves with the arrow keys. However, if you select the text box in the upper-left corner, the box will no longer move.

Update:

I tried to add the KeyBindings to the JTextFields as given in the answer by @camickr, but it did not seem to work. Perhaps I am doing something incorrectly?

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;

import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.WindowConstants;

public class Test extends JPanel implements ActionListener {
    private static final long serialVersionUID = 1L;

    private static JFrame frame;

    private static boolean up = false, down = false, left = false, right = false;

    private static int x = 275, y = 275;

    public static void main(String[] args) {
        Test t = new Test();
        t.setBounds(0, 0, 1200, 600);
        t.setVisible(true);

        JTextField field = new JTextField();
        field.setBounds(20, 20, 100, 20);

        Timer repaintTimer = new Timer(2, t);

        frame = new JFrame();
        frame.setSize(600, 600);

        setUpKeyActions(t, field);

        frame.add(field);
        frame.add(t);

        Dimension dim = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setLocation((dim.width - frame.getWidth()) / 2, (dim.height - frame.getHeight()) / 2);
        frame.getContentPane().setLayout(null);
        frame.setAlwaysOnTop(true);
        frame.setResizable(false);

        repaintTimer.start();

        frame.setVisible(true);
        frame.requestFocus();
    }

    private static void setUpKeyActions(Test t, JTextField field) {
        int condition = WHEN_IN_FOCUSED_WINDOW;

        new KeyAction(condition, KeyEvent.VK_UP, 0, false, t, field) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                up = true;
            }

        };

        new KeyAction(condition, KeyEvent.VK_UP, 0, true, t, field) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                up = false;
            }

        };

        new KeyAction(condition, KeyEvent.VK_LEFT, 0, false, t, field) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                left = true;
            }

        };

        new KeyAction(condition, KeyEvent.VK_LEFT, 0, true, t, field) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                left = false;
            }

        };

        new KeyAction(condition, KeyEvent.VK_RIGHT, 0, false, t, field) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                right = true;
            }

        };

        new KeyAction(condition, KeyEvent.VK_RIGHT, 0, true, t, field) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                right = false;
            }

        };

        new KeyAction(condition, KeyEvent.VK_DOWN, 0, false, t, field) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                down = true;
            }

        };

        new KeyAction(condition, KeyEvent.VK_DOWN, 0, true, t, field) {
            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent e) {
                down = false;
            }

        };

    }

    private static abstract class KeyAction extends AbstractAction {
        private static final long serialVersionUID = 1L;

        KeyAction(int condition, int keyCode, int modifiers, boolean onKeyRelease, JComponent component, JComponent... components) {
            InputMap inputMap = component.getInputMap(condition);
            ActionMap actionMap = component.getActionMap();
            KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode, modifiers, onKeyRelease);
            inputMap.put(keyStroke, keyStroke.toString());
            actionMap.put(keyStroke.toString(), this);
            for(JComponent jc : components) {
                inputMap = jc.getInputMap(condition);
                actionMap = jc.getActionMap();
                keyStroke = KeyStroke.getKeyStroke(keyCode, modifiers, onKeyRelease);
                inputMap.put(keyStroke, keyStroke.toString());
                actionMap.put(keyStroke.toString(), this);
            }
        }

    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        if(up)
            y -= 1;
        if(down)
            y += 1;
        if(right)
            x += 1;
        if(left)
            x -= 1;
        if(x < 0)
            x = 0;
        else if(x > frame.getWidth() - 30)
            x = frame.getWidth() - 30;
        if(y < 0)
            y = 0;
        else if(y > frame.getHeight() - 50)
            y = frame.getHeight() - 50;
        g.drawRect(x, y, 30, 30);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        frame.repaint();
    }

}

Answer:

I am using KeyBindings and am using the condition WHEN_IN_FOCUSED_WINDOW

There are 3 InputMaps:

  1. JComponent.WHEN_FOCUSED
  2. JComponent.WHEN_ANCESTOR_OF_FOCUSED_
  3. JComponent.WHEN_IN_FOCUSED_WINDOW

The WHEN_FOCUSED has precedence, so you can't just add the Key Bindings to the parent panel.

So in your case you could:

  1. add the bindings to the text field as well or
  2. remove the bindings from the text field.

See How to Remove Key Bindings.

Edit:

Take a look a UIManager Defaults. It will show the default properties for each component, including which InputMap(s) are used by the component.

So for the JTextField you can remove the default bindings for all text fields by using:

InputMap im = (InputMap)UIManager.get("TextField.focusInputMap");
KeyStroke keyStroke = KeyStroke.getKeyStroke("RIGHT");
im.put(keyStroke, "none"); //noop

The above will disable the right arrow key of all text fields. Then I believe the bindings for the parent panel of the text field will now become active.

If not you can try changing the default Action for the text field. Take a look at Key Bindings. It will show the default bindings for each component. So you can just replace the Action for a specific binding. Something like:

ActionMap am = (ActionMap)UIManager.get("TextField.actionMap");
am.put("caret-forward", yourRightActionHere);

If you only want to change certain text field, then you will need to get the InputMap or ActionMap from each text field component.

Question:

I have a JTextField that I'm trying to add an autocompletion menu to. But I'm having issues with how I should handle the focus.

Here's a SSCCE

package test;

import java.awt.Point;

import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

public class SSCCE extends JFrame implements DocumentListener {
    private AutocompletionDialog dialog;

    public SSCCE() {
        dialog = new AutocompletionDialog ();

        JTextField textField = new JTextField(20);
        textField.getDocument().addDocumentListener(this);

        add(textField);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        pack();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new SSCCE().setVisible(true);
            }
        });
    }

    public void insertUpdate(DocumentEvent e) {
        Point p = this.getLocationOnScreen();
        dialog.setLocation(p.x, p.y + 50);
        dialog.setVisible(true);
    }

    public void removeUpdate(DocumentEvent e) { }
    public void changedUpdate(DocumentEvent e) { }

    private class AutocompletionDialog extends JDialog {
        JList<String> list = new JList<>(
                new String[] { "One", "Two", "Three" });

        AutocompletionDialog() {
            setSize(100, 100);
            add(list);
        }
    }
}

Of course there's more logic to it in the real program, but the issue I'm having is that I want to show the autocompletion dialog/menu, but still be able to continue typing in the text field. At the same time, I also want to be able to navigate the menu with the up/down arrows and the enter key, as well as with the mouse, to select one of the completion options.

Can someone please help me with how I should proceed here? Thanks!

EDIT:

Thanks to @camickr's reply I played around a bit with setFocusableWindowState together with an InputMap/ActionMap to always keep the focus in the text field, and manually control the selected list item. The problem is that you get a visual difference when doing it that way compared to if the list had proper focus. See the screen shots.

This is what it looks like if I don't mess with the focus (this is what I want).

This is what it looks like if I run setFocusableWindowState(false)

The main differences are the highlight border (darker blue) around the selected list item, but also the blue highlight around the entire dialog. Then there's also the differences in the title bar.

(Don't mind the render artifacts, I'm connecting to a three year old virtual Linux installation using an old NX client)

EDIT 2:

I was afraid that it was the Look and Feel or OS that determined how the selected list item should look (with the highlighted border for example). But it turns out that it is indeed just the cell renderer that makes that call. Knowing that I felt much better about writing my own cell renderer, and I now have a solution that I'm happy with.

This is the code I ended up using:

private class CellRenderer extends DefaultListCellRenderer
{
    @Override
    public Component getListCellRendererComponent(
            JList<?> jlist, Object value, int index,
            boolean isSelected, boolean cellHasFocus) {
        super.getListCellRendererComponent(
                jlist, value, index, isSelected, cellHasFocus);

        if (isSelected) {
            Border border = UIManager.getBorder(
                    "List.focusSelectedCellHighlightBorder");

            if (border == null) {
                border = UIManager.getBorder(
                        "List.focusCellHighlightBorder");
            }

            setBorder(border);
        }

        return this;
    }
}

Answer:

As I show the auto completion menu the focus is given to that dialog.

To prevent focus from going to the popup window you can use:

JDialog dialog = new JDialog(...);
dialog.setFocusableWindowState( false );
...
dialog.setVisible( true );

I also want to be able to navigate the menu with the up/down arrows and the enter key

Then you need to override the default Actions provided by the text field. Check out Key Bindings for more information.

You can also check out: button highlighting using keyboard keys where I just provided a simple example of implementing an Action.

Question:

I have a class implements FocusListener, inside the class got a lot of JTextField, I want all of them select all when the focus gained. This is my focusGained() function:

@Override
public void focusGained(FocusEvent fe)
{
    JTextField txt = (JTextField)fe.getComponent();
    txt.selectAll();
}

I try to convert fe to component then selectAll(), but it doesn't works. Any idea about this?


Answer:

You need to use getSource()

((JTextField)fe.getSource()).selectAll();

I'd personnally check the instanceof fe.getSource()

@Override
public void focusGained(FocusEvent fe) {
    if (!(fe.getSource() instanceof JTextField)) return;
    JTextField txt = (JTextField)fe.getSource();
    txt.selectAll();
}

Question:

I am new to java GUI and I have 2 JTextField's txtMessage1 and txtMessage2. I'd like to archive this: if one textfiled has focus the other one will be emptied, is that possible and how to archive it?

I tried:

if (txtMessage1.isFocusOwner())
    txtMessage2.setText("");
if (txtMessage2.isFocusOwner())
    txtMessage1.setText("");

But it doesn't work, not throwing anything....


Answer:

You need a FocusListener for it, like this:

FocusAdapter fl = new FocusAdapter()
{
    public void focusGained (FocusEvent evt)
    {
        if (evt.getSource() == txtField1)
            txtField2.setText("");
        else if (evt.getSource() == txtField2)
            txtField1.setText("");
    }
}
txtField1.addFocusListener(fl);
txtField2.addFocusListener(fl);

Question:

I have these two classes:

class Test:

import java.awt.BorderLayout;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Test {

    //frame
    private static JFrame frame = new JFrame() {
        private static final long serialVersionUID = 1L;

        {
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setSize(400, 200);
            setLocationRelativeTo(null);
            setLayout(new BorderLayout());

            viewPanel = new JPanel(new BorderLayout());
            add(viewPanel);
        }
    };

    private static JPanel viewPanel;

    //change the panels
    public static void showView(JPanel panel) {
        viewPanel.removeAll();

        viewPanel.add(panel, BorderLayout.CENTER);
        viewPanel.revalidate();
        viewPanel.repaint();
    }

    //main method
    public static void main (String [] args) {

        SwingUtilities.invokeLater(() -> showView(Panels.panel1));

        SwingUtilities.invokeLater(() -> {
            frame.setVisible(true);
        });
    }
}

class Panels:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

//panels
public class Panels {

    //first panel
    static JPanel panel1 = new JPanel() {
        private static final long serialVersionUID = 1L;
        {
            JButton button = new JButton("Click here!");

            add(button);

            button.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent arg0) {
                    SwingUtilities.invokeLater(() -> Test.showView(panel2));
                }
            });
        }
    };

    //second panel
    static JPanel panel2 = new JPanel() {
        private static final long serialVersionUID = 1L;
        {
            JTextField textField = new JTextField(5);

                add(textField);
        }
    };
}

And as you can see, the JPanel changes inside the JFrame, after clicking the JButton: How can I change the JPanel from another Class?

But how can I now set the focus on the JTextField, after changing panel1 to panel2?

I've tried to add grabFocus(); to the JTextField, but it didn't work and requestFocus(); didn't work as well.

Thanks in advance!


Answer:

  1. There's no need to call showView(...) with invokeLater. Your ActionListener is being called on the EDT, so this is unnecessary code.
  2. If you had a handle to the JTextField, you could call requestFocusInWindow() on it after making it visible, and it should have focus.

For example:

button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        // SwingUtilities.invokeLater(() -> Test.showView(panel2)); // not needed
        Test.showView(panel2);
        Component[] comps = panel2.getComponents();
        if (comps.length > 0) {
            comps[0].requestFocusInWindow();
        }
    }
});

Myself, I would use CardLayout to do my swapping and would not use the kludge of getting components via getComponents() but rather using much less brittle method calls.

For example:

import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import javax.swing.*;

@SuppressWarnings("serial")
public class MyPanelTest extends JPanel {
    private TextFieldPanel textFieldPanel = new TextFieldPanel();
    private CardLayout cardLayout = new CardLayout();

    public MyPanelTest() {
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(new JButton(new ButtonAction("Press Me")));        
        setPreferredSize(new Dimension(400, 200));
        setLayout(cardLayout);
        add(buttonPanel, "button panel");
        add(textFieldPanel, TextFieldPanel.NAME);
    }

    private class ButtonAction extends AbstractAction {

        public ButtonAction(String name) {
            super(name);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            cardLayout.show(MyPanelTest.this, TextFieldPanel.NAME);
            textFieldPanel.textFieldRequestFocus();
        }
    }

    private static void createAndShowGui() {
        JFrame frame = new JFrame("My Panel Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(new MyPanelTest());
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}

@SuppressWarnings("serial")
class TextFieldPanel extends JPanel {
    public static final String NAME = "TEXT_FIELD_PANEL";
    private JTextField textField = new JTextField(10);

    public TextFieldPanel() {
        add(textField);
    }

    public void textFieldRequestFocus() {
        textField.requestFocusInWindow();
    }
}

Question:

in the following example:

JTextField name = new JTextField("Enter Name");
JTextField place = new JTextField("Enter Place of birth");
JTextField a = new JTextField("Enter a");
JTextField b = new JTextField("Enter b");
JTextField c = new JTextField("Enter c");


FocusListener f = new FocusListener() {
  public void focusGained(FocusEvent e) {

  }

  public void focusLost(FocusEvent e) {

  }

name.addfocuslistener(f);
place.addfocuslistener(f);
a.addfocuslistener(f);
b.addfocuslistener(f);
c.addfocuslistener(f);

How can i set the text of the JTextfield to an empty string when focus is gained?

So something like:

focusedTextField.settext("");

Answer:

Start by taking a look at the JavaDocs for FocusEvent, it has a numbe of interesting properties, including getSource, which all EventObjects have and getComponent which returns "Returns the originator of the event." as a Component, which is very useful.

Using this knowledge, you could do something like...

FocusListener f = new FocusListener() {
  public void focusGained(FocusEvent e) {
      Component source = e.getComponent();
      if (source instanceof JTextField) {
          ((JTextField)source).setText("");
      }
  }

You should also have a look at How to Write a Focus Listener for more details

Question:

I'm working to design license activation part. It had two text Fields in Java Swing.

Java code:

jTextField1.setDocument(new JTextFieldLimit(8));   
jTextField2.setDocument(new JTextFieldLimit(8));

when the jTextField1 is ended up by entering 8 alphanumeric characters. It had to move its focus to next JTextField2 automatically.Are there any default methods available or how it can be done.


Answer:

The basic answer to your question is, KeyboardFocusManager#focusNextCompnent

The longer answer is slightly more complicated.

Lets start with the fact that Java 1.4, it is no longer required or recommended that you utilise the Document for this functionality, instead use a DocumentFilter, see Implementing a Document Filter and DocumentFilter Examples for more details

I also prefer reusable and configurable solutions, to this end, I'd prefer to see a solution which allowed me to change the decision making processes that are involved in deciding when focus should be transferred and configure how the transfer actually occurs

Now, remember, you could use a custom FocusTraversalPolicy to change the way in which focus moves between the components, but this isn't always the desirable solution.

Let's start with some basics...

    public interface AutoFocusTransferDelegate {
        public boolean shouldTransferFocus(Document doc);
    }

    public interface AutoFocusTransferObserver {
        public void focusTransferShouldOccur(Document doc);
    }

    public class AutoFocusTransferHandler implements DocumentListener {

        private AutoFocusTransferListener listener;
        private AutoFocusTransferDelegate delegate;

        public AutoFocusTransferHandler(AutoFocusTransferListener listener, AutoFocusTransferDelegate delegate) {
            this.listener = listener;
            this.delegate = delegate;
        }

        @Override
        public void insertUpdate(DocumentEvent e) {
            checkForTransfer(e.getDocument());
        }

        @Override
        public void removeUpdate(DocumentEvent e) {
            checkForTransfer(e.getDocument());
        }

        @Override
        public void changedUpdate(DocumentEvent e) {
            checkForTransfer(e.getDocument());
        }

        public void checkForTransfer(Document doc) {
            if (delegate != null && delegate.shouldTransferFocus(doc)) {
                if (listener != null) {
                    listener.focusTransferShouldOccur(doc);
                }
            }
        }

    }

Here we have a "delegate", which is used to configure and customise the decisions making process over when a transfer should take place, a "observer" which is notified when a transfer should take place, which allows it to decide "how" the transfer should take place and a DocumentListener to monitor the Document which is used to query the delegate and notify the observer.

Sure, you could wrap it all up in a single class, but now, you have a very simple and highly configurable solution where you don't need to extend from classes in order to achieve a new result (nit pick on my part). It's a basic example of composition over inheritance.

And you might be able to use it something like...

import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.KeyboardFocusManager;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.DocumentFilter;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridwidth = GridBagConstraints.REMAINDER;

            int maxCharacters = 8;
            AutoFocusTransferListener listener = new AutoFocusTransferListener() {
                @Override
                public void focusTransferShouldOccur(Document doc) {
                    KeyboardFocusManager.getCurrentKeyboardFocusManager().focusNextComponent();
                }
            };
            AutoFocusTransferDelegate delegate = new MaxLengthAutoFocusTransferDelegate(maxCharacters);
            DocumentFilter filter = new SizeFilter(maxCharacters);
            DocumentListener docListener = new AutoFocusTransferHandler(listener, delegate);

            add(createTextField(8, filter, docListener), gbc);
            add(createTextField(8, filter, docListener), gbc);
            add(new JButton("Ok"), gbc);
        }

        protected  JTextField createTextField(int maxCharacters, DocumentFilter filter, DocumentListener docListener) {
            JTextField field = new JTextField(maxCharacters);
            AbstractDocument doc = (AbstractDocument)field.getDocument();
            doc.setDocumentFilter(filter);
            doc.addDocumentListener(docListener);
            return field;
        }

    }

    public class MaxLengthAutoFocusTransferDelegate implements AutoFocusTransferDelegate {

        private int maxLength;

        public MaxLengthAutoFocusTransferDelegate(int maxLength) {
            this.maxLength = maxLength;
        }

        @Override
        public boolean shouldTransferFocus(Document doc) {
            return doc.getLength() >= maxLength;
        }

    }

    public class SizeFilter extends DocumentFilter {

        private int maxCharacters;

        public SizeFilter(int maxChars) {
            maxCharacters = maxChars;
        }

        public void insertString(FilterBypass fb, int offs, String str, AttributeSet a)
                throws BadLocationException {

            if ((fb.getDocument().getLength() + str.length()) <= maxCharacters) {
                super.insertString(fb, offs, str, a);
            }
        }

        public void replace(FilterBypass fb, int offs, int length, String str, AttributeSet a)
                throws BadLocationException {

            if ((fb.getDocument().getLength() + str.length() - length) <= maxCharacters) {
                super.replace(fb, offs, length, str, a);
            }
        }
    }

    public class AutoFocusTransferHandler implements DocumentListener {

        private AutoFocusTransferListener listener;
        private AutoFocusTransferDelegate delegate;

        public AutoFocusTransferHandler(AutoFocusTransferListener listener, AutoFocusTransferDelegate delegate) {
            this.listener = listener;
            this.delegate = delegate;
        }

        @Override
        public void insertUpdate(DocumentEvent e) {
            checkForTransfer(e.getDocument());
        }

        @Override
        public void removeUpdate(DocumentEvent e) {
            checkForTransfer(e.getDocument());
        }

        @Override
        public void changedUpdate(DocumentEvent e) {
            checkForTransfer(e.getDocument());
        }

        public void checkForTransfer(Document doc) {
            if (delegate != null && delegate.shouldTransferFocus(doc)) {
                if (listener != null) {
                    listener.focusTransferShouldOccur(doc);
                }
            }
        }

    }

    public interface AutoFocusTransferDelegate {

        public boolean shouldTransferFocus(Document doc);
    }

    public interface AutoFocusTransferListener {

        public void focusTransferShouldOccur(Document doc);
    }
}

Question:

When I was creating a bunch of JTextFields I saw that first one is selected. I want to deselect it, because I have focus listener and it's running automatically. Any clues?

SSCCE:

JTextField tf = new JTextField("hello");
tf.setForeground(Color.decode("0x8C8C8C")); // for nice comment inside the text field
textFieldKwotaWplacona.addFocusListener(new FocusListener() {

        @Override
        public void focusGained(FocusEvent e) 
        {

            if(tf.getForeground() != Color.BLACK)
            {
            tf.setText("");
            tf.setForeground(Color.BLACK);
            }
        }   @Override
        public void focusLost(FocusEvent arg0) {}});
//for deleting "nice comment" after click

tf.setBounds(//some bounds);
add(tf);

Repeat that process for another text field

EDIT2 : actual code (I believe its sscce :P)

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;

import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JRadioButton;
import javax.swing.JTextField;


public class Main extends JFrame implements ActionListener
{
JTextField textFieldKwotaWplacona, textFieldOprocentowanie, textFieldDlugoscLokaty, textFieldKwotaOtrzymana;

Main()
{   setSize(500,300);
    setLayout(null);
    setTitle("Program do liczenia procentu składanego");
setDefaultCloseOperation(EXIT_ON_CLOSE);


    textFieldKwotaWplacona = new JTextField("Ilość pieniędzy wpłaconych");
    textFieldKwotaWplacona.setForeground(Color.decode("0x8C8C8C"));
    textFieldKwotaWplacona.addActionListener(this);
    textFieldKwotaWplacona.addFocusListener(new FocusListener() {

        @Override
        public void focusGained(FocusEvent e) 
        {

            if(textFieldKwotaWplacona.getForeground() != Color.BLACK)
            {
            textFieldKwotaWplacona.setText("");
            textFieldKwotaWplacona.setForeground(Color.BLACK);
            }
        }   @Override
        public void focusLost(FocusEvent arg0) {}});

    textFieldKwotaWplacona.setBounds(10, 10, 100, 20);
    add(textFieldKwotaWplacona);

    textFieldOprocentowanie = new JTextField("Oprocentowanie");
    textFieldOprocentowanie.setForeground(Color.decode("0x8C8C8C"));
    textFieldOprocentowanie.addActionListener(this);


    textFieldOprocentowanie.addFocusListener(new FocusListener() {

        @Override
        public void focusGained(FocusEvent e) 
        {

            if(textFieldOprocentowanie.getForeground() != Color.BLACK)
            {
            textFieldOprocentowanie.setText("");
            textFieldOprocentowanie.setForeground(Color.BLACK);
            }
        }

        @Override
        public void focusLost(FocusEvent arg0) {}});
    textFieldOprocentowanie.setBounds(10, 40, 100, 20);
    add(textFieldOprocentowanie);



}




@Override
public void actionPerformed(ActionEvent arg0) 
{
    // TODO Auto-generated method stub
}

    public static void main(String[] args) 
{
    Main a=new Main();
    a.setVisible(true);


}
}

I want to set focus to window or sth else, in order to prevent text from disappearing.


Answer:

As discussed in the comments, I added a radio button to take the focus instead:

public class Main extends JFrame {

    JTextField textFieldKwotaWplacona, textFieldOprocentowanie;

    Main() {

        setTitle("Program do liczenia procentu składanego");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setLayout(new FlowLayout());

        textFieldKwotaWplacona = new JTextField("Ilość pieniędzy wpłaconych");
        textFieldKwotaWplacona.setForeground(Color.decode("0x8C8C8C"));
        textFieldKwotaWplacona.addFocusListener(new FieldFocusListener(textFieldKwotaWplacona));
        add(textFieldKwotaWplacona);

        textFieldOprocentowanie = new JTextField("Oprocentowanie");
        textFieldOprocentowanie.setForeground(Color.decode("0x8C8C8C"));
        textFieldOprocentowanie.addFocusListener(new FieldFocusListener(textFieldOprocentowanie));
        add(textFieldOprocentowanie);

        JRadioButton btn = new JRadioButton("text");
        add(btn);

        pack();
        btn.requestFocusInWindow();
    }

    private class FieldFocusListener extends FocusAdapter {

        private JTextField field;

        FieldFocusListener(JTextField field) {

            this.field = field;
        }

        @Override
        public void focusGained(FocusEvent e) {

            if (field.getForeground() != Color.BLACK) {
                field.setText("");
                field.setForeground(Color.BLACK);
            }
        }
    }

    public static void main(String[] args) {

        Main a = new Main();
        a.setVisible(true);
    }
}
Explanation

From the tutorial:

If you want to ensure that a particular component gains the focus the first time a window is activated, you can call the requestFocusInWindow method on the component after the component has been realized, but before the frame is displayed.

That means btn.requestFocusInWindow() must appear after pack() and before a.setVisible(true).

The reason you need another component to take the focus is that when a window is focused, a component inside it must gain the focus.

Notes:
  • If you want a better text field hint, see @camickr's answer.
  • Don't use null layout. Pick one that serves your GUI design (I picked FlowLayout just because it's fast to use, though probably not what you need).
  • Instead of setting the size of the frame, pack() after all components had been added.
  • Instead of creating the same focus listener for every text field, just create it as a class and reuse it. I show one way with passing the component to a constructor, but you can get rid of that and use e.getComponent() to get the text field instance.

Question:

I have two JPanels inside another JPanel. One of them has a JTextField inside, another few JButtons. I want focus to be set on the JTextField every time user starts typing (even when one of the buttons has focus at the moment).


Answer:

KeyListener won't work, because in order for it to trigger key events, the component it is registered to must be focusable AND have focus, this means you'd have to attach a KeyListener to EVERY component that might be visible on the screen, this is obviously not a practical idea.

Instead, you could use a AWTEventListener which allows you to register a listener that will notify you of all the events been processed through the event queue.

The registration process allows you to specify the events your are interested, so you don't need to constantly try and filter out events which your not interested in

For example. Now, you can automatically focus the textField when a key is triggered, but you should check to see if the event was triggered by the text field and ignore it if it was

One of the other things you would be need to do is re-dispatch the key event to the text field when it isn't focused, otherwise the field will not show the character which triggered it...

Something like...

if (Character.isLetterOrDigit(e.getKeyChar())) {
    filterField.setText(null);
    filterField.requestFocusInWindow();
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            filterField.dispatchEvent(e);
        }
    });
}

as an example

Question:

so I have a couple JButtons, and hundreds of JTextFields throughout a program (with CardLayout, don't worry). I want these JButtons to find the JTextField that was last in focus, so when the button is clicked, it sets the text of that field to be whatever that button is.

I have tried getFocusOwner() and getMostRecentFocusOwner() on JTextFields that were setFocusable(true)

I'm hoping there's a method already available somewhere for this.


Answer:

we have getOppositeComponent() in FocusEvent.

which returns the other Component involved in this focus change. For a FOCUS_GAINED event, this is the Component that lost focus. For a FOCUS_LOST event, this is the Component that gained focus. If this focus change occurs with a native application, with a Java application in a different VM or context, or with no other Component, then null is returned. see documentation for more detail.

or

in the focus lost of TextField assign the textfield to some variable and then use that variable in button click event.

Question:

I have the following code that works correctly in my opinion but when I try to enter a new record starts blinking between charter field and the field name, this happens when the validation performed to see if the jtexfiedl is empty.

Here the code.

public void validarCedula(JTextField txt, JLabel lblMensaje) {
    texto = txt.getText().trim();
    tamanio = texto.length();
    lblMensaje.setText("");        
    try{
    if (texto.isEmpty()) 
    {
        lblMensaje.setText("Cedula Vacio");
        lblMensaje.setForeground(Color.red);
        txt.requestFocus();
    }
    else if (tamanio > 0 && tamanio < 9) {
        lblMensaje.setText("Cedula Incorrecta");
        lblMensaje.setForeground(Color.red);
        txt.requestFocus();
    } else if (tamanio == 10) {
        lblMensaje.setText("Cedula Correcta");
        lblMensaje.setForeground(Color.white);
    } else if (tamanio > 11 && tamanio < 13) {
        lblMensaje.setText("RUC Incorrecto");
        lblMensaje.setForeground(Color.red);
        txt.requestFocus();
    } else if (tamanio == 13) {
        lblMensaje.setText("R.U.C Correcto");
        lblMensaje.setForeground(Color.WHITE);
    }
    }catch(Exception ex)
    {
        JOptionPane.showMessageDialog(null, ex);
    }
}


public void validarNombre(JTextField txt, JLabel lblMensaje) {
    texto = txt.getText().trim();
    tamanio = texto.length();   
    try{
    if (texto.isEmpty()) 
    {
        lblMensaje.setText("Nombre Vacio");
        lblMensaje.setForeground(Color.red);
        txt.requestFocus();
    }
    else if (tamanio > 0 && tamanio < 7) {
            lblMensaje.setText("Debe Ingresar 2 Nombres");
            lblMensaje.setForeground(Color.red);
            txt.requestFocus();
        } else if (tamanio > 7 && tamanio < 24) {
            lblMensaje.setText("Nombre Correcto");
            lblMensaje.setForeground(Color.WHITE);
        } else if (tamanio > 25) {
            lblMensaje.setText("Nombre Incorrecto");
            lblMensaje.setForeground(Color.red);
            txt.requestFocus();
        }
    }catch(Exception ex)
    {
        JOptionPane.showMessageDialog(null, ex);
    }
}

These methods are called in the main class in each jtexfield focusLost event.

Someone could help me find the solution?


Answer:

Your code locks up because it when one field loses focus, the other field gains focus. Your FocusListener tries to bring the focus back to the first field, but it can't because the second listener is trying to do the same, to bring the focus back to its field, resulting in the two validation methods continually being called, locking up your program.

Add a two System.out.println(...) calls to prove this:

public void validarCedula(JTextField txt, JLabel lblMensaje) {
    System.out.println("Dentro do validarCedula");  // ***** add this *****
    texto = txt.getText().trim();

    //...
}


public void validarNombre(JTextField txt, JLabel lblMensaje) {
   System.out.println("Dentro do validarNombre");  // ***** add this *****

   // ....
}

Solution: use an InputVerifier as noted in my comments.

Code to test my assertion:

import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;

import javax.swing.*;

public class Foo3b extends JPanel {
   private String texto;
   private int tamanio;
   private JTextField cedulaField = new JTextField(10);
   private JTextField nombreField = new JTextField(10);
   private JLabel mensajeLabel = new JLabel(" ");

   public Foo3b() {
      JPanel panel = new JPanel();
      panel.add(new JLabel("Cedula:"));
      panel.add(cedulaField);
      panel.add(new JLabel("Nombre:"));
      panel.add(nombreField);

      JPanel mensajePanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
      mensajePanel.add(new JLabel("Mensaje:"));
      mensajePanel.add(mensajeLabel);

      setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
      add(panel);
      add(mensajePanel);

      cedulaField.addFocusListener(new FocusAdapter() {
         @Override
         public void focusLost(FocusEvent e) {
            validarCedula(cedulaField, mensajeLabel);
         }
      });

      nombreField.addFocusListener(new FocusAdapter() {
         @Override
         public void focusLost(FocusEvent e) {
            validarNombre(nombreField, mensajeLabel);
         }
      });
   }

   public void validarCedula(JTextField txt, JLabel lblMensaje) {
      System.out.println("Dentro do validarCedula");
      texto = txt.getText().trim();
      tamanio = texto.length();
      lblMensaje.setText("");        
      try{
      if (texto.isEmpty()) 
      {
          lblMensaje.setText("Cedula Vacio");
          lblMensaje.setForeground(Color.red);
          txt.requestFocus();
      }
      else if (tamanio > 0 && tamanio < 9) {
          lblMensaje.setText("Cedula Incorrecta");
          lblMensaje.setForeground(Color.red);
          txt.requestFocus();
      } else if (tamanio == 10) {
          lblMensaje.setText("Cedula Correcta");
          lblMensaje.setForeground(Color.white);
      } else if (tamanio > 11 && tamanio < 13) {
          lblMensaje.setText("RUC Incorrecto");
          lblMensaje.setForeground(Color.red);
          txt.requestFocus();
      } else if (tamanio == 13) {
          lblMensaje.setText("R.U.C Correcto");
          lblMensaje.setForeground(Color.WHITE);
      }
      }catch(Exception ex)
      {
          JOptionPane.showMessageDialog(null, ex);
      }
  }


  public void validarNombre(JTextField txt, JLabel lblMensaje) {
     System.out.println("Dentro do validarNombre");
      texto = txt.getText().trim();
      tamanio = texto.length();   
      try{
      if (texto.isEmpty()) 
      {
          lblMensaje.setText("Nombre Vacio");
          lblMensaje.setForeground(Color.red);
          txt.requestFocus();
      }
      else if (tamanio > 0 && tamanio < 7) {
              lblMensaje.setText("Debe Ingresar 2 Nombres");
              lblMensaje.setForeground(Color.red);
              txt.requestFocus();
          } else if (tamanio > 7 && tamanio < 24) {
              lblMensaje.setText("Nombre Correcto");
              lblMensaje.setForeground(Color.WHITE);
          } else if (tamanio > 25) {
              lblMensaje.setText("Nombre Incorrecto");
              lblMensaje.setForeground(Color.red);
              txt.requestFocus();
          }
      }catch(Exception ex)
      {
          JOptionPane.showMessageDialog(null, ex);
      }
  }

  private static void createAndShowGui() {
     Foo3b mainPanel = new Foo3b();

     JFrame frame = new JFrame("Foo3");
     frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
     frame.getContentPane().add(mainPanel);
     frame.pack();
     frame.setLocationByPlatform(true);
     frame.setVisible(true);
  }

  public static void main(String[] args) {
     SwingUtilities.invokeLater(new Runnable() {
        public void run() {
           createAndShowGui();
        }
     });
  }


}

Which returns:

Dentro do validarCedula
Dentro do validarNombre
Dentro do validarCedula
Dentro do validarNombre
Dentro do validarCedula
Dentro do validarNombre
Dentro do validarCedula
Dentro do validarNombre
Dentro do validarCedula
Dentro do validarNombre
Dentro do validarCedula
Dentro do validarNombre
Dentro do validarCedula
Dentro do validarNombre
.
.
. 
etc

Better would be something like:

import java.awt.Color;
import java.awt.FlowLayout;
import javax.swing.*;

public class Foo3b extends JPanel {
   public static final int CEDULA_TAMANIO_CORRECTO1 = 10;
   public static final int CEDULA_TAMANIO_CORRECTO2 = 13;
   public static final Color COLOR_INCORRECTO = Color.RED;
   public static final Color COLOR_CORRECTO = Color.BLUE;
   public static final int NOMBRE_TAMANIO_MIN = 8;
   public static final int NOMBRE_TAMANIO_MAX = 24;
   private JTextField cedulaField = new JTextField(10);
   private JTextField nombreField = new JTextField(10);
   private JLabel mensajeLabel = new JLabel(" ");

   public Foo3b() {
      JPanel panel = new JPanel();
      panel.add(new JLabel("Cedula:"));
      panel.add(cedulaField);
      panel.add(new JLabel("Nombre:"));
      panel.add(nombreField);

      JPanel mensajePanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
      mensajePanel.add(new JLabel("Mensaje:"));
      mensajePanel.add(mensajeLabel);

      setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
      add(panel);
      add(mensajePanel);

      cedulaField.setInputVerifier(new CedulaVerifier());

      nombreField.setInputVerifier(new NombreVerifier());
   }

   private class CedulaVerifier extends InputVerifier {
      private String texto = "";
      private int tamanio = 0;

      @Override
      public boolean verify(JComponent input) {
         texto = ((JTextField) input).getText().trim();
         tamanio = texto.length();

         if (texto.isEmpty()) {
            return false;
         } else if (tamanio != CEDULA_TAMANIO_CORRECTO1
               && tamanio != CEDULA_TAMANIO_CORRECTO2) {
            return false;
         }
         // default
         return true;
      }

      @Override
      public boolean shouldYieldFocus(JComponent input) {
         texto = ((JTextField) input).getText().trim();
         tamanio = texto.length();
         if (verify(input)) {
            mensajeLabel.setForeground(COLOR_CORRECTO);
            if (tamanio == CEDULA_TAMANIO_CORRECTO1) {
               mensajeLabel.setText("Cedula Correcta");
            } else if (tamanio == CEDULA_TAMANIO_CORRECTO2) {
               mensajeLabel.setText("R.U.C Correcto");
            }

            return true;
         } else {
            mensajeLabel.setForeground(COLOR_INCORRECTO);

            if (texto.isEmpty()) {
               mensajeLabel.setText("Cedula Vacio");
            } else if (tamanio > 0 && tamanio < 9) {
               mensajeLabel.setText("Cedula Incorrecta");
            } else if (tamanio > 11 && tamanio < 13) {
               mensajeLabel.setText("RUC Incorrecto");
            } else if (tamanio > 13) {
               mensajeLabel.setText("R.U.C INcorrecto");
            }
         }
         return false;
      }

   }

   private class NombreVerifier extends InputVerifier {
      private String texto = "";
      private int tamanio = 0;

      @Override
      public boolean verify(JComponent input) {
         texto = ((JTextField) input).getText().trim();
         tamanio = texto.length();

         if (texto.isEmpty()) {
            return false;
         } else if (tamanio < NOMBRE_TAMANIO_MIN
               || tamanio > NOMBRE_TAMANIO_MAX) {
            return false;
         }
         // default
         return true;

      }

      @Override
      public boolean shouldYieldFocus(JComponent input) {
         texto = ((JTextField) input).getText().trim();
         tamanio = texto.length();
         if (verify(input)) {
            mensajeLabel.setForeground(COLOR_CORRECTO);
            mensajeLabel.setText("Nombre Correcto");            
            return true;
         } else {
            mensajeLabel.setForeground(COLOR_INCORRECTO);
            if (texto.isEmpty()) {
               mensajeLabel.setText("Nombre Vacio");
            } else if (tamanio < NOMBRE_TAMANIO_MIN) {
               mensajeLabel.setText("Debe Ingresar 2 Nombres");
            } else if (tamanio > NOMBRE_TAMANIO_MAX) {
               mensajeLabel.setText("Nombre Incorrecto");
            }            
            return false;
         }
      }
   }

   private static void createAndShowGui() {
      Foo3b mainPanel = new Foo3b();

      JFrame frame = new JFrame("Foo3");
      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }

}

Question:

In my Java Swing app, I have multiple JTextFields for dates, there is a JButton when clicked, it will open a calendar to pick a date, and the date string should be inserted into one of the JTextFields, so I want to design the program so that user first clicks in a date JTextField he wants to input a date [ get focus on that field and remember it ], the program saves the JTextField as target component, then that component is passed to the calendar object to input the picked date. So far I can hard code the program so it can input any date string I pick in to a certain JTextField I've hard coded with, but the problem is how to remember the JTextField user clicked on ? So I don't have to hard code it.

I've tried : Date_Field.getDocument().addDocumentListener(A_Listener); It won't get the focus until user starts typing in it.

I've also tried :

Date_Field.addActionListener(new ActionListener() {
  public void actionPerformed(ActionEvent evt) {
     Focused_Date_TextField=(JTextField)evt.getSource();
  }
});

Also didn't work, because when user clicked on it, there is no action yet [ therefore no focus ] until user starts typing.

So what's a way to get the JTextField when user JUST clicks on it without typing anything ?


Answer:

Combine both the JTextField and JButton into a custom component (maybe a JPanel) and isolate the functionality within it. This way, the button is ALWAYS associated with a given JTextField and you don't care about which field was "focused" last

public class DateField extends JPanel {
    private JTextField field;
    private JButton btn;

    public DateField() {
        setLayout(new FlowLayout(FlowLayout.LEFT));

        field = new JTextField(11);
        btn = new JButton("...");

        add(field);
        add(btn);

        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // Show calendar, get date do all that funky stuff
                field.setText(dateAsString);
            }
        });
    }

}

Then you can create as many of these as you want and add them to whatever container you want

Question:

I have created buttons 0-9 as well as 4 text fields (JTextField). I am trying to allow the user to click on any number 0-9 to input into each text field. However, I cannot determine which field the user is clicked on. So when the user select the second field, it doesn't show any text it work only on the first field.

field = new JTextField();
    field.setHorizontalAlignment(SwingConstants.RIGHT);
    field.setText("");
    field.setBounds(12, 12, 66, 34);
    field.setBackground(Color.WHITE);
    frame.getContentPane().add(field);
    field.setColumns(10);
    field.setFont(new Font("Liberation Mono", Font.BOLD, 
20));
    field.setFocusable(true);
    field.addFocusListener(new FocusListener() {

        @Override
        public void focusLost(FocusEvent arg0) {
             f=false;
        }

        @Override
        public void focusGained(FocusEvent arg0) {
             f=true;
        }
    });

    field2 = new JTextField();
    field2.setText("");
    field2.setHorizontalAlignment(SwingConstants.RIGHT);
    field2.setFont(new Font("Liberation Mono", Font.BOLD, 
20));
    field2.setColumns(10);
    field2.setBackground(Color.WHITE);
    field2.setBounds(90, 12, 66, 34);
    field2.setFocusable(true);
    field2.addFocusListener(new FocusListener() {

        @Override
        public void focusLost(FocusEvent arg0) {
            f = false;
        }

        @Override
        public void focusGained(FocusEvent arg0) {
            f = true;
        }
    });
    frame.getContentPane().add(field2);

    field3 = new JTextField();
    field3.setFont(new Font("Liberation Mono", Font.BOLD, 
20));
    field3.setHorizontalAlignment(SwingConstants.RIGHT);
    field3.setBounds(199, 12, 66, 34);
    frame.getContentPane().add(field3);
    field3.setColumns(10);
    field3.setFocusable(true);
    field3.addFocusListener(new FocusListener() {

        @Override
        public void focusLost(FocusEvent arg0) {
            f=false;
        }

        @Override
        public void focusGained(FocusEvent arg0) {
             f=true;
        }
    });

    field4 = new JTextField();
    field4.setText("");
    field4.setHorizontalAlignment(SwingConstants.RIGHT);
    field4.setFont(new Font("Liberation Mono", Font.BOLD, 
20));
    field4.setColumns(10);
    field4.setBackground(Color.WHITE);
    field4.setBounds(277, 12, 66, 34);
    frame.getContentPane().add(field4);
    field4.setFocusable(true);
    field4.addFocusListener(new FocusListener() {

        @Override
        public void focusLost(FocusEvent arg0) {
             f = false;
        }

        @Override
        public void focusGained(FocusEvent arg0) {
             f = true;
        }
    });

The button example:

 JButton btn0 = new JButton("0");
    btn0.setFont(new Font("Tahoma",Font.BOLD,15));
    btn0.setBounds(199, 228, 80, 30);
    frame.getContentPane().add(btn0);
    btn0.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent arg0) {
                if (f==false) {
                    String num = 
 field.getText()+btn0.getText();
                    field.setText(num);

                }else if (f==false) {
                    String num = 
 field2.getText()+btn0.getText();
                    field2.setText(num);
                }else if (f==false) {
                    String num = 
field3.getText()+btn0.getText();
                    field3.setText(num);
                }
                String 
num=textField.getText()+btn0.getText();
                textField.setText(num);
        }
    });

Answer:

You should use a TextAction for the ActionListener of your button. The TextAction implements a getFocusedComponent() method that will return to you the last text component that had focus.

So to append text to the last text component with focus the code would be something like:

TextAction digit = new TextAction()
{
    @Override
    public void actionPerformed(ActionEvent e)
    {
        JButton button = (JButton)e.getSource();
        JTextComponent textField = getFocusedComponent();
        textField.replaceSelection( button.getText() );
    }
}

JButton button0 = new JButton("0");
button0.addActionListener(digit);
JButton button1 = new JButton("1");
button1.addActionListener(digit);

The above action is generic, so it can be used by all your buttons. It will simply append the text of the button to the last text field that had focus.

Question:


Answer:

You need:

JFrame frame = new JFrame();
        JTextField text = new JTextField();
        frame.add(text);
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowOpened(WindowEvent e) {
                text.requestDefaultFocus();
            }
        });

Question:

I'm trying to build a JPopupMenu that appears on mouse entering in a specific component. This JPopupMenu contains a JTextField for value editing (numbers). Since I cannot know in advance the length of the number that will be edited, I'd like to make my popup resizing after each key is typed. I achieved this by adding KeyListener to the JTextField and trying to handle the focus. My trick works, but I meet the following problems when I build the application:

  • Every time I call the pack() method, the focus moves from JtextField to another component and then comes back to JtextField thanks to the requestFocus() method (this makes my windows continuously flickering). In this case, to make the other component not focusable could not be a solution to me.
  • JPopupMenu disappears when its size so as to exit from the window.

I attach an abstract of my code below. Is there a better way to achieve my goal? Or to manage the issues caused by the use of both pack() and requestFocus() methods?

package prova;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JRootPane;
import javax.swing.JTextField;

public class Main {
    public final static void main(String[] args ){
        JFrame frame = new JFrame();
        JPanel p = (JPanel)frame.getContentPane();
        p.setLayout(new BorderLayout());
        p.setPreferredSize(new java.awt.Dimension(100,100));

        JLabel l = new JLabel("my label");
        l.setOpaque(true);
        l.setPreferredSize(new java.awt.Dimension(50,20));
        l.setBackground(Color.white);

        JPopupMenu pop = new JPopupMenu();

        JTextField textField = new JTextField("edit text");
        textField.addKeyListener(new KeyListener() {

            @Override
            public void keyTyped(KeyEvent e) {}

            @Override
            public void keyReleased(KeyEvent e) {
                pop.pack();
                ((JTextField)e.getSource()).requestFocus();
            }

            @Override
            public void keyPressed(KeyEvent e) {}
        });



        l.addMouseListener(new MouseListener() {

            @Override
            public void mouseReleased(MouseEvent e) {}

            @Override
            public void mousePressed(MouseEvent e) {}

            @Override
            public void mouseExited(MouseEvent e) {}

            @Override
            public void mouseEntered(MouseEvent e) {
                if(!pop.isVisible()){
                    pop.show((java.awt.Component)e.getSource(), e.getX(), e.getY());
                }
            }

            @Override
            public void mouseClicked(MouseEvent e) {}
        });

        pop.add(textField);
        p.add(l,BorderLayout.EAST);

        frame.pack();
        frame.setVisible(true);
    }
}

Answer:

For the first problem:

Solution:

@Override
public void keyReleased(KeyEvent e) {
    Window window = SwingUtilities.getWindowAncestor(pop);
    window.pack();
}

I think(!) the reason for the flicker effect is because JPopupMenu doesn't extend Window in it's class hierarchy (see below), and the pack() method is designed for windows only.

 java.lang.Object
    java.awt.Component
        java.awt.Container
            javax.swing.JComponent
                javax.swing.JPopupMenu 

For the second problem:

I don't understand what you mean by that, the popupmenu doesn't disappear for me when it's size is "too big" (if that is what you meant).

Question:

Developing an application in swing, just a little query :- I want to clear the current focus owner textfield using a button. It is possible to determine whether a textfield is the current focus owner or not using isFocusOwner() but how to clear the textfield which is currently on focus?

Thanks!!!


Answer:

You might be able use a TextAction. A TextAction has access to the last text component that had focus. So then in the text action you just clear the text in the component. All the logic is fully contained in the one place.

Here is an example that demonstrates the concept of using a TextAction. In this case the number represented by the button is appended to the text field with focus:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.text.*;

public class NumpadPanel extends JPanel
{
    public NumpadPanel()
    {
        setLayout( new BorderLayout() );

        JTextField textField1 = new JTextField(4);
        JTextField textField2 = new JTextField(2);
        JTextField textField3 = new JTextField(2);

        JPanel panel = new JPanel();
        panel.add( textField1 );
        panel.add( textField2 );
        panel.add( textField3 );
        add(panel, BorderLayout.PAGE_START);

        Action numberAction = new TextAction("")
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                JTextComponent textComponent = getFocusedComponent();

                if (textComponent != null)
                    textComponent.replaceSelection(e.getActionCommand());
            }
        };

        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout( new GridLayout(0, 5) );
        add(buttonPanel, BorderLayout.CENTER);

        for (int i = 0; i < 10; i++)
        {
            String text = String.valueOf(i);
            JButton button = new JButton( text );
            button.addActionListener( numberAction );
            button.setMargin( new Insets(20, 20, 20, 20) );
            button.setFocusable( false );
            buttonPanel.add( button );
        }
    }

    private static void createAndShowUI()
    {
        JFrame frame = new JFrame("Numpad Panel");
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        frame.add( new NumpadPanel() );
        frame.pack();
        frame.setLocationRelativeTo( null );
        frame.setVisible(true);
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowUI();
            }
        });
    }
}

In your case instead of using the replaceSelection() method you would just use the setText() method.

Question:

The code below can trigger two actions:

- the "Paste" action triggered by the "Paste" JButton or "Ctrl V" KeyStroke.
- the "Close" action triggered by the "Close" JButton or "Esc" KeyStroke.

Each action will work if :

- you do not select a JTextField and you click the JButton.
- you do not select a JTextField and you use the Keystroke.
- you select a JTextField and you click the JButton.

If the content of two cells of a spreasheet is copied, the "Paste" action will paste the content of each cell in the corresponding JTextField. The "Close" action will close the JFrame.

However, it will not work if :

- you select a JTextField and you use the Keystroke.

If the content of two cells of a spreasheet is copied, the "Paste" action will paste the content of all cells in the selected JTextField. The "Close" action will not close the JFrame. How can I solve this ?

I tried many things, given for instance at How to UnFocus a JTextField. I am missing something since none of them worked.

Thanks in advance for your answers.

Here is the code :

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.datatransfer.DataFlavor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.Scanner;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingConstants;

public class Test extends JFrame implements ActionListener {

    private static JTextField[] A;
    private static JButton[] B;

    public static void main(String[] args) {
        Test F = new Test();
        JPanel H = new JPanel();
        F.setContentPane(H);
        A = new JTextField[2];
        B = new JButton[2];
        B[0] = new JButton("Paste");
        H.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_V,InputEvent.CTRL_MASK),"0");
        H.getActionMap().put("0",new AbstractAction() {
            public void actionPerformed(ActionEvent J) {
                B[0].doClick();
            }
        });
        B[1] = new JButton("Close");
        H.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE,0),"1");
        H.getActionMap().put("1",new AbstractAction() {
            public void actionPerformed(ActionEvent J) {
                B[1].doClick();
            }
        });
        GridBagLayout I = new GridBagLayout();
        H.setLayout(I);
        for (int i=0;i<A.length;i++) {
            A[i] = new JTextField();
            A[i].setHorizontalAlignment(SwingConstants.CENTER);
            A[i].setPreferredSize(new Dimension((int)B[i].getPreferredSize().getWidth(),(int)A[i].getPreferredSize().getHeight()));
            I.setConstraints(A[i],new GridBagConstraints(0,i,1,1,0,0,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
            H.add(A[i]);
        }
        for (int i=0;i<B.length;i++) {
            B[i].addActionListener(F);
            B[i].setActionCommand(String.valueOf(i));
            I.setConstraints(B[i],new GridBagConstraints(0,A.length+i,1,1,0,0,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
            H.add(B[i]);
        }
        F.pack();
        F.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        F.setLocationRelativeTo(null);
        F.setTitle("Parameters");
        F.setVisible(true);
    }

    public void actionPerformed(ActionEvent J) {
        if(J.getActionCommand().equals("0")) {
            try {
                if (Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null)!=null && Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null).isDataFlavorSupported(DataFlavor.stringFlavor) && A[0].isEditable() && A[1].isEditable()) {
                    Scanner D = new Scanner((String)Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null).getTransferData(DataFlavor.stringFlavor));
                    A[0].setText(String.valueOf(D.next()));
                    A[1].setText(String.valueOf(D.next()));
                    D.close();
                }
            }
            catch (Throwable K) {
                System.out.println("Paste failed");
            }
        }
        if (J.getActionCommand().equals("1")) {
            this.dispose();
        }
    }

}

Answer:

The code above doesn't even enter the ActionMap of the JPanel when a JTextField is selected. Thus a solution I found is to add the ActionMap of the JPanel to each JTextField by adding:

        A[i].getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_V,InputEvent.CTRL_MASK),"0");
        A[i].getActionMap().put(String.valueOf("0"),new AbstractAction() {
            public void actionPerformed(ActionEvent J) {
                B[0].doClick();
            }
        });
        A[i].getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE,0),"1");
        A[i].getActionMap().put(String.valueOf("1"),new AbstractAction() {
            public void actionPerformed(ActionEvent J) {
                B[1].doClick();
            }
        });

after:

A[i] = new JTextField();

Question:

I made a landing interface in Java using NetBeans. I want to set when the textfield input format does not meet the requirements, then Red tips occur, how to achieve this? I know it is related to focus event, but I do not know the details


Answer:

I suggest that use ActionEvent and ActionListener for textfield.

then use textfield.getText() to get String data.

you can now examine the String's content by separate it.

If you wanna check the format is a number or not, just use NumberFormatException.

https://docs.oracle.com/javase/7/docs/api/java/lang/NumberFormatException.html

after that,

you want a red warning tip, use label with color red, and .setVisible(boolean) to control it shows or not.

Question:

I have a very strange scenario which unfortunately I cannot prevent from occurring in my Swing application. When it occurs however, it has major consequences for me. Perhaps somebody could help!

The basic setup is as follows:

  • Linux environment.
  • Multiple JTextFields in a JFrame.
  • JTextFields push through transferFocus() when the Enter key is pressed.
  • A JDialog pops up on leaving one of the fields which requires the Enter key to be pressed to remove it.

The situation that causes the issue is as follows:

  • The Enter key is held down for a few seconds.

When the enter key is held down, the focus obviously flies through the different text fields. When the dialog box is shown, the enter key closes it causing the focus to then continue to fly through the text fields. Eventually, within a couple of seconds, Java breaks. The textboxes immediately stop responding to key strokes - you cannot type anything in them at all. Other than that, everything seems normal - you can click around and focus on different textboxes, close the application etc.

I have created a simple test case you can use to recreate the situation.

The JFrame:

public class TestSwing extends JFrame {

    JTextField jtfText1, jtfText2, jtfText3;
    TextHandler handler = null;

    public TestSwing() {
        super("TextField Test Demo");
        Container container = getContentPane();
        container.setLayout(new FlowLayout());
        jtfText1 = new MyJTextField(10);
        jtfText2 = new MyJTextField(10);
        jtfText3 = new MyJTextField(10);
        container.add(jtfText1);
        container.add(jtfText2);
        container.add(jtfText3);
        handler = new TextHandler();
        jtfText3.addActionListener(handler);
        setSize(325, 100);
        setVisible(true);
    }
    private class TextHandler implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            JOptionPane.showConfirmDialog(null, "wait!");
        }
    }
    public static void main(String args[]) {
        TestSwing test = new TestSwing();
        test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}

The custom JTextField:

public class MyJTextField extends JTextField {    
    public MyJTextField(int len) {
        super(len);
        addKeyListener(new KeyAdapter() {
              public void keyPressed(KeyEvent evt) {
                int key = evt.getKeyCode();
                if (key == KeyEvent.VK_ENTER)
                  transferFocus();
              }
        });
    }
}

To answer any potential questions up front:

  • The Enter key must be used to transfer the focus.
  • The spamming of the Enter key comes from the user leaving something on the keyboard (this is in the retail environment so this happens often).
  • Simply closing and restarting the application is not really an option as there is no mouse plugged into the computer. The application is booted up automatically on start-up making this scenario devastating as the only way to fix the problem is to restart the machine.
  • The machines aren't very powerful (processing & memory) which somehow causes the issue to happen a lot quicker than when it's recreated on a development machine.

Is this a bug in Java? Can anyone think of a way to prevent this from happening?

The closest I can get to preventing this from happening is to put a sleep(500) call in the JDialog (mine is extended) before it closes but that's not really a great fix...

I have tested this in JDK 1.6, 1.7 and 1.8. While it takes a bit longer in the later versions for the textboxes to become unresponsive, it still happens eventually.

Thanks in advance!

Xandel


Answer:

Don't use KeyEvents. KeyEvents are generally used in AWT. Swing has newer and better API's to use (in most cases). In this case a JTextField was designed to respond to an ActionEvent when the Enter key is pressed.

You could try to keep track of the last time Enter was pressed and ignore events that seem to be invoked within the repeat rate of the OS. My repeat rate appears to be around 35ms:

import java.awt.event.*;
import javax.swing.*;

public class MyJTextField extends JTextField
{
    private static long lastTime = System.currentTimeMillis();

    public MyJTextField(int len)
    {
        super(len);
        addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent evt)
            {

                long diff = evt.getWhen() - lastTime;
                System.out.println(diff);

                if (diff > 50)
                {
                    transferFocus();
                }

                lastTime = evt.getWhen();
            }
        });
    }
}

Question:


Answer:

Working code Demo : You can use MouseAdapter and override MouseListener

As you wan to clear the JtextField when user clicks inside it. You need to add addMouseListener and override mouseClicked.

import java.awt.FlowLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JFrame;
import javax.swing.JTextField;

public class ClearJtextField {

    public ClearJtextField() {

        JFrame frame = new JFrame();
        frame.setLayout(new FlowLayout(FlowLayout.CENTER, 120, 120));
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JTextField tf = new JTextField("Type something and click");
        // adding MouseAdapter and overriding mouseClicked
        tf.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                tf.setText("");
            }
        });

        frame.addMouseListener(new MouseAdapter() {

            public void mouseClicked(MouseEvent e) {
                if (tf.getText().length() == 0)
                    tf.setText("Type something and click");

            }

        });

        frame.add(tf);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        new ClearJtextField();

    }

}

Above code will clear the JTextField on click and again set text back to "Type something and click" if JTextField is empty when user click outside the JTextField.

Question:

I have a view in Java where I am entering data in JTextfields. A thread is running in parallel that gets input from a keypad by using snippets of code written below. Now whenever I call

JTextField c = (JTextField) manager.getFocusOwner();
c.getText();

where the manager is

KeyboardFocusManager.getCurrentFocusManager();

It does return the text of the current JTextField but when I call the following line, it returns null.

c.getName();

Why is this happening and how should I solve this?


Answer:

You never set a name for the text field in the first place. You can't .getName if you haven't .setName.

Cheers!