logo头像
Snippet 博客主题

Qt5.9读书笔记

目前正在做一个基于Qt的桌面建模软件,我主要负责做偏服务端插件,很少做界面开发,所以一直没仔细了解过Qt。近段稍微有点空闲,系统学习了下Qt相关教程,过程还算轻松,因为它整体设计架构和开发流程很像我以前搞游戏开发用的cocos。下面是我学习笔记,记录下来加深印象。

一、认识Qt

1.1 简介

Qt是一套C++编写的应用程序开发类库,跨平台。

1.2 Qt的获取与安装

1.2.1 Qt的许可类型

分为商业许可和开源许可,商业许可要支付费用,允许开发者不公开项目的源代码,而且某些模块只有商业许可的版本里才有。而使用开源许可版本发布产品则要求公开源码。

1.2.2 Qt的版本

如果不是为了维护旧版本项目,原则上一定要选用最新版本的Qt进行程序开发。新版本具有更强的性能,更好的稳定性,更多的新特性。

1.2.3 Qt的下载与安装

从Qt官网可以下载最新版本的Qt软件。根据开发项目的不同,Qt分为桌面和移动设备应用开发嵌入式设备开发两大类不同安装包。前者有开源许可协议,可以免费下载和使用,而后者只可下载30天试用版本。

安装教程

1.3 Qt Creator初步使用

这节没什么好说的,就一个Qt的IDE,主要集成了示例教程、编码、编译、调试,UI设计。安装好后自己看看就是。

1.4 编写一个Hello World程序

  1. 文件->创建项目

  • Qt Widgets Application 支持桌面平台的有图形用户界面,界面设计采用C++语言开发。
  • Qt Console Application 控制台应用程序,无GUI界面,一般用于学习C/C++语言。
  • Qt Quick Application Qt支持的一套GUI开发架构,界面设计采用QML语言,程序架构采用C++语言。可以类比cocos + lua关系。
  1. Edit 项目的文件组成

  • .pro是项目管理文件,包括一些对项目的设置项。
  • Headers分组,是项目所有的头文件。
  • Sources分组,是项目所有源文件。
  • Forms分组,是项目所有ui文件。
  1. Projects 编译器设置

Build & Run列表下列出所有安装的编译器,点击即可选择,每个编译器有Build和Run两个分页可设置。

其中Shadow build勾选的话,表示在编译后会在项目同级目录生成一个对应编译器环境的独立目录。这种方式一般用于使用不同编译器创建不同版本的可执行文件。

左下角这排图标分别是选择debug/release、运行、调试运行、编译。和vs编译流程类似。

1.5 在Visual Studio里使用Qt

如果你不喜欢用Qt Creator,习惯了Visual Studio编写C++程序,Qt提供了Visual Studio for Qt插件。


二、GUI应用程序设计基础

2.1 项目文件组成

项目包含以下一些文件:

  • 项目组织文件xx.pro,存储项目设置的文件。
  • 主程序入口文件main.cpp
  • 自定义设计的窗体类头文件(.h)和对应的源文件(.cpp)。
  • 窗体类对应的ui文件,使用xml描述,是通过UI设计器可视化设计生成的。
  • ui_xx.h文件,是在对xx.ui文件编译后自动生成的一个文件。里边定义了ui窗体相关属性设置信息。

