如何使用格式化的文本字段

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

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

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

使用格式化文本字段的另一种替代方法或附件是在该字段上安装input verifier。当组件几乎失去键盘焦点时,将调用组件的 Importing 验证程序。Importing 验证程序使您可以检查组件的值是否有效,并可以选择更改它或停止转移焦点。

该 GUI 使用格式化的文本字段来显示四种不同格式的数字。

FormattedTextFieldDemo 的快照

Try this:

  • 单击启动按钮以使用Java™Web 开始(下载 JDK 7 或更高版本)运行 FormattedTextFieldDemo。另外,要自己编译和运行示例,请查阅example index

  • 试用不同的贷款金额,年利率(APR)和贷款期限。
    请注意,只要您 Importing 的文本有效,当您按 Enter 键或将焦点移出您正在编辑的字段时,“月付款”字段就会更新。

  • 在“贷款金额”字段中键入无效的文本,例如“ abcd”,然后按 Enter。
    月付款字段保持不变。当您从“贷款金额”字段中移动焦点时,文本将还原为该字段的最后一个有效值。

  • 在“贷款金额”字段中 Importing 诸如“ 2000abcd”之类的边际有效文本,然后按 Enter。
    尽管“贷款金额”字段仍显示2000abcd,但“每月付款”字段已更新。当您从“贷款额”字段中移动焦点时,其显示的文本将更新为其值的整齐格式的版本,例如“ 2,000”。

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

amountField = new JFormattedTextField(amountFormat);
amountField.setValue(new Double(amount));
amountField.setColumns(10);
amountField.addPropertyChangeListener("value", this);
...
amountFormat = NumberFormat.getNumberInstance();

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

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

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

本节不解释从JTextField类继承的 API。该 API 在如何使用 Literals 栏位中进行了描述。

创建和初始化格式化的文本字段

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

rateField = new JFormattedTextField(percentFormat);
rateField.setValue(new Double(rate));
rateField.setColumns(10);
rateField.addPropertyChangeListener("value", this);

numPeriodsField = new JFormattedTextField();
numPeriodsField.setValue(new Integer(numPeriods));
numPeriodsField.setColumns(10);
numPeriodsField.addPropertyChangeListener("value", this);

paymentField = new JFormattedTextField(paymentFormat);
paymentField.setValue(new Double(payment));
paymentField.setColumns(10);
paymentField.setEditable(false);
paymentField.setForeground(Color.red);

...
percentFormat = NumberFormat.getNumberInstance();
percentFormat.setMinimumFractionDigits(2);

paymentFormat = NumberFormat.getCurrencyInstance();

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

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

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

设置和获取字段的值

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


格式化的文本字段的 text 及其 value 是两个不同的属性,该值通常滞后于文本.


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

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

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

  • 当用户按下该字段的焦点时,按 Enter 键。

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

Note:

一些格式化程序可能会不断更新该值,从而使失去焦点变得毫无意义,因为该值始终与文本指定的值相同。

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

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

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

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

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

//The property change listener is registered on each
//field using code like this:
//    someField.addPropertyChangeListener("value", this);

/** Called when a field's "value" property changes. */
public void propertyChange(PropertyChangeEvent e) {
    Object source = e.getSource();
    if (source == amountField) {
        amount = ((Number)amountField.getValue()).doubleValue();
    } else if (source == rateField) {
        rate = ((Number)rateField.getValue()).doubleValue();
    } else if (source == numPeriodsField) {
        numPeriods = ((Number)numPeriodsField.getValue()).intValue();
    }

    double payment = computePayment(amount, rate, numPeriods);
    paymentField.setValue(new Double(payment));
}

Specifying Formats

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

Note:

第三种常用的格式化程序类MaskFormatter并不从InternationalFormatter类派生,并且不使用格式。 MaskFormatterUsing MaskFormatter中讨论。

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

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

Using MaskFormatter

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

zipField = new JFormattedTextField(
                    createFormatter("#####"));
...
protected MaskFormatter createFormatter(String s) {
    MaskFormatter formatter = null;
    try {
        formatter = new MaskFormatter(s);
    } catch (java.text.ParseException exc) {
        System.err.println("formatter is bad: " + exc.getMessage());
        System.exit(-1);
    }
    return formatter;
}

您可以通过运行TextInputDemo来try前面代码的结果。单击启动按钮以使用Java™Web 开始(下载 JDK 7 或更高版本)运行 TextInputDemo。另外,要自己编译和运行示例,请查阅example index

显示程序的 GUI。

TextInputDemo 的快照

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

CharacterDescription
#任何有效数字(Character.isDigit)。
'

(单引号)
转义字符,用于转义任何特殊格式的字符。
U任何字符(Character.isLetter)。所有小写字母都 Map 为大写。
L任何字符(Character.isLetter)。所有大写字母都 Map 为小写字母。
A任何字符或数字(Character.isLetterCharacter.isDigit)。
任何字符(Character.isLetter)。
*Anything.
H任何十六进制字符(0-9,a-f 或 A-F)。

指定格式化程序并使用格式化程序工厂

