Qt学习入门

Qt的整体框架

Qt作为一个GUI的解决方案,其被设计为基于面向对象,跨平台,并直接与底层接口的framework,下图为主要的层次结构:

基于QT的系统架构 qt底层架构_QML


下边将从对象模型,事件机制,通信机制,定时器,Frame,模板,线程以及Qstring这几个方面来作为切入点,尝试去架构描述这个庞大的体系。

1. 对象模型

C++标准中虽然有很多的对实时的对象模型的支持,但其静态的特性,导致其仍然缺乏灵活性,Qt提供了自己的对象模型。

主要包括对象树,对象属性,以及元对象系统等

(1)对象树(Object tree)

由于GUI的设计层次结构比较强,并需要兼顾效率,Qt设计了对象树,并支持了动态类类型转换,其中父对象与子对象相互指向,整体的结构关系相当于一个森林, 父对象与子对象为一对多的关系,并有多个平行的父对象。其中有两点需要注意,首先当父对象析构的时候将析构所有的子对象,如果子对象在栈中或者为全局变量,有可能导致重复析构,程序崩溃(* C++标准中,局部变量析构的顺序是构造过程的逆向 );其次如果事件在发送中将QObject(* QObject作为其最终的基类,源自官方Qt文档中~QObject() )析构,也可能导致多线程调用过程中的崩溃。

(2) 对象属性(Object properties)

对象属性是基于元对象系统( Meta-Class system ,信号槽机制 signals and slots 也基于该模块, 在后边的章节将会具体谈),Qt中的Q_PROPORTY(…)宏标记了相关属性信息,将其注册到QMetaObject中,QMetaObject记录了所有注册过的属性信息,允许程序在编译时不知情的一些信息,在实时运行阶段能够动态添加进来。

相当于一个盒子,假设我是盒子的设计者,我并不知道将来盒子里要放什么东西,设计的要求是,我可以放新的东西进来也可以添加已有的东西,也可以将盒子更改我自定义的样式。
(3) 元对象系统(meta-class system)

元对象系统负责信号槽机制,实时类型判断,以及对象属性。这个系统依赖于MOC( meta object complier ),MOC“阅读”代码,将所有标记信息读入,整理,来满足上面所述3个方面的应用。

在QObject所属子类中,所有拥有QMetaObject的类都支持反射模式(并不被C++标准支持),但Qt通过MOC间接支持了该设计模式,QMetaObject提供了类的属性以及方法描述信息,下图给出了一个例子

基于QT的系统架构 qt底层架构_基于QT的系统架构_02

Qt学习可以基本分为 基础开发,熟悉内核及原理,优化框架三部分。

基于QT的系统架构 qt底层架构_数据_03

在Qt Creator中查看All Modules,会发现有5个模块组成。

Qt Essentials(基本模块)
Qt Add-Ons(扩展模块)
Value-Add Modules(增值模块)
Technology Preview Modules(技术预览模块)
Qt Tools (Qt工具)

其中基本模块包括:

  • Qt Core: Core non-graphical classes used by other modules,提供了元对象系统、对象树、信号槽、线程、输入输出、资源系统、容器、动画框架、JSON支持、状态机框架、插件系统、事件系统等等所有基础功能。
  • QtGUI:图形用户界面
  • Qt Multimedia
  • Qt Multimedia Widgets
  • Qt Network
  • Qt QML: QML和javascript解析引擎
  • Qt Quick: 基于上述语言的现代化界面和功能开发框架
  • Qt Quick Controls
  • Qt Quick Dialogs
  • Qt Quick Layouts
  • Qt SQL
  • Qt Test: 测试模块
  • Qt Widgets: 基于widget的GUI开发控件

基本模块框架图

基于QT的系统架构 qt底层架构_Qt_04


对于整个框架,大家可以理解为下层模块为上层模块提供支持,或者说上层模块包含下层模块的功能。举个例子,例如 QtWebKit 模块,它既有图形界面部件也支持网络功能,还支持多媒体应用。 其中QtTest和QtSql是相互独立的模块。

因此最初的学习可以暂时只学习QtCore, QtGui部分的内容,然后可以尝试扩展到QtTest部分,其他的部分可以后续再进一步学习

图像界面库框架

基于QT的系统架构 qt底层架构_Qt_05

这个图里面包含Qt GUI以及Qt Widget的部分组成,其中蓝色块表示包含在GUI模块中的,可以参考一下上图中的Qt
GUI模块的功能描述,并不包含所有的显示部分,想要仔细了解可以查阅帮助文档。
从这里也可以更加直观的看到两个不同的UI体系是怎么架构起来的。它们被分为了两类,一类以 OpenGL 为核心,它是现在最新的QtQuick2 和 QtWebkit 的基础;一类是以辅助访问和输入方式为基础的一般图形显示类,它们是经典 QWidget 部件类和QtQuick1 的基础。

QtQML和QtQuick框架