2.2 可视化UI设计(布局/信号、槽)

  1. 熟练使用布局(窗口大小改变时里面控件相对位置自动适配)

  2. 信号与槽

    一、全代码信号/槽(纯手写代码形式)

    1
    2
    3
    4
    5
    6
    7
    8
    // sender 信号发射对象
    // SIGNAL/SLOT QT的函数宏,指明信号/槽,并将它们的参数转换为相应的字符串
    // signal()/slot() 信号/槽,都是函数,就是发射信号对应槽函数处理
    // type: 表示信号与槽之间的关联方式,缺省值为Qt::AutoConnection,自动确定关联方式。一般缺省最后一个参数,用默认值就行了。
    QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(slot()), Qt::ConnectionType type = Qt::AutoConnection);

    // 手动信号发射
    emit xxx_signal(param);

    关于信号与槽的使用,有一些规则需要注意:
    (1)一个信号可以连接多个槽。

    (2)多个信号也可以连接一个槽。

    (3)一个信号可以连接另一个信号。这样一个信号发射时,另一个信号也会发送。

    (4)严格情况下,信号与槽函数的参数和类型要一致,至少信号的参数不能少于槽的参数。如果不匹配,会出现编译错误或运行错误。

    (5)在使用信号与槽的类中,必须加入宏Q_OBJECT

    (6)当一个信号发射时,它关联的槽函数通常会立即执行,就像调用一个函数一样。只有当槽函数执行完毕后,才会执行发射信号后面的代码。即信号发射与响应是同步的。

    二、信号是对象系统的,槽要自定义。可以通过UI设计器,选择对象控件右键,Go to slot...,选择信号,然后后自动生成对应的槽函数。这种信号/槽的绑定是通过connectSlotsByName这个接口connect的。(半写代码形式)

    三、信号和槽都是对象系统自带的,可以全通过UI设计器完成。有两种形式:(完全不写代码形式)

    a. 工具栏进入编辑信号/槽模式,点击组件对象移动到空白地方再松开,会弹出信号与槽设置界面进行设置。

    b. 直接在UI编辑区下方进行添加也是一样的。

2.3 代码化UI设计

创建类向导时,不勾选Generate form,即不会生成xx.ui文件,界面全部手写代码完成。这玩法就和cocos完全一样的,没什么说的。

2.4 混合方式UI设计

2.4.1 添加资源文件

资源文件可以打包资源,编译后资源会打包进应用程序里,可脱离原始资源使用。

2.4.2 设计Action

用于菜单和工具栏设计,添加的Action可以像左侧控件一样拖到菜单栏和工具栏里。这个控件的主要信号是trigger()/trigger(bool),处理Action控件点击响应我们就只要关联这个信号的槽函数就行了。和普通控件信号/槽一样,没什么区别。只是它用于菜单和工具栏,发出的是trigger信号。

2.4.3 为应用程序设置图标

  1. 将一个图标文件,必须是.ico格式,复制到项目源程序目录下。
  2. 在项目配置文件里用RC_ICONS设置图标文件名,添加: RC_ICONS = AppIcon.ico

2.5 Qt Creator使用技巧

没啥记录的,就是这个工具的快捷键介绍和帮助文档怎么查看。实际项目开发,很少用它,一般还是习惯用vs写代码。倒是帮助文档查API什么的可以多看看。

三、Qt类库概叙

3.1 Qt核心特点

Qt是一个用标准C++编写的跨平台开发类库,它对标准C++进行了扩展,引入了元对象系统、信号与槽、属性等特性。

MOC是Qt的元对象编译器,是一个预处理器,在源程序被编译前先将这些Qt特性的程序转换为标准C++兼容的形式,然后再由标准C++编译器进行编译。这就是为什么在使用信号与槽机制类里,必须添加一个Q_OBJECT宏的原因,只有添加了这个宏,moc才能对类里的信号与槽的代码进行预处理。

Qt Core模块是Qt类库的核心,所有其它模块都依赖它。Qt为C++语言增加的特性都是在Qt Core模块里实现的。

3.1.1 元对象系统

元对象系统由下面三个基础组成:

  1. QObject类是所有使用元对象系统的类的基类。
  2. 在一个类的private部分声明Q_OBJECT宏,使得类可以使用元对象的特性,如动态属性、信号与槽。
  3. MOC为每个QObject的子类提供必要的代码来实现元对象系统的特性。

具体有哪些使用看帮助文档里:QObject类提供的接口就知道了。

3.1.2 属性系统

