3.5.2.1.47. 文本控件

TextField 是用于文本编辑的控件。它可以用于处理实体属性,也可用于输入/显示任何文本信息。

该组件对应的 XML 名称:textField

  • 从本地消息包中获取标题(caption)的文本控件示例:

    <textField id="nameField" caption="msg://name"/>

    下图展示了一个简单文本控件示例:

    gui textField data
  • Web Client 使用 Halo-based 主题时,在 XML 描述或者界面控制器中可以使用 stylename 属性给文本框组件设置预定义的样式 :

    <textField id="textField"
               stylename="borderless"/>

    如果使用编程的方式设置样式,可以选择一个前缀为 TEXTFIELD_HaloTheme class 常量。

    textField.setStyleName(HaloTheme.TEXTFIELD_INLINE_ICON);

    TextField 样式:

    • align-center - 使文本在文本框中居中显示。

    • align-right - 使文本在文本框中居右显示。

    • borderless - 移除文本框的边框和背景。

    • inline-icon - 使标题图标显示在文本框里面。

    文本框支持自动大小写转换。 caseConvertion 属性包含下列取值:

    • UPPER - 转换为大写,

    • LOWER - 转换为小写,

    • NONE - 不转换(默认值)。用这个选项来支持在输入法连续输入(比如,在输入中文、日文、韩文的时候)

  • 要创建连接数据的文本框,使用数据容器property 属性。

    <data>
        <instance id="customerDc" class="com.company.sales.entity.Customer" view="_local">
            <loader/>
        </instance>
    </data>
    <layout>
        <textField dataContainer="customerDc" property="name" caption="msg://name"/>
    </layout>

    如上所示,界面描述中为实体 Customer 定义了数据容器 customerDc ,并且 Customer 实体有一个 name 属性。文本控件通过 dataContainer 属性连接到数据容器;property 属性设置为要显示在控件中的实体属性的名称。

  • 如果文本控件没有连接到任何实体属性 (即,未设置数据容器和属性名称),可以使用 datatype 属性设置数据类型,数据类型用来格式化控件值。datatype 属性值可以是应用程序元数据中注册的任何数据类型 – 见 数据类型接口。通常,TextField 使用下面的数据类型:

    • decimal

    • double

    • int

    • long

    如果该字段有 datatype 属性,并且用户输入了一个错误的值,则会显示默认的转换错误消息。

    下面是一个数据类型是 Integer 的文本控件示例。

    <textField id="integerField" datatype="int" caption="msg://integerFieldName"/>

    如果用户输入的字符不能解析为整数,当该控件失去焦点时,应用程序将显示错误消息。

    gui datatype default message

    默认的消息是在主语言包中定义的,有这样的模板:databinding.conversion.error.<type>,比如:

    databinding.conversion.error.int = Must be Integer
  • 可以在界面 XML 描述中声明式的定义自己的类型转换错误消息,使用 conversionErrorMessage 属性:

    <textField conversionErrorMessage="This field can work only with Integers" datatype="int"/>

    或者在界面控制器中通过便层的方式创建:

    textField.setConversionErrorMessage("This field can work only with Integers");
  • 可以为文本控件分配一个验证器 - 实现了 Field.Validator 接口的类。在 datatype 对输入的字符格式进行验证后,验证器进行进一步的验证。例如,要创建一个正整数输入控件,需要创建一个验证器类:

    public class PositiveIntegerValidator implements Field.Validator {
        @Override
        public void validate(Object value) throws ValidationException {
            Integer i = (Integer) value;
            if (i <= 0)
                throw new ValidationException("Value must be positive");
        }
    }

    同时设置它为数据类型是 int 的文本控件的验证器:

    <textField id="integerField" datatype="int">
        <validator class="com.sample.sales.gui.PositiveIntegerValidator"/>
    </textField>

    与数据类型的输入时检查不同,验证不是在控件失去焦点时执行,而是在调用控件的 validate() 方法之后执行。这意味着控件(和连接的实体属性)可能暂时包含不满足验证条件的值(上例中的非正数)。这应该不是问题,因为要验证的控件通常用在编辑界面中,它会在提交之前自动调用所有控件的验证。如果该控件不在编辑界面中,则应在控制器中显式调用该控件的 validate() 方法。

  • TextField 支持其实现的 TextInputField 接口中定义的 TextChangeListener。为了不阻塞用户输入,文本变化事件的处理是异步进行的。

    textField.addTextChangeListener(event -> {
        int length = event.getText().length();
        textFieldLabel.setValue(length + " of " + textField.getMaxLength());
    });
    textField.setTextChangeEventMode(TextInputField.TextChangeEventMode.LAZY);
    gui textfield 2
  • The TextChangeEventMode 定义文本的变化被发送到服务器并触发服务端事件的方式。有 3 种预定义的事件模式:

    • LAZY (默认) - 文件输入暂停时触发事件。暂停时间可以通过 setInputEventTimeout() 修改。即使用户在输入文本时没有发生暂停,也会在可能发生的 ValueChangeEvent 之前强制触发文本更改事件。

    • TIMEOUT - 超时后触发事件。如果在超时周期内进行了多次更改,则将周期内自最后一次更改后发生的更改发送到服务端。可以使用 setInputEventTimeout() 设置超时时长。

      如果在超时期限之前发生 ValueChangeEvent,则在它之前触发 TextChangeEvent,条件是文本内容自上一个 TextChangeEvent 以来已经发生改变。

    • EAGER - 对于文本内容的每次更改,都会立即触发 TextChangeEvent 事件,通常是由按键触发。请求是独立且一个接一个地顺序处理。文本变化事件以异步方式与服务器交互,因此可以在处理事件请求的同时继续输入。

    • BLUR - 文本控件失去焦点时,发送事件。

  • EnterPressListener 允许定义一个在 Enter 键按下时被执行的操作

    textField.addEnterPressListener(enterPressEvent ->
            notifications.create()
                    .withCaption("Enter pressed")
                    .show());
  • ValueChangeListener 当用户完成文本输入时,即在按下 Enter 键或组件失去焦点时,将触发 ValueChangeListenerValueChangeEvent 类型的事件对象被传递给监听器,它有以下方法:

    • getPrevValue() 返回组件之前的值。

    • getValue() 返回组件的当前值。

      textField.addValueChangeListener(stringValueChangeEvent ->
              notifications.create()
                      .withCaption("Before: " + stringValueChangeEvent.getPrevValue() +
                              ". After: " + stringValueChangeEvent.getValue())
                      .show());

      可以使用 isUserOriginated() 方法跟踪 ValueChangeEvent 的来源。

  • 如果文本控件连接到实体属性(通过 dataContainerproperty),并且实体属性具有定义在 @Column JPA 注解中的 length 参数,那么 TextField 将相应地限制输入文本的最大长度。

    如果文本控件未链接到属性,或者属性未定义 length 值,或者需要覆盖此值,则可以使用 maxLength 属性限制输入文本的最大长度。值 "-1" 表示没有限制。 例如:

    <textField id="shortTextField" maxLength="10"/>
  • 默认情况下,文本控件截去字符串的前后空格。即,如果用户输入 " aaa bbb ",则 getValue() 方法返回并保存到连接实体属性的控件值将为 "aaa bbb"。可以通过将 trim 属性设置为 false 来禁用空格去除。

    应该注意的是,去除空格仅在用户输入新值时起作用。如果连接属性的值中已包含空格,则将显示空格,直到用户编辑该值。

  • 文本控件始终返回 null 而不是输入的空字符串。因此,启用 trim 属性后,任何只包含空格的字符串都将转换为 null

  • setCursorPosition() 方法可使控件获得焦点并将光标位置设置为指定索引,索引基于 0。