首页 Qt 学习之路 2 Qt 学习之路 2(82):输入元素

Qt 学习之路 2(82):输入元素

15 2.6K

前面的章节中,我们看到了作为输入元素的MouseArea,用于接收鼠标的输入。下面,我们再来介绍关于键盘输入的两个元素:TextInputTextEdit

TextInput是单行的文本输入框,支持验证器、输入掩码和显示模式等。

import QtQuick 2.0

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"
    }
}
QML TextInput

注意,我们这里放置了两个TextInput,用户可以通过点击输入框改变焦点。如果我们想支持键盘导航,可以添加KeyNavigation附加属性。

import QtQuick 2.0

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是一个附加属性。当用户点击了指定的按键时,属性指定的组件就会获得焦点。附加属性类似于普通属性,但是又有所区别。普通的属性隶属于这个类型;附加属性一般用于修饰或补充目标类型。比如这里的KeyNavigation.tab并不是TextInput的普通属性,仅仅是用来说明TextInput的一种特征。附加属性的一般语法是类型.属性名,以此为例,类型就是KeyNavigation,属性名就是tab

QLineEdit不同,QML 的文本出入组件只有一个闪动的光标和用户输入的文本,没有边框等可视元素。因此,为了能够让用户意识到这是一个可输入元素,通常需要一些可视化修饰,比如绘制一个矩形框。当我们这么做的时候,创建一个完整的组件可能是更好的选择,只是要记得导出所需要的属性,以便外部使用。按照这种思路,我们创建一个组件:

// LineEdit.qml

import QtQuick 2.0

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
    }
}

为了让外界可以直接设置TextInputtext属性,我们给这个属性声明了一个别名。同时,为了让外界可以访问到内部的textInput,我们将这个子组件也暴露出来。不过,从封装的角度而言,将实现细节暴露出去并不是一个好的设计,这要看暴露出来这个子组件的影响究竟有多大。然而这些都是关于设计的问题,需要具体问题具体分析,这里不再赘述。

下面我们可以将前面的例子修改成我们新创建的LineEdit组件:

import QtQuick 2.0

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

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

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

只要将 LineEdit.qml 与 main.qml 放在同一目录下,我们就不需要额外的操作,即可在 main.qml 中直接使用LineEdit。运行结果如下:

自定义 LineEdit

现在再来试试键盘导航。这次无论怎么按键盘,焦点始终不会到input2。虽然我们在组件中添加了focus: true,可是不起作用。原因是,焦点被inputText的父组件Rectangle获得,然而,Rectangle不会将焦点转发给inputText。为了解决这一问题,QML提供了另外一个组件FocusScope

FocusScope接收到焦点时,会将焦点转发给最后一个设置了focus:true的子对象。所以,我们可以使用FocusScope重写LineEdit组件:

// LineEdit.qml

import QtQuick 2.0

FocusScope {
    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一样正常使用了。

TextEditTextInput非常类似,唯一区别是TextEdit是多行的文本编辑组件。与TextInput类似,TextEdit也没有一个可视化的显示,所以我们也需要自己绘制其显示区域。这些内容与前面代码几乎一样,这里不再赘述。

附加属性Keys类似于键盘事件,允许我们相应特定的按键按下事件。例如,我们可以利用方向键控制举行的位置,如下代码所示:

import QtQuick 2.0

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: {
        switch(event.key) {
            case Qt.Key_Plus:
                square.scale += 0.2
                break;
            case Qt.Key_Minus:
                square.scale -= 0.2
                break;
        }
    }
}

15 评论

wuqi 2014年3月22日 - 09:21

想问下博主,最近需要做一个sidebar,象vs2010的侧边栏那种,可以自动收起,focus的时候滑动出来,qt能用什么做?

回复
豆子 2014年3月24日 - 13:50

Qt 没有这种组件,可以试试自定义 QDockWidget。

回复
wuqi 2014年3月24日 - 14:00

嗯,这两天查了一下,试试用animation 做个效果看看行不,或者试试tab,看wps上面那撮ribbon有些类似。谢谢。

回复
fire 2014年3月25日 - 18:00

请教博主一个问题,最近需要实现在给定的矩形框内显示几行文本(英文单词)信息,不使用控件的情况下怎样实现文本的自动换行?

回复
豆子 2014年3月26日 - 13:20

不使用控件那么你就是在 paintEvent 函数里面自己绘制的文本?这样的话就需要自己计算文本宽度,然后手动换行。

回复
fire 2014年3月26日 - 16:03

谢谢解答!
是自己绘制的,现在麻烦的就是使用的非等宽字体,文本宽度没有好的计算方法

回复
豆子 2014年3月27日 - 09:01

QFontMetrics 类可以计算一个字符串在给定字体时的宽度和高度。你可以利用这个类计算换行所需要的数据。具体方法可以看看文档。

回复
fire 2014年3月27日 - 10:17

太好了,用这个类配合wordwrap函数很容易就定位到合适的换行位置了,非常感谢!

xiaohui 2014年4月24日 - 23:48

豆子,有看到你在 UPYUN 上提交的用Qt实现的 SDK 和 客户端哦~投你一票!

回复
豆子 2014年4月25日 - 09:14

多谢支持 ;-P

回复
似水流年 2014年5月6日 - 14:17

豆子兄,qt5版本的qml程序发布后拷贝的别的机子上显示为一片空白,在本机却能正常显示,能帮忙指点一下是哪方面出了问题了么?谢谢了。

回复
ma qd 2015年8月10日 - 10:34

极大可能是 pro.user 的原因。

回复
Jewelxiao 2016年7月6日 - 19:42

老师您好!我跑了你的demo编译LineEdit出错了。查了下FocusScope里面好像没有color和border元素的。这样子的话要怎么把输入框设为可视的呢?

回复
青山 2016年7月19日 - 14:21

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

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

//增加一个rectangle用作背景色和边框
Rectangle {
anchors.fill:parent
color:"lightsteelblue"
border.color: "gray"
}

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

}

回复
Jewelxiao 2016年7月19日 - 22:29

明白啦 谢谢你了

回复

回复 wuqi 取消回复

关于我

devbean

devbean

豆子,生于山东,定居南京。毕业于山东大学软件工程专业。软件工程师,主要关注于 Qt、Angular 等界面技术。

主题 Salodad 由 PenciDesign 提供 | 静态文件存储由又拍云存储提供 | 苏ICP备13027999号-2