Qt的属性系统类似cocoscreator的属性,它与普通成员变量区别是,可以绑定信号,当值发生变化可以发送信号,还可以在Qt Designer属性编译器可见,可直接修改组件的属性。还支持Qt元对象特性,可获取属性元对象信息等。

  1. 创建属性:

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class QPerson : public QObject
{
Q_OBJECT
Q_CLASSINFO("author", "yan") // 定义QPerson这个类的附加信息(名称, 值)
Q_CLASSINFO("company", "NJUST")
Q_CLASSINFO("version", "1.0.0")
Q_PROPERTY(int age READ age WRITE setAge NOTIFY ageChanged) // 定义QPerson这个类的属性
Q_PROPERTY(QString name MEMBER m_name)
Q_PROPERTY(int score MEMBER m_score)
private:
int m_age = 10;
QString m_name;
int m_score = 79;
public:
explicit QPerson(QObject *parent = nullptr);
int age();
void setAge(int value);
void incAge();
signals:
agechanged(int value);
  1. 使用:

    1
    2
    3
    4
    5
    6
    7
    8
    // 创建好属性后,可以通过setProperty和property设置和获取属性
    QPerson *person = new QPerson;
    person->setProperty("age", 18);
    int age = person->property("age");

    // 获取类的附件信息
    const QMetaObject *metaObject = QPerson::staticMetaObject;
    QString author = metaObject->classInfo(metaObject->indexOfClassInfo("author")).value();

3.2 Qt全局定义

头文件包含了Qt类库得一些全局定义,包括基本数据类型、函数和宏,一般的Qt类的头文件都会包含该文件,所以不用显式包含这个头文件也可以使用其中的定义。

3.2.1 数据类型定义

为了确保在各个平台上各数据类型都有统一确定的长度,Qt为各种常见数据类型定义了类型符号。如: typedef signed char qint8;

3.2.2 函数

里还包含了一些常用的函数定义,多以模板的形式提供。还有一些基础数学函数在头文件中定义。

3.2.3 宏定义

头文件中定义了很多宏,以下是一些比较常用的。

  • QT_VERSION 数值形式0x050901
  • QT_VERSION_CHECK 整数表示,如: #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
  • QT_VERSION_STR 字符串表示,如"5.9.0"
  • QT_BYTE_ORDER 表示系统内存中数据的字节序,返回值有Q_BIG_ENDIAN表示大端字节序和Q_LITTLE_ENDIAN表示小端字节序。
  • Q_DECL_IMPORT和Q_DECL_EXPORT 设计或使用共享库时,用于导入或导出。
  • Q_DECL_OVERRIDE 用于重载一个虚函数,加了这个宏后,如果要重载的虚函数没有进行任何重载操作,编译时就会报错。
  • Q_DECL_FINAL 将一个虚函数定义为最终级别,不能再被重载/继承。
  • Q_UNUSED(name) 在函数中定义不在函数体里使用的参数。不加它编译器会报警告。
  • foreach 遍历容器类,遍历时是创建的容器副本,所以不能修改原来容器变量的数据项。
  • forever 无限循环。
  • qDebug/qWarning/qCritical/qFatal/qInfo等,用于debugger窗体显示日志。

3. 3 容器类

顺序容器类

  • QList 以数组+列表形式实现的,类似以前写的那个hash map实现。
  • QLinkedList 链式列表,不是用连续内存存储,插入和删除数据项时间相同。
  • QVector 接口和QList几乎完全相同,但它比QList性能更高,因为它的数据项是连续存储的。
  • QStack 类似堆栈的后入先出,push()和pop()是主要的接口函数。
  • QQueue 类似队列先入先出,enqueue()和dequeue()是主要操作函数。

关联容器类

  • QSet 键和值是同一个,无序的,不能插入相同的键,适用需要快速查找与判断重复元素场景。
  • QMap 键值对,按键排序。
  • QMultiMap 是QMap的子类,用于处理一个键值对应多个值场景。
  • QHash 功能和QMap类似,只是它基于散列表来实现字典功能,无序,但是查找速度快。如果对存储遍历顺序不关心,建议使用它。
  • QMultiHash 是QHash的子类,用于处理一个键值对应多个值场景。

3.4 容器的迭代

  1. Java类型迭代器
  2. STL类型迭代器
  3. 使用Qt的宏foreach

3.5 Qt类库的模块

3.5.1 Qt基础模块

3.5.2 Qt附加模块

3.5.3 增值模块

3.5.4 技术预览模块

3.5.5 Qt工具模块

四、常用界面设计组件

4.1 字符串与输入输出

界面设计显示/编辑字符串就是QLableQLineEdit这两个控件了。界面设计主要就是用好布局和占位符Spacers控件。

这两个控件主要接口是QString text() const获取字符串内容和void setText(const QString &)设置字符串内容。

4.1.1 QString 的常用功能

  • append()和prepend() 字符串后面添加和前面添加。
  • toUpper()和toLower() 字符串字母大小写转换。
  • count()、size()和length() 返回结果都一样,返回字符串的字符个数。注意如果有汉字,一个汉字算一个字符。
  • trimmed()和simplified() 前者去掉字符串首尾空格,后者不仅会去掉首尾空格,中间连续的空格也用一个空格替换。
  • indexOf()和lastIndexOf() 查找子字符串开始出现的位置,后者查找子字符串最后出现的位置。
  • isNull()和isEmpty() 判断字符串是否为空。它们区别是,如果一个字符串,只有”\0”(即“”),isNull()返回false,而isEmpty()返回true。只有未赋值的字符串,isNull()才返回true。
  • contains() 判断字符串内是否包含了某个字符串,可指定是否区分大小写。
  • endsWith()和startsWith() 判断是否以某个字符串开头/结束。
  • left()和right() 从字符串中取左边/右边多少个字符。
  • section() 以某个分割符分割字符串,从分割的字符串中指定提取。

4.2 SpinBox的使用

4.3 其它数值输入和显示组件

  • QSlider: 滚动条
  • QScrollBar: 卷滚条
  • QProgressBar: 进度条
  • QDial: 表盘
  • QLCDNumber: 模拟LCD数字显示

4.4 时间日期与定时器

  • QTimeEdit: 编辑和显示时间的组件。
  • QDateEdit: 编辑和显示日期的组件。
  • QDateTimeEdit: 编辑和显示日期时间的组件。
  • QCalendarWidget: 一个用日历形式选择日期的组件。
  • QTimer: 定时器类,不是一个可见的界面组件。timeout()是定时器开始后周期性发射的信号。
  • QTime: 计时器类,开始和结束两点过去多久。xx.start()---xx.elapsed().

4.5 QComboBox和QPlainTextEdit

  • QComboBox:下拉列表控件
  • QPlainTextEdit:编译多行文本的编辑器,提供了复制、粘贴、撤销、全选等快捷操作,还提供了一个标准的右键快捷菜单。

4.6 QListWidget和QToolButton

  • QTabWidget 设计多页界面
  • QToolBox 设计多组工具箱(分组列表)
  • QSplitter 工具栏里,同时选择两个控件,再点工具栏选择分割条,就可以设置两个控件的大小布局。
  • QToolButton 设计具有下拉菜单(setMenu)功能的按钮,可以与Action关联(setDefaultAction)。
  • QListWidget 列表组件
  • 创建右键菜单 信号: customContextMenuRequested()
  • 创建Action

4.7 QTreeWidget和QDockWidget

  • QTreeWidget 创建和管理目录树结构的类。
  • QDockWidget 停靠区域组件。即窗口可以拖出来,悬浮,停靠。
  • QLabel/QPixmap 组件显示图片。

4.8 QTableWidget使用

  • 表格组件类

五、Model/View结构

5.1 原理

就是将显示与数据分开。实现它们由3个东西组成:模型、视图、代理

原理:模型、视图和代理之间使用信号与槽通信,当源数据发生变化时,数据模型发射信号通知视图组件;当用户在界面上操作数据时,视图组件发射信号表示这些操作信息;当编辑数据时,代理发射信号告知数据模型和视图组件编辑器的状态。

5.1.1 数据模型

如果这些现有的模型类无法满足需求,用户也可以从QAbstractItemModel QAbstractListModelQAbstractTableModel继承,实现自己定制的数据模型类。

QT中模型类的继承关系图:

5.1.2 视图组件

视图组件就是显示数据模型的数据的界面组件,Qt提供的视图组件如下:

  • QListView: 显示单列的列表数据
  • QTreeView: 显示树状结构数据
  • QTableView: 显示表格数据
  • QColumnView: 树形结构,每一层是一个QListView
  • QHeaderView: 提供行表头或列表头的视图组件

视图组件和数据模型之间通过setModel()函数关联起来,我们第4节介绍的QListWidget QTreeWidgetQTableWidget是3个便利类,直接用项的方式集成了数据模型的功能,将数据与界面绑定了。所以它们缺乏对大型数据源进行灵活处理的能力,适用于小型数据的显示和编辑。

5.1.3 代理

代理就是在视图组件上为编辑数据提供编辑器,如:在表格组件中编辑一个单元格数据时,代理默认提供一个QLineEdit编辑框。代理负责从数据模型获取相应的数据,然后显示到这个编辑框中,修改数据后,又将其保存到数据模型中。

5.2 QFileSystemModel

QFileSystemModel提供了一个可用于访问本机文件系统的数据模型。与QTreeView结合使用,可以用目录树的形式显示本机上的文件系统。

5.3 QStringListModel

用于处理字符串列表的数据模型,可作为QListView的数据模型。

5.4 QStandardItemModel

标准的以项数据为基础的标准数据模型类。通常与QTableView组合成Model/View结构,实现通用的二维数据的管理功能。

5.5 自定义代理

可以修改默认的编辑控件。

六、 对话框与多窗体设计

6.1 标准对话框

6.2 自定义对话框及其调用

File->New File or Project->Qt->Qt Designer Form Class->Dialog without Buttons

  1. new 对象,设置相关属性。
  2. xx->exec(); 模态方式显示(不能操作其它窗口) 而使用xx->show() 则是以非模态方式打开,可以操作其它窗口。
  3. 分别绑定槽函数accept()/reject() 确定与取消操作。
  4. delete xx; 释放对话框窗口资源。(如果不释放,则对话框只是隐藏)。

注:主窗口与弹框交互,两种形式:1,传递对方的this对象引用直接访问 2,通过信号/槽机制。

6.3 多窗体应用程序设计

  • QWidget: 没有指定父容器时可作为独立的窗口,指定父容器后可以作为容器的内部组件。
  • QDialog: 用于设计对话框,以独立窗口显示。
  • QMainWindow: 一般以独立窗口显示,用于设计带菜单栏、工具栏、状态栏的主窗口。
  • QSplashScreen: 启动窗口,没有边框。
  • QMdiSubWindow: 用于MDI多文档应用程序设计。
  • QDesktopWidget: 多显示器场景。
  • QWindow: 一般作为一个父容器的嵌入式窗体,不作为独立窗体。

窗体类重要特性的设置接口:

  1. setAttribute()函数,原型:

    1
    void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on = true)

    可以打开和关闭这些属性。

  2. setWindowFlags()和setWindowFlag()函数

    设置窗体标记,第一个是一次设置多种,第二个一次设置一个。

  1. setWindowState()函数

    设置窗口处于最大化、最小化等状态。

  2. setWindowModality()函数

    设置窗口的模态,只对窗口类型有用。

  3. setWindowOpacity()函数

    设置窗口的透明度。

