当前位置: 首页 > 知识库问答 >
问题:

InputVerifier错误地产生焦点,需要建议将其与其他ActionListener方法一起使用

南宫云
2023-03-14

我有一个GUI,用户在其中将测量值输入多个字段,并根据测量值计算结果。我正在尝试为字段实现以下内容-

  1. 输入的值必须在适当的范围内
  2. 我有一个选项对话框,其中包括设置单位。任何有值的字段都必须更新为当前单位
  3. 当字段中的值发生变化时,我需要查看是否输入了所有测量值,如果是,则执行(或重做)计算。

我用表格做过类似的事情(模型保留了“标准”单位中的值,并处理了一个自定义渲染器和单元编辑器,向用户显示当前单位中的值,并将值存储在模型中的“标准”单位中)。

我不相信JTextField有渲染器要覆盖,文档编辑器看起来有点令人生畏,而且用户不喜欢JFormattedTextField,所以我想我会创建一个存储“标准”值的自定义JTextField并使用我之前用于表的inputVerifier。

下面是示例代码(它几乎可以工作)。我使用JComboBox作为选项对话框的替代,只实现了一个文本字段。

我需要一些专家的建议

  1. 我可能误解了setInputVerifier。我认为如果我试图从文本字段更改焦点并在文本字段中保持焦点,如果我说不产生焦点,则应该调用它。但是如果我在文本字段中放入'aa'(不点击Enter),我可以更改组合框中的值。我的调试println说-

音量值已更改(f)//我的焦点侦听器启动更新模型//来自我的焦点侦听器验证:'aa'//来自我的输入验证器无效数字//来自我的输入验证器

文本框有一个红色的轮廓,我听到一声蜂鸣,但组合框是活动的。文本字段以空值结束,因为当我更改其值时会调用combobox操作侦听器。为什么允许我更改combox值?我该怎么阻止呢?

  1. 我添加一个InputVerifier、两个ActionListener和一个FocusListener似乎是错误的。我确实喜欢任务的逻辑分离。我该怎么办?我是否应该扩展DoubleVerifier并覆盖执行的操作,只包括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;
   }
} 

单位Label.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();
   }
}

双重验证器。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" );
      }
   }
}

共有1个答案

景国兴
2023-03-14

我从额外的研究中了解了部分问题。InputVerifier只关注焦点。如果输入无效,则不会转移焦点,但会允许操作事件发生。我所看到的投诉与那些有退出按钮的人有关,即使某个字段中的数据无效,也会执行该按钮的操作。在我的例子中,我有一个组合框,即使InputVerifier抱怨无效数据(文本字段有一个红色边框并发出哔哔声),它的操作仍然可以执行。因此,关于问题的这一方面,我认为没有好的解决方案。一个建议是,所有操作侦听器在执行操作之前都要检查一个变量,该变量将由InputVerifier设置。我的(理想情况下)可重用例程都放在不同的文件中,所以这个解决方案会有一些问题。

我仍然不确定如何优雅地处理这样的情况:我有几个不同的通用操作(验证输入、转换单元、更新视图),其中任何给定字段都只需要一些操作,我想按顺序分配ActionListeners和FocusListeners。我现在唯一的想法是有一个基本的监听器,比如验证输入,然后扩展它并覆盖actionPerformed、FocusGain和focusLost方法,尽管看起来我最终会为每个组合复制代码

 类似资料:
  • 我仍然是Java的新手,我正在努力使这个程序适合我的任务。 问题是: 杰夫在你家附近经营着一家当地的零售店。他已与您签订合同,让您创建一个交互式应用程序,以帮助他增加员工工资。创建一个名为 Details 的类,该类将包含员工 ID 号、名字、姓氏和薪水的获取和设置方法。包括一个名为getUpdateSalary()的方法,该方法将使员工的薪水增加10%。在您的主类中,包括一个名为 () 的静态方

  • 用 assert 测试编码和设计错误。如果其返回false,则程序终止,应纠正代码。这种方法在调试时很有用处。 忽略异常,这不适合公开发布的软件产品和任务关键的专用软件。但自用软件通常可以忽略许多错误。 退出程序,使程序无法运行完毕或产生错误结果。实际上,对于许多错误类型,这是个好办法,特别是对于能让程序运行完毕的非致命错误,因为让程序运行完毕很可能使程序员误以为程序工作很顺利。这种方法也不适合任

  • 我想将ListView与其他小部件一起使用,但我不能。当我将容器用于ListView时,我不能查看任何其他小部件。我该怎么做?

  • 问题内容: 我真的需要Babel或其他编译器在React中使用ES6吗? 我正在看图表https://kangax.github.io/compat- table/es6/ 好像我当前的浏览器Chrome(最新的稳定版)几乎支持所有ES6功能… 如果我可以在没有Babel的情况下使用ES6,该怎么办? 问题答案: 没有babel,您将获得所链接图表的兼容性。但是请记住,如果要使用JSX,则需要使用

  • 问题内容: 我在else语句上不断收到语法错误,但不确定为什么会继续产生此错误。我在相同的def中没有其他任何语句,但仍然会出错。我该怎么办? 问题答案: 您的log_f.write语句还缺少结尾的’)’,这可能会使解析器感到困惑…并且缩进看起来不正确。剪切和粘贴问题?

  • 问题内容: 好的,所以我确实搜索了这个问题,并显示了可观的结果。尽管它们似乎都具有完全不同的场景,并且每种解决方案都不相同,所以我有点困惑。 基本上,我有一个Driver类,它运行我的程序并包含main方法。我有第二堂课,其中提供了几种编辑聚会的方法(例如游戏中的角色聚会)。我想要做的是这(主要方法的一部分) 其中很多只是一些后台代码,问题在于 我得到了错误 那么,如何在我的主类中从另一个类调用此