指定格式化程序时,请记住,每个格式化程序对象一次最多只能被一个格式化的文本字段使用。每个字段至少应具有一个与其关联的格式化程序,该格式化程序可随时使用。

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

  • 使用带有Format参数的JFormattedTextField构造函数.
    将自动创建使用指定格式的字段格式化程序。

  • 使用带有JFormattedTextField.AbstractFormatter参数的JFormattedTextField构造函数.
    指定的格式化程序用于该字段。

  • 设置没有指定格式,格式化程序或格式化程序工厂的格式化文本字段的值.
    默认格式器工厂使用该字段值的类型作为指导,将格式器分配给该字段。如果值为Date,则格式化程序为DateFormatter。如果值为Number,则格式化程序为NumberFormatter。其他类型导致DefaultFormatter的实例。

  • 使格式化的文本字段使用返回自定义格式器对象的格式器工厂.
    这是最灵活的方法。当您要将一个以上的格式化程序与一个字段关联或添加一种新的格式化程序以用于多个字段时,此功能很有用。前一种用法的示例是一个字段,该字段以某种方式解释用户的键入,但以另一种方式显示值(当用户未键入时)。后一种用法的一个示例是具有自定义类值的多个字段,例如PhoneNumber。您可以设置字段以使用格式化程序工厂,该工厂返回电话 Numbers 的专用格式化程序。

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

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

单击启动按钮以使用Java™Web 开始(下载 JDK 7 或更高版本)运行 FormatterFactoryDemo。另外,要自己编译和运行示例,请查阅example index

FormatterFactoryDemo,金额字段被编辑

FormatterFactoryDemo,未安装自定义编辑器

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

private double rate = .075;  //7.5 %
...
amountField = new JFormattedTextField(
                    new DefaultFormatterFactory(
                        new NumberFormatter(amountDisplayFormat),
                        new NumberFormatter(amountDisplayFormat),
                        new NumberFormatter(amountEditFormat)));
...
NumberFormatter percentEditFormatter =
        new NumberFormatter(percentEditFormat) {
    public String valueToString(Object o)
          throws ParseException {
        Number number = (Number)o;
        if (number != null) {
            double d = number.doubleValue() * 100.0;
            number = new Double(d);
        }
        return super.valueToString(number);
    }
    public Object stringToValue(String s)
           throws ParseException {
        Number number = (Number)super.stringToValue(s);
        if (number != null) {
            double d = number.doubleValue() / 100.0;
            number = new Double(d);
        }
        return number;
    }
};
rateField = new JFormattedTextField(
                     new DefaultFormatterFactory(
                        new NumberFormatter(percentDisplayFormat),
                        new NumberFormatter(percentDisplayFormat),
                        percentEditFormatter));
...
amountDisplayFormat = NumberFormat.getCurrencyInstance();
amountDisplayFormat.setMinimumFractionDigits(0);
amountEditFormat = NumberFormat.getNumberInstance();

percentDisplayFormat = NumberFormat.getPercentInstance();
percentDisplayFormat.setMinimumFractionDigits(2);
percentEditFormat = NumberFormat.getNumberInstance();
percentEditFormat.setMinimumFractionDigits(2);

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

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

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

格式化的文本字段 API

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

与格式化文本字段相关的类

类或interfacePurpose
JFormattedTextFieldJTextField的子类,支持格式化任意值。
JFormattedTextField.AbstractFormatterJFormattedTextField的所有格式化程序的超类。格式化程序强制执行编辑策略和导航策略,处理字符串 到对象的转换,并根据需要操纵JFormattedTextField以强制执行所需的策略。
JFormattedTextField.AbstractFormatterFactory所有格式化程序工厂的超类。每个JFormattedTextField都使用格式化程序工厂来获取与文本字段的状态最对应的格式化程序。
DefaultFormatterFactory格式化程序工厂通常使用。根据诸如传入的参数和焦点状态之类的细节提供格式化程序。
DefaultFormatterJFormattedTextField.AbstractFormatter的子类,它使用toString方法格式化任意对象。
MaskFormatterDefaultFormatter的子类,使用指定的字符掩码设置格式并编辑字符串。 (例如,可以使用“ ###-####”指定七位数的电话 Numbers.)
InternationalFormatterDefaultFormatter的子类,它使用java.text.Format的实例来处理与String之间的转换。
NumberFormatterInternationalFormatter的子类通过使用NumberFormat的实例支持数字格式。
DateFormatterInternationalFormatter的子类通过使用DateFormat的实例支持日期格式。

JFormattedTextField Methods

方法或构造函数Purpose
JFormattedTextField()

JFormattedTextField(Object)
JFormattedTextField(Format)
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。

DefaultFormatter Options

MethodPurpose
void setCommitsOnValidEdit(boolean)

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

使用格式化文本字段的示例

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

ExampleWhere DescribedNotes
FormattedTextFieldDemoThis section使用四个格式化的文本字段。
SpinnerDemo如何使用微调器自定义两个微调器使用的格式化文本字段的外观。
ConverterUsing Models每个ConversionPanel都将一个带格式的文本字段与一个滑块配对。
TextInputDemoThis section显示如何一起使用文本字段,微调框和带格式的文本字段,并演示如何使用MaskFormatter。包括用于选择刚刚获得焦点的字段文本的代码。
FormatterFactoryDemoThis sectionFormattedTextFieldDemo 的一种变体,它使用格式化程序工厂为两个格式化的文本字段指定多个格式化程序。