如何使用格式化文本字段

原文: https://docs.oracle.com/javase/tutorial/uiswing/components/formattedtextfield.html

格式化文本字段为开发人员提供了一种指定可在文本字段中键入的有效字符集的方法。具体来说, JFormattedTextField 类将格式化程序和对象添加到从JTextField类继承的特征。格式化程序将字段的值转换为它显示的文本,将文本转换为字段的值。

使用 Swing 提供的格式化程序,您可以设置格式化文本字段,以本地化格式键入日期和数字。另一种格式化程序使您可以使用字符掩码来指定可在字段中的每个位置键入的字符集。例如,您可以指定用于以特定格式键入电话号码的掩码,例如(XX)X-XX-XX-XX-XX。

如果格式化文本字段的可能值具有明显的顺序,请改用微调器。微调器默认使用格式化文本字段,但添加了两个按钮,使用户可以选择序列中的值。

使用格式化文本字段的另一个替代或辅助是在字段上安装输入验证程序。当组件几乎失去键盘焦点时,将调用组件的输入验证器。输入验证程序使您可以检查组件的值是否有效,并可选择更改它或停止传输焦点。

此 GUI 使用格式化文本字段以四种不同格式显示数字。

A snapshot of FormattedTextFieldDemo


Try this:

  1. 单击“启动”按钮以使用 Java™Web Start下载 JDK 7 或更高版本)运行 FormattedTextFieldDemo。或者,要自己编译并运行示例,请参考示例索引Launches the FormattedTextFieldDemo Application

  2. 尝试不同的贷款金额,年度百分比率(APR)和贷款期限。 请注意,只要您输入的文本有效,当您按 Enter 键或将焦点移出您正在编辑的字段时,月份付款字段就会更新。

  3. 在 Loan Amount 字段中键入无效文本,例如“abcd”,然后按 Enter 键。 月付款字段保持不变。当您从“贷款金额”字段移动焦点时,文本将恢复为该字段的上一个有效值。
  4. 在贷款金额字段中键入边际有效的文本,例如“2000abcd”,然后按 Enter 键。 月度付款字段已更新,但贷款金额字段仍显示2000abcd。当您从“贷款金额”字段移动焦点时,它显示的文本将更新为其值的整齐格式版本,例如“2,000”。

您可以在 FormattedTextFieldDemo.java中找到该程序的完整代码。此代码创建第一个字段。

  1. amountField = new JFormattedTextField(amountFormat);
  2. amountField.setValue(new Double(amount));
  3. amountField.setColumns(10);
  4. amountField.addPropertyChangeListener("value", this);
  5. ...
  6. amountFormat = NumberFormat.getNumberInstance();

用于创建amountField对象的构造器采用java.text.Format参数。字段的格式化程序使用Format对象将字段的值转换为文本,将文本转换为字段的值。

其余代码设置amountField对象。 setValue方法将字段的 value 属性设置为表示为Double对象的浮点数。从JTextField类继承的setColumns方法提示字段的首选大小。对addPropertyChangeListener方法的调用为该字段的 value 属性注册一个监听器,因此每当用户更改贷款金额时,程序都可以更新每月付款字段。

本节的其余部分包括以下主题:

本节不解释从JTextField类继承的 API。该 API 在如何使用文本字段中描述。

以下代码创建并初始化FormattedTextFieldDemo示例中的其余三个字段。

  1. rateField = new JFormattedTextField(percentFormat);
  2. rateField.setValue(new Double(rate));
  3. rateField.setColumns(10);
  4. rateField.addPropertyChangeListener("value", this);
  5. numPeriodsField = new JFormattedTextField();
  6. numPeriodsField.setValue(new Integer(numPeriods));
  7. numPeriodsField.setColumns(10);
  8. numPeriodsField.addPropertyChangeListener("value", this);
  9. paymentField = new JFormattedTextField(paymentFormat);
  10. paymentField.setValue(new Double(payment));
  11. paymentField.setColumns(10);
  12. paymentField.setEditable(false);
  13. paymentField.setForeground(Color.red);
  14. ...
  15. percentFormat = NumberFormat.getNumberInstance();
  16. percentFormat.setMinimumFractionDigits(2);
  17. paymentFormat = NumberFormat.getCurrencyInstance();