6.4 MDI应用程序设计

多文档界面设计,常见的就是代码编辑器,notepad++,便签等这些。使用QMdiArea实现,使用上和tabWidget多页面类似,只是QMdiArea提供了更多的功能。

6.5 Splash与登录窗口

  • 启动界面Splash本质就是对话框,无边框。
  • 鼠标如何拖到无边框对话框。
  • QSettings类注册表读取/写入键值对。
  • QCryptographicHash Md5加解密算法使用。
  • 登录成功后进入主界面操作(main里接收accept消息,进入主界面)。

七、文件系统和文件读写

7.1 文本文件读写

有两种方式:

  1. QFile类的IODevice

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // 读
    QFile aFile(aFileName);
    if (!aFile.exists()) //文件不存在
    return false;
    if (!aFile.open(QIODevice::ReadOnly | QIODevice::Text))
    return false;
    ui->textEditDevice->setPlainText(aFile.readAll());
    aFile.close();

    // 写
    QFile aFile(aFileName);
    if (!aFile.open(QIODevice::WriteOnly | QIODevice::Text))
    return false;
    QString str=ui->textEditDevice->toPlainText(); //整个内容作为字符串
    QByteArray strBytes=str.toUtf8();//转换为字节数组
    aFile.write(strBytes,strBytes.length()); //写入文件
    aFile.close();
  2. QFile和QTextStream结合

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    // 读
    QFile aFile(aFileName);
    if (!aFile.exists()) //文件不存在
    return false;
    if (!aFile.open(QIODevice::ReadOnly | QIODevice::Text))
    return false;

    QTextStream aStream(&aFile); //用文本流读取文件
    aStream.setAutoDetectUnicode(true); //自动检测Unicode,才能正常显示文档内的汉字
    ui->textEditStream->setPlainText(aStream.readAll());

    // 逐行读取
    // ui->textEditStream->clear();//清空
    // while (!aStream.atEnd())
    // {
    // str=aStream.readLine();//读取文件的一行
    // ui->textEditStream->appendPlainText(str); //添加到文本框显示
    // }

    aFile.close();//关闭文件

    // 写
    QFile aFile(aFileName);
    if (!aFile.open(QIODevice::WriteOnly | QIODevice::Text))
    return false;
    QTextStream aStream(&aFile); //用文本流读取文件
    aStream.setAutoDetectUnicode(true); //自动检测Unicode,才能正常显示文档内的汉字
    QString str=ui->textEditStream->toPlainText(); //转换为字符串
    aStream<<str; //写入文本流
    aFile.close();//关闭文件

    解决中文乱码问题:

    上面是通过设置setAutoDetectUnicode(true) QTextStream才可以识别Unicode码,如果不做此设置,读取中文将乱码。还一种方式,就是在main中全局设置,后续文件读写就不需要再特殊设置了。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    int main(int argc, char *argc[])
    {
    // 解决汉字乱码问题
    QTextCodec *codec = QTextCodec::codecForName("UTF-8");
    QTextCodec::setCodecForLocale(codec); //解决汉字乱码问题

    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
    }

