我想知道JFormattedTextField
与默认按钮结合使用的方式是否正确。编辑JFormattedTextField
的值时,通常需要提交该值,然后使用它,这种情况通常发生在focusLost
上,有时也发生在手动触发ActionListener
时。现在,如果这样的文本字段位于定义了DefaultButton
的JDialog
内部,则用Ctrl+Enter触发默认按钮不会导致当前关注的JFormattedTextField
触发其focusLost
事件。
现在,我看到了两种解决方案:
- 手动确保所有inupt字段都处于委托(或还原(状态
- 在默认按钮的
ActionListener
中使用SwingUtilities.InvokeLater
然而,这两个似乎都很脏,尤其是第一个,因为在不忘记处理组件的情况下扩展所述对话框不是很容易。第二种是不可取的imo,因为更多的invokeLater
通常意味着更多的代码更难调试。
有更好的方法解决这个问题吗?
示例:
import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class DefaultButton
{
public static void main( String[] args )
{
JFrame frame = new JFrame();
JFormattedTextField field = new JFormattedTextField();
field.setValue( "HELLO" );
JButton defaultButton = new JButton( "Default" );
defaultButton.addActionListener( __ ->
{
JOptionPane.showMessageDialog( frame, "You've chosen: " + field.getValue() );
} );
frame.getRootPane().setDefaultButton( defaultButton );
JPanel panel = new JPanel( new BorderLayout() );
panel.add( field, BorderLayout.NORTH );
panel.add( defaultButton, BorderLayout.SOUTH );
frame.add( panel );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE );
frame.setVisible( true );
}
}
是,当JFormattedTextField
具有输入焦点并且您激活defaultButton
时,JFormattedTextField
不会失去焦点,因此不会提交该值。
请参阅如何使用格式化的文本字段
这里有一个报价:
格式化文本字段的文本及其值是两个不同的属性,并且该值通常滞后于文本
text属性由JTextField
类定义。此属性始终反映字段显示的内容。JFormattedTextField
类定义的值属性可能无法反映字段中显示的最新文本。当用户键入时,text属性会更改,但value属性不会更改,直到提交更改。
我看到了两种可能的解决方案(尽管我认为还有更多(
在actionPerformed()
方法中,调用getText()
而不是getValue()
,或者在调用getValue()
之前调用commitEdit()
,即
JOptionPane.showMessageDialog( frame, "You've chosen: " + field.getText() );
或
try {
field.commitEdit();
}
catch (java.text.ParseException x) {
x.printStackTrace();
}
JOptionPane.showMessageDialog(frame, "You've chosen: " + field.getValue());
编辑
我相信这就是你想要的。
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.KeyboardFocusManager;
import javax.swing.JButton;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class DefaultButton
{
public static void main( String[] args )
{
JFrame frame = new JFrame();
JFormattedTextField field = new JFormattedTextField();
field.setValue( "HELLO" );
JButton defaultButton = new JButton( "Default" );
defaultButton.addActionListener( __ ->
{
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
if (kfm.getFocusOwner() == field) {
kfm.focusNextComponent();
}
EventQueue.invokeLater(() -> JOptionPane.showMessageDialog( frame, "You've chosen: " + field.getValue() ));
} );
frame.getRootPane().setDefaultButton( defaultButton );
JPanel panel = new JPanel( new BorderLayout() );
panel.add( field, BorderLayout.NORTH );
panel.add( defaultButton, BorderLayout.SOUTH );
frame.add( panel );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE );
frame.setVisible( true );
}
}
专注于方法actionPerformed()
。如果JFormattedTextField
当前具有焦点,则强制焦点移动到下一个组件。无论哪个组件具有键盘焦点,都要将JOptionPane
的显示封装在invokeLater()
调用中。