设置rateField对象的代码几乎与之前为其他字段列出的代码相同。唯一的区别是,由于代码percentFormat.setMinimumFractionDigits(2),格式略有不同。

创建numPeriodsField对象的代码未显式设置格式或格式化程序。相反,它将值设置为Integer并使该字段能够使用Integer对象的默认格式化程序。代码在前两个字段中没有执行此操作,因为默认格式化程序未用于Double对象。结果不是所需要的。本节后面将介绍如何指定格式和格式化程序。

付款字段与其他字段不同,因为它不可编辑,为其文本使用不同的颜色,并且没有属性更改监听器。否则,它与其他字段相同。我们本可以选择使用文本字段标签。无论组件是什么,我们仍然可以使用paymentFormat方法将付款金额解析为要显示的文本。

使用带格式的文本字段时,请记住以下几点:


格式化文本字段的文本及其是两个不同的属性,值通常落后于文本。


text 属性由JTextField类定义。此属性始终反映字段显示的内容。由JFormattedTextField类定义的属性可能不会反映字段中显示的最新文本。当用户键入时,text 属性会更改,但 value 属性不会更改,直到更改为。

更准确地说,可以使用setValue方法或commitEdit方法设置格式化文本字段的值。 setValue方法将值设置为指定的参数。该参数在技术上可以是任何Object,但格式化程序需要能够将其转换为字符串。否则,文本字段不显示任何实质性信息。

commitEdit方法将值设置为格式化程序确定的任何对象,由字段的文本表示。发生以下任一情况时,将自动调用commitEdit方法:

  • 当用户按下 Enter 键时,该字段具有焦点。
  • 默认情况下,当字段失去焦点时,例如,当用户按 Tab 键将焦点更改为另一个组件时。当字段失去焦点时,您可以使用setFocusLostBehavior方法指定不同的结果。

Note:

某些格式化程序可能会不断更新值,导致焦点丢失毫无意义,因为值始终与文本指定的值相同。


设置格式化文本字段的值时,将更新字段的文本以反映该值。具体如何将值表示为文本取决于字段的格式化程序。

请注意,虽然JFormattedTextField类继承了JTextField类的setText方法,但通常不会在格式化的文本字段上调用setText方法。如果这样做,字段的显示会相应更改但值不会更新(除非字段的格式化程序不断更新)。

要获取格式化文本字段的当前值,请使用getValue方法。如有必要,可以通过在getValue之前调用commitEdit方法来确保该值反映文本。因为getValue方法返回Object,所以需要将其强制转换为用于字段值的类型。例如:

  1. Date enteredDate = (Date)dateField.getValue();

要检测格式化文本字段值的更改,可以在格式化文本字段上注册属性更改监听器,以侦听对“value”属性的更改。属性更改监听器取自FormattedTextFieldDemo示例:

  1. //The property change listener is registered on each
  2. //field using code like this:
  3. // someField.addPropertyChangeListener("value", this);
  4. /** Called when a field's "value" property changes. */
  5. public void propertyChange(PropertyChangeEvent e) {
  6. Object source = e.getSource();
  7. if (source == amountField) {
  8. amount = ((Number)amountField.getValue()).doubleValue();
  9. } else if (source == rateField) {
  10. rate = ((Number)rateField.getValue()).doubleValue();
  11. } else if (source == numPeriodsField) {
  12. numPeriods = ((Number)numPeriodsField.getValue()).intValue();
  13. }
  14. double payment = computePayment(amount, rate, numPeriods);
  15. paymentField.setValue(new Double(payment));
  16. }

Format 类提供了一种格式化区域设置敏感信息(如日期和数字)的方法。来自 InternationalFormatter 类的格式化程序,例如 DateFormatterNumberFormatter 类,使用Format对象在字段之间进行转换文字和价值。您可以通过调用 DateFormatNumberFormat 类中的一种工厂方法,或使用 SimpleDateFormat之一来获取Format对象构造器。


Note:

第三种常用的格式化程序类MaskFormatter不是来自InternationalFormatter类而不使用格式。 MaskFormatter中使用 MaskFormatter 进行了讨论。


您可以在创建Format对象时自定义某些格式方面,而通过特定于格式的 API 自定义其他格式方面。例如, DecimalFormat 对象继承自NumberFormat并且通常由其工厂方法返回,可以使用setMaximumFractionDigitssetNegativePrefix方法进行自定义。有关使用Format对象的信息,请参阅国际化路径的格式化课程。

将自定义格式与格式化文本字段相关联的最简单方法是使用以Format作为参数的JFormattedTextField构造器创建字段。您可以在之前的代码示例中看到创建amountFieldrateField对象的关联。

MaskFormatter 类实现了一个格式化程序,它准确指定字段文本的每个位置中哪些字符有效。例如,以下代码创建MaskFormatter,允许用户键入五位邮政编码:

  1. zipField = new JFormattedTextField(
  2. createFormatter("#####"));
  3. ...
  4. protected MaskFormatter createFormatter(String s) {
  5. MaskFormatter formatter = null;
  6. try {
  7. formatter = new MaskFormatter(s);
  8. } catch (java.text.ParseException exc) {
  9. System.err.println("formatter is bad: " + exc.getMessage());
  10. System.exit(-1);
  11. }
  12. return formatter;
  13. }

您可以通过运行TextInputDemo来尝试上述代码的结果。单击“启动”按钮以使用 Java™Web Start下载 JDK 7 或更高版本)运行 TextInputDemo。或者,要自己编译并运行示例,请参考示例索引

Launches the TextInputDemo Application

显示程序的 GUI。

A snapshot of TextInputDemo

下表显示了可以在格式设置掩码中使用的字符:

字符 描述
任何有效数字(Character.isDigit)。

(单引号) | 转义字符,用于转义任何特殊格式字符。 | | ü | 任何字符(Character.isLetter)。所有小写​​字母都映射为大写。 | | 大号 | 任何字符(Character.isLetter)。所有大写字母都映射为小写。 | | 一个 | 任何字符或数字(Character.isLetterCharacter.isDigit)。 | | ? | 任何字符(Character.isLetter)。 | | * | 任何东西。 | | H | 任何十六进制字符(0-9,a-f 或 A-F)。 |

指定格式化程序时,请记住每个格式化程序对象最多只能由一个格式化文本字段使用。每个字段应至少有一个与之关联的格式化程序,其中任何一个都可以随时使用。

您可以通过多种方式指定格式化文本字段使用的格式化程序:

  • 使用带有Format参数的JFormattedTextField构造器。 自动创建使用指定格式的字段格式化程序。
  • 使用带有JFormattedTextField.AbstractFormatter参数的JFormattedTextField构造器。 指定的格式化程序用于该字段。
  • 设置未指定格式,格式化程序或格式化程序工厂的格式化文本字段的值。 默认格式化工厂将格式化程序分配给字段,使用字段值的类型作为指导。如果值为Date,则格式化程序为DateFormatter。如果值为Number,则格式化程序为NumberFormatter。其他类型导致DefaultFormatter的实例。
  • 使格式化文本字段使用返回自定义格式化程序对象的格式化程序工厂。 这是最灵活的方法。当您想要将多个格式化程序与字段关联或添加要用于多个字段的新格式化程序时,它非常有用。前一种用法的示例是解释用户以某种方式键入但以另一种方式显示值(当用户未键入时)的字段。后一种用法的一个例子是具有自定义类值的几个字段,例如PhoneNumber。您可以设置字段以使用格式化工厂返回电话号码的专用格式化程序。

您可以通过使用带有格式化程序工厂参数的构造器创建字段,或者通过在字段上调用setFormatterFactory方法来设置字段的格式化程序工厂。要创建格式化程序工厂,通常可以使用 DefaultFormatterFactory 类的实例。使用DefaultFormatterFactory对象可以指定在编辑值,未编辑值或具有空值时返回的格式化程序。

下图显示了基于FormattedTextFieldDemo示例的应用程序,该示例使用 formatter 工厂为 Loan Amount 和 APR 字段设置多个编辑器。当用户正在编辑贷款金额时,不使用$字符,因此不会强制用户键入它。同样,在用户编辑 APR 字段时,不需要%字符。

