簡體   English   中英

InputVerifier錯誤地產生了焦點,需要與其他ActionListener方法一起使用的建議

[英]InputVerifier incorrectly yielding focus and need advice using it with other ActionListener methods

我有一個GUI,用戶可以在其中將測量值輸入許多字段,並根據測量值計算結果。 我正在嘗試對以下字段實施以下操作:

  1. 輸入的值必須在正確的范圍內
  2. 我有一個選項對話框,其中包括設置單位。 任何包含值的字段都必須更新為當前單位
  3. 當字段中的值更改時,我需要查看是否輸入了所有度量,如果是,則進行(或重做)計算。

我已經使用表格做了類似的事情(模型以“標准”單位保留值,並且自定義渲染器和單元格編輯器處理了向用戶顯示當前單位的值並將值存儲在模型中的“標准”單位中的情況) )。

我不相信JTextField可以覆蓋渲染器,Document編輯器看起來有些令人生畏,並且用戶不喜歡JFormattedTextField,所以我想我會創建一個自定義JTextField來存儲“標准”值並使用inputVerifier我以前在桌子上使用過的

示例代碼如下(幾乎可以使用)。 我使用JComboBox作為選項對話框的替代,僅實現了一個文本字段。

我可以使用一些專家意見-

  1. 我可能會誤解setInputVerifier。 我認為如果我嘗試從文本字段更改焦點並在我說不產生焦點的情況下保持焦點在文本字段中,則應該調用它。 但是,如果我在文本字段中輸入“ aa”(不按Enter),則可以更改組合框中的值。 我的調試println說-

體積值已更改(f)//我的焦點偵聽器已啟動//從我的焦點偵聽器更新模型//驗證:'aa'//來自我的輸入驗證器//無效的數字//來自我的輸入驗證器

文本框顯示為紅色輪廓,並且聽到嗶聲,但組合框處於活動狀態。 文本字段以空值結尾,因為當我更改其值時會調用組合框動作監聽器。 為什么允許我更改combox的值? 我該如何阻止呢?

  1. 我添加了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() );
   }
}

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

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" );
      }
   }
}

通過其他研究,我了解了部分問題。 InputVerifier僅關注焦點。 如果輸入無效,那么它將不會轉移焦點,但是,它將允許發生操作事件。 我所看到的投訴與那些具有退出按鈕的人有關,即使該字段中的數據無效,該按鈕也將執行操作。 就我而言,我有一個組合框,即使InputVerifier抱怨無效數據(文本字段顯示紅色邊框並發出嗶嗶聲),其操作仍然可以執行。 因此,就問題的這一方面而言,我認為沒有好的解決方案。 一個建議是一個變量,在執行操作之前,所有操作偵聽器都會對其進行檢查,該變量將由InputVerifier設置。 我的(理想情況下)可重用的例程位於單獨的文件中,因此此解決方案將存在一些問題。

我仍然不確定如何妥善處理以下情況:我有幾個不同的通用動作(驗證輸入,轉換單位,更新視圖),其中任何給定字段僅需要一些動作,並且我想在其中分配ActionListener和FocusListener順序順序。 我現在唯一的想法就是擁有一個基本的偵聽器,例如,驗證輸入,然后擴展輸入並覆蓋actionPerformed,focusGained和focusLost方法,盡管看起來我最終將為每個組合復制代碼。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM