Java InputVerifier错误地产生焦点,需要建议将其与其他ActionListener方法一起使用
我有一个GUI,用户在其中将测量值输入多个字段,并根据测量值计算结果。我正在尝试为字段实现以下内容-Java InputVerifier错误地产生焦点,需要建议将其与其他ActionListener方法一起使用,java,actionlistener,inputverifier,Java,Actionlistener,Inputverifier,我有一个GUI,用户在其中将测量值输入多个字段,并根据测量值计算结果。我正在尝试为字段实现以下内容- 输入的值必须在正确的范围内 我有一个选项对话框,其中包括设置单位。任何包含值的字段都必须更新为当前单位 当字段中的值发生变化时,我需要查看是否输入了所有测量值,如果输入了,则执行(或重做)计算 我对表格做过类似的操作(模型保留了“标准”单位中的值,并处理了一个自定义渲染器和单元编辑器,向用户显示当前单位中的值,并将值存储在模型中的“标准”单位中) 我不相信JTextField有一个要重写的渲染器
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
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
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();
}
}
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" );
}
}
}
我从额外的研究中了解了部分问题。InputVerifier只关注焦点。如果输入无效,则不会转移焦点,但会允许发生操作事件。我所看到的投诉与那些有退出按钮的人有关,即使某个字段中的数据无效,也会执行该按钮的操作。在我的例子中,我有一个组合框,即使InputVerifier抱怨无效数据(文本字段得到红色边框并发出蜂鸣声),它的操作仍然可以执行。因此,关于问题的这一方面,我认为没有好的解决办法。一个建议是所有操作侦听器在执行操作之前检查一个变量,该变量将由InputVerifier设置。我在单独的文件中有我的(理想的)可重用例程,所以这个解决方案会有一些问题
我仍然不确定如何优雅地处理这样一种情况:我有几个不同的通用操作(验证输入、转换单元、更新视图),其中任何给定字段都只需要一些操作,并且我希望按顺序分配ActionListeners和FocusListeners。我现在唯一的想法是有一个基本的侦听器,例如验证输入,然后扩展它并覆盖actionPerformed、FocusGain和focusLost方法,尽管看起来我最终会为每个组合复制代码。geez太多了抱歉,实现函数的最低要求是在文本字段中存储模型值,然后让它显示不同的视图并进行验证。您想要一个只显示文本字段对组合框失去焦点的示例吗?那会短一点,最好是这样。如果您知道最有可能导致问题的代码段(在本例中,似乎是纯粹的Swing代码,尽管情况可能并非如此),那么最好提供SSCCE—请参阅以了解更多详细信息。这样一来,问题就与重要的问题隔离开来,你会因为得到帮助而得到更好的改变:)
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" );
}
}
}