单击“启动”按钮以使用 Java™Web Start下载 JDK 7 或更高版本)运行 FormatterFactoryDe​​mo。或者,要自己编译并运行示例,请参考示例索引

Launches the FormatterFactoryDemo Application

FormatterFactoryDemo, with amount field being edited FormatterFactoryDemo, with no custom editors installed

以下代码创建格式化程序并使用DefaultFormatterFactory类的实例进行设置:

  1. private double rate = .075; //7.5 %
  2. ...
  3. amountField = new JFormattedTextField(
  4. new DefaultFormatterFactory(
  5. new NumberFormatter(amountDisplayFormat),
  6. new NumberFormatter(amountDisplayFormat),
  7. new NumberFormatter(amountEditFormat)));
  8. ...
  9. NumberFormatter percentEditFormatter =
  10. new NumberFormatter(percentEditFormat) {
  11. public String valueToString(Object o)
  12. throws ParseException {
  13. Number number = (Number)o;
  14. if (number != null) {
  15. double d = number.doubleValue() * 100.0;
  16. number = new Double(d);
  17. }
  18. return super.valueToString(number);
  19. }
  20. public Object stringToValue(String s)
  21. throws ParseException {
  22. Number number = (Number)super.stringToValue(s);
  23. if (number != null) {
  24. double d = number.doubleValue() / 100.0;
  25. number = new Double(d);
  26. }
  27. return number;
  28. }
  29. };
  30. rateField = new JFormattedTextField(
  31. new DefaultFormatterFactory(
  32. new NumberFormatter(percentDisplayFormat),
  33. new NumberFormatter(percentDisplayFormat),
  34. percentEditFormatter));
  35. ...
  36. amountDisplayFormat = NumberFormat.getCurrencyInstance();
  37. amountDisplayFormat.setMinimumFractionDigits(0);
  38. amountEditFormat = NumberFormat.getNumberInstance();
  39. percentDisplayFormat = NumberFormat.getPercentInstance();
  40. percentDisplayFormat.setMinimumFractionDigits(2);
  41. percentEditFormat = NumberFormat.getNumberInstance();
  42. percentEditFormat.setMinimumFractionDigits(2);

粗体代码突出显示对DefaultFormatterFactory构造器的调用。构造器的第一个参数指定用于格式化文本字段的默认格式化程序。第二个参数指定显示格式化程序,在字段没有焦点时使用。第三个参数指定编辑格式化程序,该字段具有焦点时使用。代码不使用第四个参数,但如果是,则第四个参数将指定 null 格式化程序,当字段的值为 null 时使用该格式化程序。由于未指定 null 格式化程序,因此在值为 null 时使用默认格式化程序。

该代码通过创建NumberFormatter类的子类来自定义使用percentEditFormat的格式化程序。此子类重写NumberFormattervalueToStringstringToValue方法,以便将显示的数字转换为计算中实际使用的值,并将值转换为数字。具体而言,显示的数字是实际值的 100 倍。原因是显示格式化程序使用的百分比格式自动将文本显示为值的 100 倍,因此相应的编辑器格式化程序必须以相同的值显示文本。 FormattedTextFieldDemo示例不需要处理此转换,因为此演示仅使用一种格式进行显示和编辑。

您可以在 FormatterFactoryDemo.java中找到整个程序的代码。

下表列出了一些使用格式化文本字段的常用 API。

