# 输入元素

我们早已使用鼠标输入元素 MouseArea,接下来看看键盘输入。我们从文本编辑元素 TextInputTextEdit 元素开始。

# TextInput

TextInput 允许用户输入一行文本。该元素支持输入约束,如 validatorinputMaskechoMode

// textinput.qml

import QtQuick

Rectangle {
    width: 200
    height: 80
    color: "linen"

    TextInput {
        id: input1
        x: 8; y: 8
        width: 96; height: 20
        focus: true
        text: "Text Input 1"
    }

    TextInput {
        id: input2
        x: 8; y: 36
        width: 96; height: 20
        text: "Text Input 2"
    }
}

用户可点击 TextInput 内部获得焦点。要支持通过键盘切换焦点,可以使用附加属性 KeyNavigation

// textinput2.qml

import QtQuick

Rectangle {
    width: 200
    height: 80
    color: "linen"

    TextInput {
        id: input1
        x: 8; y: 8
        width: 96; height: 20
        focus: true
        text: "Text Input 1"
        KeyNavigation.tab: input2
    }

    TextInput {
        id: input2
        x: 8; y: 36
        width: 96; height: 20
        text: "Text Input 2"
        KeyNavigation.tab: input1
    }
}

附加属性 KeyNavigation 支持一些预设的导航键,按下导航键,可以在元素间切换焦点。

文本输入元素除了闪烁的光标和输入的文本外没有任何视觉展示。为了让用户能将元素识别为输入元素,需要一些视觉装饰,例如,简单的矩形。若将 TextInput 放入其它元素,需要确保导出了要使用的主要元素。

为了复用,我们将这段代码移入了自定义组件 TLineEditV1

// TLineEditV1.qml

import QtQuick

Rectangle {
    width: 96; height: input.height + 8
    color: "lightsteelblue"
    border.color: "gray"

    property alias text: input.text
    property alias input: input

    TextInput {
        id: input
        anchors.fill: parent
        anchors.margins: 4
        focus: true
    }
}

提示

若你想完全导出 TextInput,可以通过 property alias input: input 完成。第一个 input 是属性名称,第二个是元素名称。

随后我们用 TLineEditV1 组件重写了 KeyNavigation 实例。

Rectangle {
    ...
    TLineEditV1 {
        id: input1
        ...
    }
    TLineEditV1 {
        id: input2
        ...
    }
}

尝试按下 tab 键触发导航。你会发现焦点并未切换至 input2。只配置 focus: true 是不够的。问题是当焦点切给 input2 元素时,TlineEditV1 内的顶级元素(Rectangle)获得了焦点,并未将焦点转发给 TextInput。为了避免此问题,QML 提供了 FocusScope

# FocusScope

焦点作用域内最后一个 focus: true 的子元素会获得焦点。所以它将焦点转发给最后一个请求焦点的子元素。我们会用焦点作用域创建第二版的 TLineEdit 组件,名为 TLineEditV2。

// TLineEditV2.qml

import QtQuick

FocusScope {
    width: 96; height: input.height + 8
    Rectangle {
        anchors.fill: parent
        color: "lightsteelblue"
        border.color: "gray"

    }

    property alias text: input.text
    property alias input: input

    TextInput {
        id: input
        anchors.fill: parent
        anchors.margins: 4
        focus: true
    }
}

我们的实例现在长这样:

Rectangle {
    ...
    TLineEditV2 {
        id: input1
        ...
    }
    TLineEditV2 {
        id: input2
        ...
    }
}

现在按下 tab 键,能成功地在两个组件间正确切换,内部的子元素也能正确的获得焦点。

# TextEdit

TextEditTextInput 十分类似,支持多行文本。它没有文本约束属性,因为着依赖于查询文本内容尺寸(contentHeightcontentWidth)。我们也创建了名为 `TTextEdit 的自定义组件,为编辑区域提供了背景色,使用了焦点作用域获得更好的焦点转发机制。

// TTextEdit.qml

import QtQuick

FocusScope {
    width: 96; height: 96
    Rectangle {
        anchors.fill: parent
        color: "lightsteelblue"
        border.color: "gray"

    }

    property alias text: input.text
    property alias input: input

    TextEdit {
        id: input
        anchors.fill: parent
        anchors.margins: 4
        focus: true
    }
}

你可以像使用 TLineEdit 组件一样使用它

// textedit.qml

import QtQuick

Rectangle {
    width: 136
    height: 120
    color: "linen"

    TTextEdit {
        id: input
        x: 8; y: 8
        width: 120; height: 104
        focus: true
        text: "Text Edit"
    }
}

# Keys 元素

附加属性 Keys 允许在按下某个按键时执行代码。例如,为了移动,缩小或放大矩形,我们可以钩入上,下,左和右键,在按下这些键时变化元素,也可以钩入加和减键,在按下这些键时执行缩放元素操作。

// keys.qml

import QtQuick

DarkSquare {
    width: 400; height: 200

    GreenSquare {
        id: square
        x: 8; y: 8
    }
    focus: true
    Keys.onLeftPressed: square.x -= 8
    Keys.onRightPressed: square.x += 8
    Keys.onUpPressed: square.y -= 8
    Keys.onDownPressed: square.y += 8
    Keys.onPressed: function (event) {
        switch(event.key) {
            case Qt.Key_Plus:
                square.scale += 0.2
                break;
            case Qt.Key_Minus:
                square.scale -= 0.2
                break;
        }
    }
}