首页 Qt 学习之路 2 Qt 学习之路 2(83):Qt Quick Controls

Qt 学习之路 2(83):Qt Quick Controls

38 11

自 QML 第一次发布已经过去一年多的时间,但在企业应用领域,QML 一直没有能够占据一定地位。很大一部分原因是,QML 缺少一些在企业应用中亟需的组件,比如按钮、菜单等。虽然移动领域,这些组件已经变得可有可无,但在桌面系统中依然不可或缺。为了解决这一问题,Qt 5.1 发布了 Qt Quick 的一个全新模块:Qt Quick Controls。顾名思义,这个模块提供了大量类似 Qt Widgets 模块那样可重用的组件。本章我们将介绍 Qt Quick Controls,你会发现这个模块与 Qt 组件非常类似。

为了开发基于 Qt Quick Controls 的程序,我们需要创建一个 Qt Quick Application 类型的应用程序,选择组件集的时候注意选择 Qt Quick Controls 即可:

Qt Quick Controls Component Set

注意,Qt Creator 给出的是 Qt Quick Controls 1.0,而最新版本的 Qt 5.2 搭载的 Qt Quick Controls 是 1.1。1.1 比 1.0 新增加了一些组件,比如BusyIndicator等。所以,如果你发现某个组件找不到,记得更新下 Qt Quick Controls 的版本。

Qt Quick Controls 1.1 提供了多种组件:

应用程序窗口
用于描述应用程序的基本窗口属性的组件
ApplicationWindow对应QMainWindow,提供顶层应用程序窗口
MenuBar对应QMenuBar,提供窗口顶部横向的菜单栏
StatusBar对应QStatusBar,提供状态栏
ToolBar对应QToolBar,提供工具栏,可以添加ToolButton和其它组件
Action对应QAction,提供能够绑定到导航和视图的抽象的用户界面动作
导航和视图
方便用户在一个布局中管理和显示其它组件
ScrollView对应QScrollView,提供滚动视图
SplitView对应QSplitter,提供可拖动的分割视图布局
StackView对应QStackedWidget,提供基于栈的层叠布局
TabView对应QTabWidget,提供带有标签的基于栈的层叠布局
TableView对应QTableWidget,提供带有滚动条、样式和表头的表格
控件
控件用于表现或接受用户输入
BusyIndicator提供忙等示意组件
Button对应QPushButton,提供按钮组件
CheckBox对应QCheckBox,提供复选框
ComboBox对应QComboBox,提供下拉框
GroupBox对应QGroupBox,提供带有标题、边框的容器
Label对应QLabel,提供标签组件
ProgressBar对应QProgressBar,提供进度条组件
RadioButton对应QRadioButton,提供单选按钮
Slider对应QSlider,提供滑动组件
SpinBox对应QSpinBox,提供微调组件
Switch提供类似单选按钮的开关组件
TextArea对应QTextEdit,提供能够显示多行文本的富文本编辑框
TextField对应QTextLine,提供显示单行文本的纯文本编辑框
ToolButton对应QToolButton,提供在工具栏上显示的工具按钮
ExclusiveGroup提供互斥
菜单
用于构建菜单的组件
Menu对应QMenu,提供菜单、子菜单、弹出菜单等
MenuSeparator提供菜单分隔符
MenuItem提供添加到菜单栏或菜单的菜单项
StatusBar对应QStatusBar,提供状态栏
ToolBar对应QToolBar,提供工具栏,可以添加ToolButton和其它组件

我们尝试实现一个编辑器。这是一个简单的文本编辑器,具有新建、剪切、复制和粘贴等操作。程序运行出来效果如下:

Simple Editor

整个程序都是在 IDE 帮我们生成的 main.qml 中实现的。首先我们需要添加import语句:

import QtQuick 2.1
import QtQuick.Controls 1.1

注意我们修改了 IDE 生成的默认语句。整个 QML 文档的根元素是ApplicationWindow

ApplicationWindow {
    title: qsTr("Simple Editor")
    width: 640
    height: 480
    ...
}

ApplicationWindow是应用程序的主窗口,类似QMainWindow,提供了很多预定义的功能,比如菜单、工具栏等。代码里面的qsTr()函数类似tr()函数,用于以后的国际化。所有面向用户的文本都应该使用这个函数。

下面向ApplicationWindow中添加控件:

menuBar: MenuBar {
    Menu {
        title: qsTr("&File")
        MenuItem { action: newAction }
        MenuItem { action: exitAction }
    }
    Menu {
        title: qsTr("&Edit")
        MenuItem { action: cutAction }
        MenuItem { action: copyAction }
        MenuItem { action: pasteAction }
        MenuSeparator {}
        MenuItem { action: selectAllAction }
    }
}

toolBar: ToolBar {
    Row {
        anchors.fill: parent
        ToolButton { action: newAction }
        ToolButton { action: cutAction }
        ToolButton { action: copyAction }
        ToolButton { action: pasteAction }
    }
}

TextArea {
    id: textArea
    anchors.fill: parent
}

首先看最后面的TextArea,这是整个窗口的主要控件,类似于setCentralWidget()函数调用。

menuBartoolBar两个属性都是ApplicationWindow提供的属性。

menuBarMenuBar类型的,所以我们创建一个新的MenuBar控件。MenuBar具有层次结构,这是通过Menu的嵌套实现的。每一个菜单项都是用MenuItem实现的;菜单项之间的分隔符则使用MenuSeparator控件。这点与 QtWidgets 有所不同。

toolBarItem类型的,不过通常都会使用ToolBar控件。ToolBar默认没有提供布局,因此我们必须给它设置一个布局。这里我们直接添加了一个Row,作为横向工具栏的布局。这个工具栏要横向充满父窗口,因此设置锚点为anchors.fill: parent。虽然我们设置的是充满整个父窗口,但是工具栏的行为是,如果其中只有一个子元素(比如这里的Row),那么工具栏的高度将被设置为这个子元素的implicitHeight属性。这对结合布局使用非常有用。事实上,这也是工具栏最常用的方法。工具栏中添加了四个按钮,都是ToolButton类型。

每一个MenuItemToolButton都添加了一个action属性。下面是这部分代码:

Action {
    id: exitAction
    text: qsTr("E&xit")
    onTriggered: Qt.quit()
}
Action {
    id: newAction
    text: qsTr("New")
    iconSource: "images/new.png"
    onTriggered: {
        textArea.text = "";
    }
}
Action {
    id: cutAction
    text: qsTr("Cut")
    iconSource: "images/cut.png"
    onTriggered: textArea.cut()
}
Action {
    id: copyAction
    text: qsTr("Copy")
    iconSource: "images/copy.png"
    onTriggered: textArea.copy()
}
Action {
    id: pasteAction
    text: qsTr("Paste")
    iconSource: "images/paste.png"
    onTriggered: textArea.paste()
}
Action {
    id: selectAllAction
    text: qsTr("Select All")
    onTriggered: textArea.selectAll()
}

Action类似QAction。这里我们还是使用qsTr()函数设置其显示的文本。

使用iconSource属性可以指定图标。注意这里的图标只能是位于文件系统中的,不能加载资源文件中的图标(当然,这并不是绝对的。如果我们将整个 QML 文档放在资源文件中,那么就可以直接加载资源文件中的图标。我们会在后面的章节详细介绍这种技术。)。当我们直接类似“images/new.png”这种路径时,注意 QML 是运行时解释的,因此这个路径是相对与 QML 文件的路径。所以这里的图标需要放在与 main.qml 文件同目录下的 images 目录中。

onTriggered属性是一种信号处理函数,后面可以添加 JavaScript 语句。如果是多条语句,可以使用大括号,例如newActiononTriggered。QML 组件可以发出信号。与 C++ 不同的是,QML 组件的信号并不需要特别的连接语句,而是使用"on信号名字"的形式。比如,Action有一个名为triggered的信号,则其信号处理函数即为onTriggered。事实上,这是最简单的一种信号槽的实现。不过,这种实现的困难在于,同一个信号只能有一个固定名字的信号处理函数。不过,我们也可以使用 connect 连接语句。后面的章节中将详细介绍这一点。

至此,我们的编辑器便实现了。由于全部使用了TextArea提供的功能,所以代码很简单。不过,复杂的程序都是这些简单的元素堆积而成,所以,我们现在只是简单介绍,具体的控件使用还要根据文档仔细研究。

附件:SimpleEditor.zip

38 评论

jerry 2014年5月9日 - 16:16

想請問自己建置的QtQuick跟Qt提供的Example code的差別
QtQuick2ApplicationViewer viewer;
跟QQuickView view; 的差別是?

回复
豆子 2014年5月9日 - 22:22

QtQuick2ApplicationViewer 是 IDE 帮助生成的一个类,封装了 QQuickWindow。在一定程度上,QtQuick2ApplicationViewer 可以认为是 QQuickWindow 的子类。QQuickView 是 QQuickWindow 的子类,增加了直接读取 QML 文件等功能。