7.2 二进制文件读写

使用Qt的QDataStream进行二进制文件读写,有两种形式:

  1. 用Qt预定义编码(不完全知道文件内每个字节的意义)
  2. 用标准编码数据的二进制原始内容.

7.3 文件目录操作

7.3.1 QCoreApplication类

7.3.2 QFile类

  • QFile的一些静态函数

  • QFile的一些成员函数

7.3.3 QFileInfo类

7.3.4 QDir类

  • QDir的一些静态函数

  • QDir的一些成员函数

7.3.5 QTemporaryDir和QTemporaryFile

7.3.6 QFileSystemWatcher类

八、绘图

8.1 QPainter基础绘图

  1. 重载绘图设备(QWidget、QPixmap、QImage等)的paintEvent()接口,在此接口里编写绘图的代码。

  2. pen属性

  3. brush属性

  4. font属性

  5. QPainter绘制基本图形元件的函数

8.2 坐标系统和坐标变换

8.3 Graphics View绘图架构

采用前面QPainter绘图时需要在绘图设备的paintEvent()事件里编写绘图程序,实现整个绘图过程。这种方式如同使用Windows的画图软件在绘图,绘制的图形是位图,不能实现图形的选择、编辑、拖放、修改等功能。

Qt为绘制复杂的可交互图形提供了Graphics View绘图架构,是一种基于图形项的模型/视图模式,类似Model/View模式。