类或接口 目的
JFormattedTextField JTextField的子类,支持格式化任意值。
JFormattedTextField.AbstractFormatter JFormattedTextField的所有格式化程序的超类。格式化程序强制执行编辑策略和导航策略,处理字符串到对象的转换,并根据需要操作JFormattedTextField以强制执行所需的策略。
JFormattedTextField.AbstractFormatterFactory 所有格式化工厂的超类。每个JFormattedTextField使用格式化程序工厂来获取最符合文本字段状态的格式化程序。
DefaultFormatterFactory 格式化工厂通常使用。提供基于细节的格式化程序,例如传入的参数和焦点状态。
DefaultFormatter JFormattedTextField.AbstractFormatter的子类,使用toString方法格式化任意对象。
MaskFormatter DefaultFormatter的子类,使用指定的字符掩码格式化和编辑字符串。 (例如,可以使用“### - ####”指定七位数的电话号码。)
国际格式 DefaultFormatter的子类,它使用java.text.Format的实例来处理与String之间的转换。
NumberFormatter InternationalFormatter的子类,通过使用NumberFormat的实例支持数字格式。
DateFormatter InternationalFormatter的子类,它使用DateFormat的实例支持日期格式。
方法或构造器 目的
JFormattedTextField()

JFormattedTextField(Object) JFormattedTextField(格式) JFormattedTextField(AbstractFormatter) JFormattedTextField(AbstractFormatterFactory) JFormattedTextField(AbstractFormatterFactory,Object) | 创建新的格式化文本字段。 Object参数(如果存在)指定字段的初始值,并导致创建适当的格式化程序工厂。 FormatAbstractFormatter参数指定要用于字段的格式或格式化程序,并导致创建适当的格式化程序工厂。 AbstractFormatterFactory参数指定要使用的格式化程序工厂,它确定用于字段的格式化程序。 | | void setValue(Object) Object getValue() | 设置或获取格式化文本字段的值。必须根据JFormattedTextField的配置方式强制转换返回类型。如果尚未设置格式化程序,则调用setValue会将格式化程序设置为字段格式化程序工厂返回的格式化程序。 | | void setFormatterFactory(AbstractFormatterFactory) | 设置确定用于格式化文本字段的格式化程序的对象。该对象通常是DefaultFormatterFactory类的实例。 | | AbstractFormatter getFormatter() | 获取格式化文本字段的格式化程序。格式化程序通常是DefaultFormatter类的一个实例。 | | void setFocusLostBehavior(int) | 指定失去焦点的字段的结果。可能的值在JFormattedTextField中定义为COMMIT_OR_REVERT(默认值),COMMIT(如果有效则提交,否则保持一切相同),PERSIST(不执行任何操作)和REVERT(更改文本以反映价值)。 | | void commitEdit() | 将值设置为字段文本所表示的对象,由字段的格式化程序确定。如果文本无效,则值保持不变,并抛出 ParseException 。 | | boolean isEditValid() | 如果格式化程序认为当前文本有效,则返回 true,由字段的格式化程序确定。 |

方法 目的
void setCommitsOnValidEdit(boolean)

boolean getCommitsOnValidEdit() | 将编辑推回JFormattedTextField时设置或获取值。如果在每次有效编辑后调用truecommitEdit。默认情况下,此属性为false。 | | void setOverwriteMode(boolean) boolean getOverwriteMode() | 设置或获取插入字符时的行为。如果true,新字符会在插入模型时覆盖模型中的现有字符。该属性的默认值为DefaultFormatter中的true(因此在MaskFormatter中)和InternationalFormatter中的false(因此在DateFormatterNumberFormatter中)。 | | void setAllowsInvalid(boolean) boolean getAllowsInvalid() | 设置或解释正在编辑的值是否允许在一段时间内无效。在尝试commitEdit方法之前,通常可以方便地使用户键入无效值。 DefaultFormatter将此属性初始化为true。在标准 Swing 格式化程序中,只有MaskFormatter将此属性设置为false。 |

此表列出了使用格式化文本字段的示例,并指出了描述这些示例的位置。

在哪里描述 笔记
FormattedTextFieldDemo 这个部分 使用四个格式化的文本字段。
SpinnerDemo 如何使用旋转器 自定义两个微调器使用的格式化文本字段的外观。
转换器 使用型号 每个ConversionPanel将带格式的文本字段与滑块配对。
TextInputDemo 这个部分 显示如何一起使用文本字段,微调器和格式化文本字段,并演示如何使用MaskFormatter。包括用于选择刚刚获得焦点的字段文本的代码。
FormatterFactoryDe​​mo 这个部分 FormattedTextFieldDemo 的一个变体,它使用格式化工厂为两个格式化的文本字段指定多个格式化程序。