I'm trying to add a FocusListener
over some JTextFields
and JFormattedTextFields
, did all right, and when the class loads up, the listener works properly, it's a simple method to select all text on the TextFields when focus is gained, but the TextField.selectAll()
only works once, then when I focus something else, ant return the focus to the Field it does nothing, but the listener itself is working, I tried adding a System.out.println(evt.getComponent())
and it prints out the result, but the focus does not select all text anymore...
The whole Frame class is huge and very specific with some IDE generated code ¯\_(ツ)_/¯, thats why I'm adding just two fields, that I believe may help understand what I've got here...
tfVencimento = new javax.swing.JFormattedTextField(dateMask());
tfValorBruto = new javax.swing.JFormattedTextField(decimalMask());
tfValorBruto.setFormatterFactory(new javax.swing.text.DefaultFormatterFactory(new javax.swing.text.NumberFormatter(new java.text.DecimalFormat("#,##0.00"))));
tfValorBruto.setText("0,00");
tfValorBruto.setMargin(new java.awt.Insets(2, 4, 2, 4));
tfValorBruto.setMinimumSize(new java.awt.Dimension(70, 22));
tfValorBruto.setPreferredSize(new java.awt.Dimension(70, 22));
tfValorBruto.addFocusListener(new java.awt.event.FocusAdapter() {
public void focusGained(java.awt.event.FocusEvent evt) {
FocusGained(evt);
}
});
tfVencimento.setMargin(new java.awt.Insets(2, 4, 2, 4));
tfVencimento.setMinimumSize(new java.awt.Dimension(70, 22));
tfVencimento.setPreferredSize(new java.awt.Dimension(70, 22));
tfVencimento.addFocusListener(new java.awt.event.FocusAdapter() {
public void focusGained(java.awt.event.FocusEvent evt) {
FocusGained(evt);
}
});
private void FocusGained(java.awt.event.FocusEvent evt) {
JTextField field = (JFormattedTextField) evt.getComponent();
field.selectAll();
}
I thought it could be something that overrides my listener, didn't find anything...
Maybe the way I applied the listener, tried a few ways and all got there...
If I apply on each Field a listener, with a different method on each (like code below), it works, but I have 10+ Fields, so it's boring to do, and a hard maintaining code...
tfVencimento.addFocusListener(new java.awt.event.FocusAdapter() {
public void focusGained(java.awt.event.FocusEvent evt) {
tfVencimentoFocusGained(evt);
}
});
private void tfVencimentoFocusGained(java.awt.event.FocusEvent evt) {
tfVencimento.selectAll();
}
I see a couple of options:
Option A. Call tfValorBruto.setCaret(new DefaultCaret());
Option B. In FocusGained
: move the call to selectAll()
inside an invoke-later Runnable, so it runs a little bit later. Like this:
private void FocusGained(java.awt.event.FocusEvent evt) {
JTextField field = (JFormattedTextField) evt.getComponent();
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
field.selectAll();
}
});
}
I used this code to help debug it:
tfValorBruto = new javax.swing.JFormattedTextField() {
public void moveCaretPosition(int pos) {
super.moveCaretPosition(pos);
}
public void setCaretPosition(int position) {
super.setCaretPosition(position);
}
};
You can add a debugger breakpoint in moveCaretPosition(int)
. It showed that on FOCUS_GAINED events someone was calling moveCaretPosition(0)
Breakpoint reached
at com.test.FocusTest$1.moveCaretPosition(FocusTest.java:22)
at com.apple.laf.AquaCaret.focusGained(AquaCaret.java:135)
at java.awt.AWTEventMulticaster.focusGained(AWTEventMulticaster.java:228)
at java.awt.AWTEventMulticaster.focusGained(AWTEventMulticaster.java:227)
at java.awt.AWTEventMulticaster.focusGained(AWTEventMulticaster.java:227)
at java.awt.Component.processFocusEvent(Component.java:6509)
at javax.swing.JFormattedTextField.processFocusEvent(JFormattedTextField.java:645)
at java.awt.Component.processEvent(Component.java:6376)
at java.awt.Container.processEvent(Container.java:2266)
at java.awt.Component.dispatchEventImpl(Component.java:4995)
at java.awt.Container.dispatchEventImpl(Container.java:2324)
at java.awt.Component.dispatchEvent(Component.java:4827)
at java.awt.KeyboardFocusManager.redispatchEvent(KeyboardFocusManager.java:1952)
at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(DefaultKeyboardFocusManager.java:1061)
at java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:687)
at java.awt.Component.dispatchEventImpl(Component.java:4876)
at java.awt.Container.dispatchEventImpl(Container.java:2324)
at java.awt.Component.dispatchEvent(Component.java:4827)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:775)
at java.awt.EventQueue$4.run(EventQueue.java:720)
at java.awt.EventQueue$4.run(EventQueue.java:714)
at java.security.AccessController.executePrivileged(AccessController.java:776)
at java.security.AccessController.doPrivileged(AccessController.java:399)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:97)
at java.awt.EventQueue$5.run(EventQueue.java:747)
at java.awt.EventQueue$5.run(EventQueue.java:745)
at java.security.AccessController.executePrivileged(AccessController.java:776)
at java.security.AccessController.doPrivileged(AccessController.java:399)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:744)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
So in my case: the default look-and-feel implementation (Aqua) was trying to set up some default behavior when it received a FOCUS_GAINED event.
We can either replace the Caret (that's solution A), or we can change the selection again after Aqua (that's solution B)