回复
jerry 2014年5月11日 - 13:02

謝謝解釋!
因為初學,想藉由模仿example code來學習,但發現光main.cpp長相都不一樣,害我有點不知如何下手來模仿...

回复
Jakes 2014年5月9日 - 20:47

非常不错,先收藏了。 感觉访问的时候有点慢。豆子大大不是建在阿里云的嘛?怎么感觉访问不怎么理想呢?

回复
豆子 2014年5月9日 - 21:31

不是的,网站用的是国外的主机,没有在阿里云上面,因为考虑到这个主机还有近一年时间的续费,而且国内主机的话备案也要一段时间,所以还没有迁移。

回复
jsxyhyj 2014年5月10日 - 10:29

qt 5.2.1for x86里Controls 是 1.0的。请问怎么更新呢?

回复
豆子 2014年5月10日 - 13:53

Qt 5.2.1 带的就是 1.1 的,不需要更新。只需要将 IDE 生成的 import QtQuick.Controls 1.0 改成 1.1 就可以了。

回复
jsxyhyj 2014年5月10日 - 10:30

楼主的书什么时候出来啊?

回复
豆子 2014年5月10日 - 13:54

最新与出版社联系的结果是6月9日交稿,等结束排版到印刷出来的话大概要两三个月的时间吧

回复
youcantknow 2014年6月5日 - 05:04

非常感谢楼主,希望楼主的书有电子版,可以在kindle上看,快点出书吧,希望豆子的书里可以详细说说这个qml,因为我想用来开发企业级应用

回复
豆子 2014年6月5日 - 09:41

现阶段不建议使用 QML 开发企业级应用。因为组件缺失太多,很容易增加开发复杂度,进而拖慢进度。

回复
youcantknow 2014年6月6日 - 16:04

那豆子前辈觉得用什么写界面比较好呀, 用来开发erp的

豆子 2014年6月12日 - 09:50

看你的需求了,一般的 GUI 界面都是可以的吧。现在不是有 Java 的,要么你就用 Qt/C++ 也可以。像 ERP 这么复杂的界面,Qt Quick 肯定很复杂的

何伟 2014年5月10日 - 10:59

想问下楼主,我们公司准备开发一套客户端使用的是http协议,而且界面可能会要美化一下,请问一下这个是使用qt还是fc好点呢,快速。容易上手。开发周期短

回复
豆子 2014年5月10日 - 13:55

话说还不大了解你说的 fc 是什么东西?具体还是看你的需求,如果要求跨平台的话,Qt 还是比较适合的。

回复
何伟 2014年5月10日 - 16:17

呵呵,不好意思,少写了个M,是MFC,,

回复
何伟 2014年5月10日 - 16:17

跨平台倒 是不用。之前以为要跨 平台准备用QT。。但不跨平台我也感觉QT好像比mfc要好。。

回复
豆子 2014年5月12日 - 21:26

Qt 的设计要比 MFC 优秀,如果喜欢 Qt,使用 Qt 也是不错的。

回复
水煮肉片 2014年5月22日 - 18:12

QWidget的思路是用C++来实现高度抽象的绘图,所以使用了大量的设计模式,虽然达到了目的,但是造就了程序的复杂性。QWidget是越往底层走,越是发觉设计模式设计的精巧,但是要研究的代码和注释也越多越复杂,这真是上层开发人员所要的么?
QML和JavaScript其实提供了另一种思路,直接使用描述式的脚本,直接使用更加符合思维习惯的编程模型,代码即是注释。
从其他项目的发展来看,也有类似的趋势,Webkit是一个把设计模式和模板技术用得淋漓尽致的项目,现在谷歌却要在分裂出来 的Blink里面用JavaScript重写DOM等模块。

回复
mycodream 2014年6月8日 - 15:47

最近在学习QT,看到前辈很多好的文章,但是每次打开您的网站都很慢,所以想请问您的文章可以转载吗?谢谢。

回复
豆子 2014年6月12日 - 10:31

不知道现在的速度如何?我这里测试还是挺快的。文章可以转载的,感谢支持!

回复
林晨 2014年6月8日 - 17:34

弱弱的问一句,如果想做一个左边是菜单,右边是内容区的类爱奇艺播放器界面,该怎么写呢?

回复
豆子 2014年6月12日 - 10:32

这个要定制界面的,可以参考一下网上的有关 360 界面的实现

回复
Jim 2014年6月12日 - 11:32

