Заставить JSpinner выделять текст при фокусировке
Я хотел бы изменить поведение JSpinner, чтобы при нажатии на текст он выделялся. Это облегчает замену поля желаемым значением. К сожалению, я не могу заставить поведение работать, и вместо этого он просто вставляет курсор в текст без выбора того, что уже есть.
Я попытался добавить слушатель фокуса как к самому JSpinner, так и к самой текстовой области, через ((DefaultEditor) this.getEditor()).getTextField()
Тем не менее ни один из них, кажется, не имеет ожидаемого эффекта. Мой код (для самого JSpinner) выглядит следующим образом:
spinner.addFocusListener(new FocusAdapter(){
@Override
public void focusGained(FocusEvent e) {
((DefaultEditor) ((JSpinner) e.getSource()).getEditor()).getTextField().selectAll();
}
});
Я не уверен, в чем проблема. Если это имеет значение, я использую Mac OS 10.7.5 и Java 6u43.
РЕДАКТИРОВАТЬ: я положил System.out.println
в самом начале метода focusGained и обнаружил, что он никогда не вызывался. Похоже, что фокус на JSpinner не регистрируется. Опять же, я попытался поместить focusAdpater и на счетчик, и на текстовое поле (но не одновременно).
3 ответа
Большая часть проблемы, с которой вы сталкиваетесь, связана с тем, как счетчик проверяет любые значения внутри счетчика ПОСЛЕ события фокусировки (и нескольких других событий состояния), которые обойдут выделение.
MacOS еще хуже.
В итоге я начал Thread
который ждал очень короткий период времени (около 25 миллисекунд), а затем использовал SwingUtilities.invokeLater
на самом деле выполнить выбор...
Обновлено с примером
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.text.JTextComponent;
public class AutoFocusSpinner {
public static void main(String[] args) {
new AutoFocusSpinner();
}
public static final SelectOnFocusGainedHandler SHARED_INSTANCE = new SelectOnFocusGainedHandler();
public AutoFocusSpinner() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JSpinner spinner = new JSpinner(new SpinnerNumberModel(1, 0, 100, 1));
installFocusListener(spinner);
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
frame.add(spinner);
frame.add(new JButton("Here for testing"));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public void installFocusListener(JSpinner spinner) {
JComponent spinnerEditor = spinner.getEditor();
if (spinnerEditor != null) {
// This is me spending a few days trying to make this work and
// eventually throwing a hissy fit and just grabbing all the
// JTextComponent components contained within the editor....
List<JTextComponent> lstChildren = findAllChildren(spinner, JTextComponent.class);
if (lstChildren != null && lstChildren.size() > 0) {
JTextComponent editor = lstChildren.get(0);
editor.addFocusListener(SHARED_INSTANCE);
}
}
}
public static <T extends Component> List<T> findAllChildren(JComponent component, Class<T> clazz) {
List<T> lstChildren = new ArrayList<T>(5);
for (Component comp : component.getComponents()) {
if (clazz.isInstance(comp)) {
lstChildren.add((T) comp);
} else if (comp instanceof JComponent) {
lstChildren.addAll(findAllChildren((JComponent) comp, clazz));
}
}
return Collections.unmodifiableList(lstChildren);
}
public static class SelectOnFocusGainedHandler extends FocusAdapter {
@Override
public void focusGained(FocusEvent e) {
Component comp = e.getComponent();
if (comp instanceof JTextComponent) {
final JTextComponent textComponent = (JTextComponent) comp;
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(25);
} catch (InterruptedException ex) {
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
textComponent.selectAll();
}
});
}
}).start();
}
}
}
}
Теперь, прямо сейчас, я молюсь о каком-то действительно хорошем, простом, недокументированном свойстве, которое мы можем установить, что будет означать, что нам не нужно делать все это:P
Не знаю насчет Mac, но я использовал этот код в Windows:
JSpinner.DefaultEditor editor = (JSpinner.DefaultEditor)spinner.getEditor();
JTextField textField = editor.getTextField();
textField.addFocusListener( new FocusAdapter()
{
public void focusGained(final FocusEvent e)
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
JTextField tf = (JTextField)e.getSource();
tf.selectAll();
}
});
}
});
Я также использовал этот код для выбора текста в JFormattedTextField.
Для меня оба вышеупомянутых решения @MadProgrammer и @camickr могут сфокусироваться на счетчике, но не на выделенном тексте. Я могу увеличить или уменьшить значение моего счетчика. Также у меня работает клавиша табуляции, поэтому я могу выбрать JTextField моего счетчика после нажатия клавиши табуляции.
Чтобы имитировать нажатие клавиши табуляции, у меня сработало следующее решение. Это я вызываю сразу после решения, предоставленного @MadProgrammer и @camickr. Заставить JSpinner выделять текст при фокусировке