主要由3部分组成:场景、视图和图形项。

8.3.1 QGraphicsView

8.3.2 QGraphicsScene

8.3.3 QGraphicsItem

8.3.4 Graphics View绘图程序示例

九、Qt Charts

9.1 Qt Charts绘图程序

1
2
3
4
5
6
// .pro文件添加
Qt += charts

// 使用处添加头文件
#include <QtCharts>
using namespace QtCharts; // 或者使用宏 Qt_CHARTS_USE_NAMESPACE

图表主要组成(创建使用3步骤):

  1. 创建QChartView,视图组件和QChart图表项。

  2. 序列,即图表绘制的曲线

    常见的序列类有:折线图、柱状图、饼图、散点图等。

  3. 坐标轴

  4. 图例

    是对序列曲线的说明,可以为每条序列设置图例中的文字,可以控制图例显示在图表的上、下、左、右不同位置。QLegendQLegendMarker后面这个还有类似QCheckBox是否选择标记,来控制序列是否显示。

9.2 QChart绘制折线图

综合示例:

9.2.1 QChart类的主要函数

9.2.2 QLineSeries序列类的主要函数

9.2.3 QValueAxis坐标类的主要函数

9.3 各种常见图标的绘制

柱状图、饼图、堆叠图、百分比柱状图和散点图。