最近才接触的Qt,差不多学了半个多月了,正愁找不到好的学习东西,一直在看一老外在youtube上的视频,内容有些陈旧了,没有新技术更新,而且无奈英语太烂,只能根据他写的代码了解个大概,有的时候,如果他不写代码的话,一直在那说,都不知道他说的是啥。。。只能是一边看,一边在网上找资料,有好几次都找到了前辈这里,真可以说是帮了我很大的忙,谢谢啦!如果有机会,我想以前辈的文章为材料,录制一套基础视频教程,这样的话以后想看视频学Qt的朋友终于也算是有中文教程了,每段视频都会介绍出处,不知道前辈是否同意

回复
豆子 2014年6月13日 - 08:54

如果有时间的话可以做个视频试试啦,不过还是贵在坚持 ;-P

回复
艾露恩·泠青 2014年6月13日 - 10:42

其中qml不能用于企业软件开发的原因说的不太准确,Qt5以前的quick1确实缺少组件、缺少桌面操作的部分支持。但Qt5开始的quick2已经获得了这方面的补充,特别是到现在的5.3版本。
目前的quick2已经足以开发企业软件,但是又一个问题:quick2采用了新的渲染方式,需要OpenGL的支持,而大多数企业办公电脑却不足以提供这方面的支持,这是致命的。
quick1要求低但适用性不好,quick2可以但要求高。结果quick目前只能更偏向于移动设备或者休闲类游戏的开发上,官方提供的示例或相关的博文都倾向于这点。

回复
豆子 2014年6月13日 - 14:29

个人感觉即便是 Qt 5.3,开发企业应用的组件还是太少。企业应用大量使用 tree、复杂的 table,这两个组件 Qt Quick Controls 要么根本没有提供,要么提供的功能太弱,定制起来非常复杂。如果要自己从头实现一个 tree,恐怕也不是那么容易的事情。Qt Quick 2 也可以使用 ANGLE 的方式,这就绕过了 OpenGL,只要系统不要太旧,一般没有问题的。我曾在六年前的机器上运行过 ANGLE 版本的 Qt Quick 2,是没有问题的。如果超过六年的确也不保证了

回复
welliam 2014年7月17日 - 14:00

那么是否可以将qml与c++方式一起使用来开发呢?复杂的控件用c++方式,然后将两者合起来?

回复
JHJH 2014年7月28日 - 17:47

当然可以啦!!可以互相调用的。

回复
welliam 2014年7月29日 - 14:42

比如我用qml写个button,c++写个widget,怎么把这个button放到widget上去?
如果可以的话那真的可以简化许多编码啊

豆子 2014年7月31日 - 14:21

可以的,你可以在文档中搜索 Integrating QML and C++ 查看相关内容。

JHJH 2014年7月28日 - 17:50

现在有哪台机器不支持OpenGL的?ANGLE 也可以的。

回复
welliam 2014年8月27日 - 14:26

看了几天,c++与qml的交互集成这个链接说的比较好。
http://developer.blackberry.com/native/documentation/cascades/dev/integrating_cpp_qml/

各种资料还是得去国外网站找啊,就是英文看的头疼

回复
jiangfengyi 2014年10月13日 - 09:41

楼主,如果你下一步能写一些Qt的应用例子,比如Qt动态绘制实时曲线图;局部放大缩小功能等等。我觉得对于Qt界朋友贡献将非常大,这个可以作为你Qt高级应用篇的文章。

回复
豆子 2014年10月13日 - 15:45

这个也会仔细考虑的,感谢关注

回复
枫亦 2014年10月16日 - 10:15

我最近研究了下qt源码,有一些心得:qt源码中的gui部分和widget是分开来了,实质上qt源码最核心的就是Qt Core和Qt GUI,一个主要负责事件,一个负责呈现。用户其实根据这两部分接口也可以实现自己的widget甚至自己的Graphics View Framework。qt中的widget和Graphics View Framework的渲染引擎都是 Qt GUI中QPainter-> QPaintEngine->QPaintDevice,事件也都是依赖Qt Core.其本质区别是对于Qt Core和Qt GUI的组织管理调用的区别。

回复
雨后星辰 2014年11月2日 - 20:32

我想用他实现一个qq聊天框那样的编辑框,虽然TextArea支持富文本编辑,但是不能动态显示gif图,请问这个有什么解决办法吗?

回复
豆子 2014年11月5日 - 11:38

可以考虑使用 QWebKit 直接写网页

回复

发表评论

关于我

devbean

devbean

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

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