Qt 5 中将QtQuick 分为了两大部分: QtQml:提供了一个 QML 语言框架,定义并实现了语言引擎基础,还提供了便于开发者使用的
API,实现使用自定义类型来扩展 QML 语言以及将 JavaScript 和 C++ 集成到 QML 代码中。
QtQuick:是一个用于编写 QML 程序的标准库,它提供了使用 QML 创建用户界面程序时需要的所有基本类型。

基于QT的系统架构 qt底层架构_QML_06

可以看到 QtQml 和 QtQuick 是独立的两部分:

QtQml 以 QtCore 为基础,拥有 QtNetwork 的相关功能,然后搭建在了 V8 和 V4 两个 JavaScript
引擎上。

QtQuick 以 QPA 为基础,而后经过了 QtGui、OpenGL 和 Scene graph 三层封装,这里可以看到,新的
QtQuick 是建立在 OpenGL 之上的,并且使用了新的 Scene graph 进行图形渲染。很明显,QtQuick
就是用于图形显示的。

通过对比Quick1(QT5之前)和Quick2(QT5)可以了解到Quick2的功能更加强大了,有很多立体图(3D)效果都是在QT5的基础上实现的。

(A goal is not always meant to be reached, it often serves simply as something to aim at. —— Bruce Lee)

Qt 模型/视图框架

模型视图框架其主要目的就是将数据和界面分开,即MVC(Model View Controller)。
在传统的Widgets应用程序中,Qt并没有将数据和窗口分开,显然这样的工作就留给了用户。而Qt的MVC框架则是将界面与数据进行了隔离,VIEW(视图)负责展示数据,MODEL(模型)负责管理数据,DELEGATE(委托)负责VIEW和MODEL的交互。

MVC的使用,使我们只需要关注更新model的部分,而不需要关心view该如何变化,因为当model改变了,所有关联它的view都会得到相应的更新,最令人兴奋的是你只需要维护一个model.

Qt引入了模型/视图结构用于完成数据与界面的分离,即InterView框架,但不同的是Qt的InterView框架中把视图和控制部件结合在一起,使得框架更加简洁。
为了灵活地处理用户输入,InterView框架引入了代理(Delegate)。
通过使用代理,能够自定义数据条目(item)的显示和编辑方式。

Qt的模型/视图结构分为了三种部分:
模型(Model)、
视图(View)、
代理(Delegate);

其中,模型与数据通信,并为了其它部件提供接口; 而视图从模型中获得用来引用数据条目的模型索引(Model Index);
在视图中,代理负责绘制数据条目,当编辑条目时,代理和模型直接进行通信。 模型/视图/代理之间通过信号和槽进行通信。

它们之间的关系如下:

数据发生改变时,模型发出信号通知视图。

用户对界面进行操作,视图发生信号。

代理发出信号告知模型和视图编辑器目前的状态。

基于QT的系统架构 qt底层架构_Qt_07


基本概念

1、模型(Model)

InterView框架中的所有模型都基于抽象基类QAbstractItemModel类,

此类由QProxyModel、QAbstractListModel、QAbstractTableModel、QAbstractProxyModel、QDirModel、QFileSystemModel、QHelpContentModel 和 QStandardItemModel类继承。

2、视图(View)
InterView框架中的所有视图都基于抽象基类QAbstractItemView类,

此类由QColumnView、QHeaderView、QListView、QTableView和QTreeView类继承。

3、代理(Delegate)
InterView框架中的所有代理都基于抽象基类QAbstractItemDelegate类,
此类由QItemDelegate 和 QStyledItemDelegate类继承。


Qt model/view framework对MVC的实现完全是基于C++的虚基类和虚函数特性。MVC各部分之间的联通除了应用signal/slot之外,就全是虚函数了。Tx们如果有兴趣的话,可以看看model/view framework源代码中那些QAbstract开头的类,它们定义了统一的接口虚函数后,派生类只需要重新实现这些函数即可。

QTestLib单元测试框架

Qt插件框架

基于插件的设计好处很多,把扩展功能从框架中剥离出来,降低了框架的复杂度,让框架更容易实现.扩展功能与框架以一种很松的方式耦合,两者在保持接口不变的情况下,可以独立变化和发布,将软件的复杂度限制在了单个的插件之中,比较适用与需求不定或是业务容易发生变化的软件设计.

插件系统的构成,插件系统主要可分为三部分:

主系统 通过插件管理器加载插件,并创建插件对象。一旦插件对象被创建,主系统就会获得相应的指针/引用,它可以像任何其他对象一样使用。

插件管理器
用于管理插件的生命周期,并将其暴露给主系统。它负责查找并加载插件,初始化它们,并且能够进行卸载。它还应该让主系统迭代加载的插件或注册的插件对象。

插件 插件本身应符合插件管理器协议,并提供符合主系统期望的对象。

实际上,很少能看到这样一个相对独立的分离,插件管理器通常与主系统紧密耦合,因为插件管理器需要最终提供(定制)某些类型的插件对象的实例。

程序流,框架的基本程序流,如下所示:

基于QT的系统架构 qt底层架构_基于QT的系统架构_08