9.3.1 柱状图相关类函数

9.3.2 饼图相关类函数

9.3.3 堆叠柱状图

和创建柱状图类似

9.3.4 百分比柱状图

9.3.5 散点图和光滑曲线图

9.4 图表的其它操作

图表的一些常用操作:

十、Data Visualization

Data Visualization是Qt提供的用于数据三维显示的模块。主要是三维柱状图、三维空间散点和三维曲面的显示。

三维地形图:

十一、数据库

Qt SQL模块提供了数据库编程的支持,支持多种常见的数据库,如MySQL、Oracle、MS SQL Server、SQLite等。可以实现数据库连接、SQL语句执行、数据获取与界面显示等功能,数据与界面之间使用Model/View架构。

这节没什么好看的,后续实际项目需要使用时再细看。

十二、自定义插件和库

就是扩展Qt控件库。有两种形式:

12.1 自定义Widget组件

  1. 创建自定义类,继承QWidget

  2. 重写paintEvent()事件,进行自定义控件绘制

  3. Qt Desinger设计器拖拽一个Widget控件,然后右键调出快捷菜单,单机”Promote to“菜单项,将Widget控件提升为自定义的类控件。

12.2 自定义Qt Designer插件

在Qt Designer中新增自定义控件。添加后,可以像内置控件一样拖拽使用了。 文档流程很详细了,后续项目中有需求时再来详细看。

12.3 创建和使用静态链接库

没啥特别的~

12.4 创建和使用共享库

没啥特别的~

十三、多线程

13.1 QThread创建多线程程序

跨平台,一般就是在主线程里调start()启动,其内部会调用run(),在run()里调用exit()quit()可以结束线程,或在主线程里调用terminate()强制结束线程。

Qthread类主要接口:

13.2 线程同步

在Qt中,有多个类可以实现线程同步功能,包括QMutexQMutexLoackerQReadWriteLockQReadLockerQWriteLockerQWaitCondition和QSemaphore。

至于各自之间使用场景和差异,后续具体使用时再详看~

十四、网络编程

主要涉及主机信息查询相关接口、TCP、UDP、HTTP等的封装使用。这些与界面设计无关,等实际使用时再详看。

十五、多媒体

Qt的多媒体模块为音频和视频播放、录音、视像头拍照和录像等提供支持,甚至还提供数字收音机的支持。

本章也是等使用时再看~

十六、应用程序设计辅助功能

16.1 多语言界面

16.2 使用样式表自定义界面

类似HTML的CSS,在UI设计器中可以编辑,右键组件选择”Change styleSheet…”编辑样式。

上方有几个具有下拉菜单的按钮,可以添加一些常用的样式属性,如前景色、背景色、选中后颜色,以及背景图片等。这种方式设计的样式保存在窗体的ui文件里,窗体创建时自动应用。

还一种通过代码的方式加载样式的方式更为灵活:QWidget::setStyleSheet(mystyle.qss)

16.3 使用QStyle设置界面外观

Qt控件样式在不同平台默认样式是不一样的,QStyle内置了很多样式,可以通过QStyleFactory::keys()获取运行平台支持的样式列表,然后用QStyleFactory::create()创建样式,再用QApplication::setStyle()设置样式即可。

也可以通过继承QStyle实现自定义样式。一般是从其子类QProxyStyle继承

16.4 Qt应用程序的发布

一般使用共享库方式。

Qt在windows上的发布工具windeployqt.exe,它可以生成待发布程序目录,包含所有依赖库,不如注意执行完后,要点目标文件执行下试试,看到缺什么库手动拷贝过来,直到能正常运行。

最后就是找一个制作安装程序的工具,制作安装文件。这个自行查阅,有很多!