[英]InputVerifier incorrectly yielding focus and need advice using it with other ActionListener methods
I have a GUI in which the user enters measurements into a number of fields and calculates a result based on the measurement. 我有一个GUI,用户可以在其中将测量值输入许多字段,并根据测量值计算结果。 I am trying to implement the following for the fields- 我正在尝试对以下字段实施以下操作:
I've done something like this with tables (the model retained the values in 'standard' units and a custom renderer and cell editor handled showing the user the values in the current units and storing the values in the 'standard' units in the model). 我已经使用表格做了类似的事情(模型以“标准”单位保留值,并且自定义渲染器和单元格编辑器处理了向用户显示当前单位的值并将值存储在模型中的“标准”单位中的情况) )。
I don't believe JTextField has a renderer to override, the Document editor looked a bit daunting, and the user didn't like the JFormattedTextField, so I thought I would create a custom JTextField that stored a 'standard' value and use the inputVerifier that I used previously for the table. 我不相信JTextField可以覆盖渲染器,Document编辑器看起来有些令人生畏,并且用户不喜欢JFormattedTextField,所以我想我会创建一个自定义JTextField来存储“标准”值并使用inputVerifier我以前在桌子上使用过的
Example code is below (it almost works). 示例代码如下(几乎可以使用)。 I used a JComboBox as a stand-in for the option dialog and implemented only one text field. 我使用JComboBox作为选项对话框的替代,仅实现了一个文本字段。
I could use some expert advice- 我可以使用一些专家意见-
Volume value changed (f) // my focus listener fired off Updating model // from my focus listener Verifying: 'aa' // from my input verifier Invalid number // from my input verifier 体积值已更改(f)//我的焦点侦听器已启动//从我的焦点侦听器更新模型//验证:'aa'//来自我的输入验证器//无效的数字//来自我的输入验证器
the text box gets a red outline and I hear a beep, but the combobox is active. 文本框显示为红色轮廓,并且听到哔声,但组合框处于活动状态。 The text field ends up with an empty value, since the combobox action listener is called when I change its value. 文本字段以空值结尾,因为当我更改其值时会调用组合框动作监听器。 Why am I allowed to change the combox value? 为什么允许我更改combox的值? How do I stop that? 我该如何阻止呢?
I want the text field to be validated and the view of the underlying data updated either when the user enters (CR) and stays in the field or when they leaves the field. 我希望验证文本字段,并在用户输入(CR)并停留在字段中或离开字段时更新基础数据的视图。 Which is why the action and focus listeners. 这就是为什么动作和焦点侦听器如此。
Any corrections or insights are most welcome. 任何改正或见解是最欢迎的。
UnitsTextField.java UnitsTextField.java
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class UnitsTextField extends JTextField
{
Double modelValue = null;
Double viewValue = null;
UnitsTextField( int cols )
{
super( cols );
}
public void updateModel() throws Exception
{
System.out.println( "Updating model" );
modelValue = Conversion.modelValue( this.getText() );
}
public void refreshView()
{
this.setText( Conversion.viewString( modelValue ) );
}
public Double getModelValue()
{
return modelValue;
}
}
UnitsLabel.java UnitsLabel.java
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class UnitsLabel extends JLabel
{
public void refreshView()
{
super.setText( Conversion.viewLabel() );
}
}
Conversion.java Conversion.java
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class Conversion
{
public static enum UNITS {CC, L, GAL};
public static Map<String,UNITS> unitTypes =
new HashMap<String, UNITS>()
{
{
put( "Cubic centimeters", UNITS.CC );
put( "Liters", UNITS.L );
put( "Gallons", UNITS.GAL );
}
};
public static Map<UNITS,Double> unitConversions =
new HashMap<UNITS, Double>()
{
{
put( UNITS.CC, 1.0 );
put( UNITS.L, 1000.0 );
put( UNITS.GAL, 4404.9 );
}
};
private static UNITS unitType = UNITS.CC;
public static void setUnitType( UNITS unit )
{
unitType = unit;
}
public static void setUnitType( String unitString )
{
unitType = unitTypes.get(unitString);
}
public static String[] getUnitNames()
{
return (unitTypes.keySet()).toArray(new String[0]);
}
public static String viewLabel()
{
return unitType.toString();
}
public static Double modelValue( String viewString ) throws Exception
{
Double value = null;
if (viewString != null && viewString.length() > 0)
{
value = Double.parseDouble( viewString );
value = value * unitConversions.get(unitType);
}
return value;
}
public static String viewString( Double modelValue )
{
Double value = null;
if (modelValue != null)
{
value = modelValue / unitConversions.get(unitType);
}
return (value == null) ? "" : value.toString();
}
}
DoubleVerifier.java DoubleVerifier.java
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import java.text.NumberFormat;
import java.awt.Toolkit;
public class DoubleVerifier extends InputVerifier implements ActionListener
{
public boolean shouldYieldFocus(JComponent input)
{
JTextField tf = (JTextField) input;
boolean inputOK = verify(input);
if (inputOK)
{
tf.setBorder( new LineBorder( Color.black ) );
return true;
}
else
{
tf.setBorder( new LineBorder( Color.red ) );
Toolkit.getDefaultToolkit().beep();
return false;
}
}
public boolean verify(JComponent input)
{
JTextField tf = (JTextField) input;
String txt = tf.getText();
double n;
System.out.println( "Verifying: '" + txt + "'" );
if (txt.length() != 0)
{
try
{
n = Double.parseDouble(txt);
}
catch (NumberFormatException nf)
{
System.out.println( "Invalid number" );
return false;
}
}
return true;
}
public void actionPerformed(ActionEvent e)
{
System.out.println( "Input verification" );
JTextField source = (JTextField) e.getSource();
shouldYieldFocus(source);
}
}
VolumeTextFieldTest.java VolumeTextFieldTest.java
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
class VolumeTextFieldTest extends JFrame
{
private JComboBox volumeCombo;
private UnitsLabel volumeLabel;
private UnitsTextField volumeField;
public VolumeTextFieldTest()
{
setSize(300, 100);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
volumeCombo = new JComboBox( Conversion.getUnitNames() );
volumeCombo.addActionListener( new VolumeListener() );
volumeCombo.addFocusListener( new VolumeListener() );
volumeLabel = new UnitsLabel();
volumeLabel.refreshView();
volumeField = new UnitsTextField(8);
DoubleVerifier dVerify = new DoubleVerifier();
volumeField.setInputVerifier( dVerify );
volumeField.addActionListener( dVerify );
volumeField.addActionListener( new VolumeValueListener() );
volumeField.addFocusListener( new VolumeValueListener() );
JPanel myPane = new JPanel();
myPane.add(volumeCombo);
myPane.add(volumeField);
myPane.add(volumeLabel);
getContentPane().add(myPane);
setVisible(true);
}
public class VolumeListener implements ActionListener, FocusListener
{
@Override
public void actionPerformed( ActionEvent ae )
{
System.out.println( "Volume type changed" );
Conversion.setUnitType( (String) volumeCombo.getSelectedItem() );
volumeLabel.refreshView();
volumeField.refreshView();
}
@Override
public void focusGained( FocusEvent fg )
{
}
@Override
public void focusLost( FocusEvent fl )
{
System.out.println( "Volume type changed" );
Conversion.setUnitType( (String) volumeCombo.getSelectedItem() );
volumeLabel.refreshView();
volumeField.refreshView();
}
}
public class VolumeValueListener implements ActionListener, FocusListener
{
@Override
public void actionPerformed( ActionEvent ae )
{
System.out.println( "Volume value changed (a)" );
try
{
volumeField.updateModel();
volumeField.refreshView();
}
catch (Exception e)
{}
}
@Override
public void focusGained( FocusEvent fg )
{
}
@Override
public void focusLost( FocusEvent fl )
{
System.out.println( "Volume value changed (f)" );
try
{
volumeField.updateModel();
volumeField.refreshView();
}
catch (Exception e)
{}
}
}
public static void main(String[] args)
{
try
{
SwingUtilities.invokeLater( new Runnable()
{
public void run ()
{
VolumeTextFieldTest runme = new VolumeTextFieldTest();
}
});
}
catch (Exception e)
{
System.out.println( "GUI did not start" );
}
}
}
I understand part of my problem from additional research. 通过其他研究,我了解了部分问题。 InputVerifier is only concerned with focus. InputVerifier仅关注焦点。 If the input is invalid, then it will not transfer focus, however, it will allow action events to occur. 如果输入无效,那么它将不会转移焦点,但是,它将允许发生操作事件。 The complaints I have seen have been related to people who had an exit button whose action would be performed even if the data in a field was invalid. 我所看到的投诉与那些具有退出按钮的人有关,即使该字段中的数据无效,该按钮也将执行操作。 In my case, I have a combobox whose action can still be performed even though the InputVerifier is complaining about the invalid data (text field gets a red border and beeps). 就我而言,我有一个组合框,即使InputVerifier抱怨无效数据(文本字段显示红色边框并发出哔哔声),其操作仍然可以执行。 So in respect to that aspect of the problem, I don't believe there is a good solution. 因此,就问题的这一方面而言,我认为没有好的解决方案。 One suggestion was a variable that all the action listeners checked before performing the action, which would be set by the InputVerifier. 一个建议是一个变量,在执行操作之前,所有操作侦听器都会对其进行检查,该变量将由InputVerifier设置。 I've got my (ideally) reusable routines in separate files, so will have some problems with this solution. 我的(理想情况下)可重用的例程位于单独的文件中,因此此解决方案将存在一些问题。
I'm still unsure of how to gracefully handle the situation where I have a several distinct generic actions (verify input, convert units, update a view) where only some will be needed for any given field and I want to assign ActionListeners and FocusListeners in sequential order. 我仍然不确定如何妥善处理以下情况:我有几个不同的通用动作(验证输入,转换单位,更新视图),其中任何给定字段仅需要一些动作,并且我想在其中分配ActionListener和FocusListener顺序顺序。 My only thought right now is to have a base listener, that for example verifies input, then extend it and override the actionPerformed, focusGained and focusLost methods, though it seems like I will end up duplicating code for every combination. 我现在唯一的想法就是拥有一个基本的侦听器,例如,验证输入,然后扩展输入并覆盖actionPerformed,focusGained和focusLost方法,尽管看起来我最终将为每个组合复制代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.