我有一个 GUI,用户可以在其中将测量值输入多个字段并根据测量值计算结果。我正在尝试为这些字段实现以下内容 -
- 输入的值必须在适当的范围内
- 我有一个选项对话框,其中包括设置单位。任何包含值的字段都必须更新为当前单位
- 当字段中的值发生变化时,我需要查看是否输入了所有测量值,如果是,则执行(或重做)计算。
我已经用表格做了类似的事情(模型保留了“标准”单位中的值,并且自定义渲染器和单元格编辑器处理了向用户显示当前单位中的值并将值存储在模型中的“标准”单位中)。
我不相信 JTextField 有要覆盖的渲染器,文档编辑器看起来有点吓人,而且用户不喜欢 JFormattedTextField,所以我想我会创建一个自定义 JTextField 来存储“标准”值并使用 inputVerifier我以前用于表的。
示例代码如下(它几乎可以工作)。我使用 JComboBox 作为选项对话框的替代品,并且只实现了一个文本字段。
我可以使用一些专家的建议-
- 我可能误解了 setInputVerifier。我认为如果我尝试从文本字段更改焦点并在我说不产生焦点时将焦点保持在文本字段中,则应该调用它。但是,如果我在文本字段中输入“aa”(不按回车键),我可以更改组合框中的值。我的调试 println 说-
Volume value changed (f) // 我的焦点监听器触发了更新模型 // 从我的焦点监听器验证:'aa' //来自我的输入验证器 无效的数字 //来自我的输入验证器
文本框出现红色轮廓,我听到哔声,但组合框处于活动状态。文本字段以空值结束,因为当我更改其值时会调用组合框操作侦听器。为什么允许我更改组合框的值?我该如何阻止它?
- 我添加一个 InputVerifier、两个 ActionListener 和一个 FocusListener 似乎是错误的。我确实喜欢任务的逻辑分离。我应该做什么?我是否应该扩展 DoubleVerifier 并覆盖 actionPerformed 以仅包含 DoubleVerifier 中当前的内容以及 VolumeValueListener 中的内容?
我希望验证文本字段,并在用户输入 (CR) 并留在字段中或离开字段时更新基础数据的视图。这就是为什么行动和焦点听众。
欢迎任何更正或见解。
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
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class UnitsLabel extends JLabel
{
public void refreshView()
{
super.setText( Conversion.viewLabel() );
}
}
转换.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
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
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" );
}
}
}