Just Java IT

          西門町學士關于Java的隨便一說而已……

          JTextField內容有效性驗證幾種方式

          在使用 SwingJTextField時,我們常常希望只接受那些符合我們要求的錄入,如數字、電話號碼、郵政編碼、E-mail等。JFC工作組在這方面也做了很多工作,每一次新的Java Se發布,往往都提供了新的、更方便和強大的有效性驗證方式,在這里列舉幾種不同的驗證方式。

          • 利用鍵盤和焦點事件

          這是最直覺的方式。利用 KeyListener來選擇允許的字符,且添加FocusListener,使得

          內容不符合要求時不允許焦點轉移。這種方式很繁瑣, Sun的建議是不推薦使用這種方式。

          • 使用自定義的 Document

          我們知道, Swing組件是基于MVC實現的。JTextComponentModel是一個叫做DocumentInterface,我們可以通過限制Document的內容來達到有效性驗證的目的。javax.swing.text包中有多個不同的Document的實現,JTextField使用的是PlainDocument。如果我們希望JTextField只接受數字,可以實現我們特定的Document并使之替換默認的Document


             package sdn;

          import javax.swing.text.*;

          public class IntegerDocument extends PlainDocument {

          int currentValue = 0;

          public int getValue() {
          return currentValue;
          }

          public void insertString(int offset, String string,
          AttributeSet attributes) throws BadLocationException {

          if (string == null) {
          return;
          } else {
          String newValue;
          int length = getLength();
          if (length == 0) {
          newValue = string;
          } else {
          String currentContent = getText(0, length);
          StringBuffer currentBuffer =
          new StringBuffer(currentContent);
          currentBuffer.insert(offset, string);
          newValue = currentBuffer.toString();
          }
          currentValue = checkInput(newValue, offset);
          super.insertString(offset, string, attributes);
          }
          }
          public void remove(int offset, int length)
          throws BadLocationException {
          int currentLength = getLength();
          String currentContent = getText(0, currentLength);
          String before = currentContent.substring(0, offset);
          String after = currentContent.substring(length+offset,
          currentLength);
          String newValue = before + after;
          currentValue = checkInput(newValue, offset);
          super.remove(offset, length);
          }
          public int checkInput(String proposedValue, int offset)
          throws BadLocationException {
          if (proposedValue.length() > 0) {
          try {
          int newValue = Integer.parseInt(proposedValue);
          return newValue;
          } catch (NumberFormatException e) {
          throw new BadLocationException(proposedValue, offset);
          }
          } else {
          return 0;
          }
          }
          }

          然后用 IntegerDocument去替換JTextField默認的Document

             package sdn;

          import javax.swing.*;
          import javax.swing.text.*;
          import java.awt.*;
          import java.awt.event.*;

          public class NumericInput {
          public static void main(String args[]) {
          Runnable runner = new Runnable() {
          public void run() {
          JFrame frame = new JFrame("Numeric Input");
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          frame.setLayout(new GridLayout(2, 2));

          frame.add(new JLabel("Number"));
          JTextField fieldOne = new JTextField();
          Document doc= new IntegerDocument();
          fieldOne.setDocument(doc);
          frame.add(fieldOne);

          frame.add(new JLabel("All"));
          JTextField fieldTwo = new JTextField();
          frame.add(fieldTwo);

          frame.setSize(250, 90);
          frame.setVisible(true);
          }
          };
          EventQueue.invokeLater(runner);
          }
          }

          代碼很簡單,一目了然。這里說點題外話, Sun建議的Swing Applicationmain函數寫法如上所示:先建一個Runnable,然后把這個Runnable放到event-dispatch thread中去執行。另外,以前有的Developer(比如我)喜歡用SwingUtilities.invokeLater(runner)來將一個thread放到event-dispatch thread中,現在Sun也建議用EventQueue.invokeLater(runner),因為SwingUtilities方法版本僅僅是對EventQueue方法版本的一個包裝。

          • InputVerifier來實現

          J2SE 1.3中加入了一個名為InputVerifier的抽象類,可用于任何JComponent。其中定義了boolean verifiy(JComponent input)方法。如果組件中的文本是有效的,當焦點轉移時(如按下TabShift-Tab),verify方法返回true;否則返回false,使得焦點仍停留在當前組件上。我們仍以數字為例:

             package sdn;

          import java.awt.*;
          import java.awt.event.*;
          import javax.swing.*;

          public class NumericVerifier{
          public static void main(String args[]) {
          Runnable runner = new Runnable() {
          public void run() {
          JFrame frame = new JFrame("Numeric Verifier");
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

          JPanel panel1 = new JPanel(new BorderLayout());
          JLabel label1 = new JLabel("Numeric-only");
          JTextField textField1 = new JTextField();
          panel1.add(label1, BorderLayout.WEST);
          panel1.add(textField1, BorderLayout.CENTER);

          JPanel panel2 = new JPanel(new BorderLayout());
          JLabel label2 = new JLabel("Anything");
          JTextField textField2 = new JTextField();
          panel2.add(label2, BorderLayout.WEST);
          panel2.add(textField2, BorderLayout.CENTER);

          JPanel panel3 = new JPanel(new BorderLayout());
          JLabel label3 = new JLabel("Numeric-only");
          JTextField textField3 = new JTextField();
          panel3.add(label3, BorderLayout.WEST);
          panel3.add(textField3, BorderLayout.CENTER);

          InputVerifier verifier = new InputVerifier() {
          public boolean verify(JComponent comp) {
          boolean returnValue;
          JTextField textField = (JTextField)comp;
          try {
          Integer.parseInt(textField.getText());
          returnValue = true;
          } catch (NumberFormatException e) {
          Toolkit.getDefaultToolkit().beep();
          returnValue = false;
          }
          return returnValue;
          }
          };

          textField1.setInputVerifier(verifier);
          textField3.setInputVerifier(verifier);

          frame.add(panel1, BorderLayout.NORTH);
          frame.add(panel2, BorderLayout.CENTER);
          frame.add(panel3, BorderLayout.SOUTH);
          frame.setSize(300, 95);
          frame.setVisible(true);
          }
          };
          EventQueue.invokeLater(runner);
          }
          }

          這個例子的效果和上一個是不同的。自定義 DocumentApp中,用戶將會發現任何非數字的字符都不會在JTextField中出現;而在使用InputVerifierApp中,用戶在錄入字符時不會發現任何異常,但是當他確認錄入完成后,如果內容不符合有效性,焦點將不會轉移!這兩種情況都可能讓一個沒有經驗的用戶茫然,具體使用哪一種是一個見仁見智的問題。

          • 使用 Document Filter

          J2SE 1.4中,又加入了一個新的類:DocumentFilter。你無需再實現一個新的Document,而是對現有的Document過濾一遍。它的結果與實現自定義的Document并無二樣,僅僅是思路不同而已。

             package snd;
          import javax.swing.text.*;
          import java.awt.Toolkit;

          public class IntegerDocumentFilter extends DocumentFilter {


          int currentValue = 0;

          public IntegerDocumentFilter() {
          }

          public void insertString(DocumentFilter.FilterBypass fb,
          int offset, String string, AttributeSet attr)
          throws BadLocationException {

          if (string == null) {
          return;
          } else {
          replace(fb, offset, 0, string, attr);
          }
          }

          public void remove(DocumentFilter.FilterBypass fb,
          int offset, int length)
          throws BadLocationException {

          replace(fb, offset, length, "", null);
          }

          public void replace(DocumentFilter.FilterBypass fb,
          int offset, int length, String text, AttributeSet attrs)
          throws BadLocationException {

          Document doc = fb.getDocument();
          int currentLength = doc.getLength();
          String currentContent = doc.getText(0, currentLength);
          String before = currentContent.substring(0, offset);
          String after = currentContent.substring(
          length+offset, currentLength);
          String newValue = before +
          (text == null ? "" : text) + after;
          currentValue = checkInput(newValue, offset);
          fb.replace(offset, length, text, attrs);
          }

          private int checkInput(String proposedValue, int offset)
          throws BadLocationException {
          int newValue = 0;
          if (proposedValue.length() > 0) {
          try {
          newValue = Integer.parseInt(proposedValue);
          } catch (NumberFormatException e) {
          throw new BadLocationException(
          proposedValue, offset);
          }
          }
          return newValue;
          }
          }

          再將這個 Filter應用于Document

             package sdn;
          import javax.swing.*;
          import javax.swing.text.*;
          import java.awt.*;

          public class NumericInputFilter {
          public static void main(String args[]) {
          Runnable runner = new Runnable() {
          public void run() {
          JFrame frame = new JFrame("Numeric Input Filter");
          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          frame.setLayout(new GridLayout(2, 2));

          frame.add(new JLabel("Number"));
          JTextField textFieldOne = new JTextField();
          Document doc= textFieldOne.getDocument();
          DocumentFilter filterOne = new IntegerDocumentFilter();
          ((AbstractDocument)doc).setDocumentFilter(filterOne);
          textFieldOne.setDocument(doc);
          frame.add(textFieldOne);

          frame.add(new JLabel("All"));
          JTextField textFieldTwo = new JTextField();
          frame.add(textFieldTwo);

          frame.setSize(250, 90);
          frame.setVisible(true);
          }
          };
          EventQueue.invokeLater(runner);
          }
          }

          DocumentFilter只能用于Swing中的與text有關的組件(而InputVerifier可用于任何組件)。除了這幾種方法,在對于TextField而言,我們還有JFormattedTextField,很多時候用JFormattedTextField將是非常容易和簡單的方式。

          注:這篇文章基本根據SDN的Core Java Tech Tips意譯而來,代碼基本跟其一致,另外還參考了M. Robinson & P. Vorobiev的Swing, Chapter 11

          posted on 2006-04-09 16:26 西門町學士 閱讀(2364) 評論(0)  編輯  收藏 所屬分類: Java

          主站蜘蛛池模板: 上犹县| 老河口市| 阳东县| 红安县| 叶城县| 和林格尔县| 海宁市| 寿光市| 东港市| 文化| 华池县| 茶陵县| 海伦市| 蓝山县| 方城县| 盱眙县| 五寨县| 遂平县| 寻甸| 湖口县| 北碚区| 南丹县| 新宾| 崇明县| 钟山县| 元谋县| 丘北县| 新绛县| 固阳县| 泰兴市| 乐安县| 怀远县| 驻马店市| 新丰县| 南京市| 绥芬河市| 巢湖市| 鄂伦春自治旗| 巴彦淖尔市| 陈巴尔虎旗| 伽师县|