您的位置:首页 > 编程语言 > C语言/C++

《Qt5.9 C++开发指南》第3章(共16章)解读

2020-01-13 17:04 176 查看

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

一、

元对象系统组成:

  1. QObject类是所有使用元对象系统的类的基类;
  2. 在一个类的private部分声明Q_OBJECT宏(使得该类可以使用元对象的特性,如动态属性、信号与槽)
  3. MOC–元对象编译器

MOC的作用:给包含Q_OBJECT的类源文件生成一个C++源文件(包含元对象支持的代码),然后这两个源文件一起编译链接。

元对象系统功能:

  1. 信号与槽机制;
  2. 返回类关联元对象;
  3. 创建一个类的新实例;
  4. 判断某个对象是否为某个类的实例;
  5. 翻译字符串;
  6. 通过属性名称动态设置、获取属性值。

属性系统:通过Q_PROPERTY()宏定义属性

  • 可通过QObject::property()读取属性值

  • 可通过QObject::setProperty()设置属性值

  • 动态属性:setproperty可以在程序运行时为类定义一个新的属性,称之为动态属性。

  • 类的附加信息:Q_CLASSINFO

信号与槽补充:

  1. Qt框架使用信号与槽实现对象间通信,与其他框架下回调函数类似。使用信号与槽更慢一些,但是更灵活。
  2. 原型1:
QMetaObject::Connection QObject::connect(const QObject *sender,const char *signal,const QObject *receiver,const char *method,Qt::ConnectionType type = Qt::AutoConnection)
//example
connect(spinNum,SIGNAL(valueChange(int)),this,SLOT(updateStatus()));
//如果信号与槽带有参数,需要指明参数类型
  1. 原型2:
QMetaObject::Connect QObject::connect(const QObject *sender,const QMetaMethod &signal,const QObject *receiver,const QMetaMethod &method,Qt::ConnecttionType type = Qt::AutoConnection)
//1.函数名唯一:使用函数指针进行关联,可省略函数参数
//example
connect(lineEdit,&QLineEdit::textChange,this,&widget::on_textChanged);
//2.函数名不唯一(即参数有区别),不可省略参数
//example
void QSpinBox::valueChange(int i);
void QSpinBox::valueChange(const QString &text);
connect (spinNum,&QSpinBox::valueChange,this,&widget::onValueChange);
//使用以上connect则会编译错误

4.最后一个参数:Qt::ConnectionType type

  • Qt ::AutoConnect(缺省值):如果信号发送者与接受者在同一个线程,使用QT::DirectConnection方式;否则使用Qt::QueuedConnection方式,在信号发射时自动确定关联方式。

1)Qt::DirectConnection:信号被发射时槽函数立即执行,执行完成后再返回发射处执行后面的代码,参函数与信号在同一个线程。
2)Qt::QueuedConnection:在事件循环到接受者线程后执行槽函数。槽函数与信号在不同线程。
3)Qt::BlockingQueuedConnection:与2类似,只是信号线程会阻塞到槽函数执行完毕。所以用在同一个线程就会死锁。

others:

  1. 使用sender()获得信号发射者(可结合相关函数对信号发射者进行操作)
  2. 自定义信号及其使用:信号就是在类定义里声明的一个函数,信号函数无返回值,可以输入参数,无需实现。
  3. 到这里Q_OBJECT宏就表示支持元对象系统。

特殊情形----多个同类型组件+同一信号+同一槽函数

  • 通过设置动态属性(给组件),然后根据使用信号发射者的类型投射确定是哪一个类型,然后根据预先设置的不同动态属性判断出是哪一个对象【猜测】

二、Qt全局定义

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

1. 数据类型定义

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

2.函数

QtGlobal头文件中包含一些常用函数的定义,这些函数多以模板类型作为参数,返回相应的模板类型。模板类型可以用任何其他类型替换。

3.宏定义

(1)Q_DECL_OVERRIDE:在类定义中,用于重载一个虚函数

void paintEvent(QPainEvent*) Q_DECL_OVERRIDE;//declare宣布
  • 如果重载的虚函数没有进行任何操作,编译器会报错

(2)Q_DECL_FINAL:表示虚函数不能被重载或者类不能被继承
(3)Q_UNUSED(name):用于在函数体中定义不在函数体中使用的参数
(4)foreach(variable,container):用于容器类的遍历
(5)forever:用于构造一个无限循环
(6)qDebug(const char *message,…)在debugger窗体显示信息

4.容器类

1概述
  • Qt提供了多个基于模板的容器类,如QStringList就是从容器类QList<QString继承的
  • Qt的容器类比标准模板库(stl)中的容器更轻巧(进行了速度、存储优化,减少可执行文件大小)、安全(作为只读容器可被多个线程访问)和易于使用(隐士共享、可重入)。
  • 容器类是基于模板的类,如常用的容器类QList《T》,T是一个具体的类型,可以是int、float等简单类型,也可是QString、QDate等类,但不能是QObject或任何其子类。T必须是一个可赋值的类型,即T必须提供一个缺省的构造函数、一个可复制构造函数和一个赋值运算符。
//.example
QList<QString> aList;
aList.append("Monday");
aList.append("Tuesday");
aList.append("Wednesday");
QString str=aList[0];
2顺序容器类

Qt顺序容器类有QList、QLinkedList、QVector、QStack和QQueue

  1. QList
    最常用的容器类,以数组列表的形式实现,在其前后添加数据非常快,以下标索引的方式对数据项进行访问。
    insert();
    replace();
    removeAt();
    move();
    swap();
    append();
    prepend();
    removeFirst();
    removeLast();
    数据访问:list[1]=list.at(1)
    判断为空:isEmpty
    返回数据项个数:size()

  2. QLinkedList
    链式链表,数据项是不用连续的内存存储的,基于迭代器访问数据,并且插入和删除数据项的操作时间相同。不提供下标索引数据访问。

  3. QVector
    提供动态数据的功能,以下标索引访问数据。QVector与QList接口几乎相同,性能更优,因为数据项是连续存储的。

  4. QStack
    类似于堆栈的后入先出操作的容器类,push()与pop()是主要接口函数。

  5. QQueue
    类似于队列先入先出操作的容器类。enqueue()与dequeue()是主要操作函数。

3关联容器类

Qt还提供关联容器类QMap、QMultiMap、QHash、QMultiHash和QSet

  1. QSet
    基于散列表的集合模板类,存储数据的顺序不定,查找值的速度非常快,内部用QHash实现。
QSet<QString> set;
set<<"dog"<<"cat"<<"tiger";
//.测试一个值是否包含于这个集合,用contains()函数
if(!set.contains("cat"))
...
  1. QMap
    QMap<Key,T>提供一个字典(关联数组),一个键映射到一个值。存储数据是按照键的顺序。如果不在乎存储顺序,用QHash会更快。
QMap<QString,int> map;
map["one"]=1;
map["two"]=2;
map["three"]=3;
//可以使用insert()函数赋值,使用remove()移除一个键值对。
map.insert("four",4);
map.remove("two");
//要查找一个值,使用运算符[]或value函数
int num1=map["one"];
int num2=map.value("two");//可以指定缺省返回值
  1. QMultiMap
    是QMap的子类,是用于处理多值映射的便利类。
    多值映射指一个键可以对应多个值。
    QMultiMap不提供[ ]操作符,使用value查看最新插入的键的单值,如果获取一个键对应的所有值,使用values()函数。返回值QList类型

  2. QHash
    基于散列表实现字典功能的模板类。查找速度非常快。
    QHash与QMap的区别
    1)QHash比QMap查找速度快
    2)QMap遍历时,数据项是按照键排序的,而QHash的数据项是任意顺序的
    3)QMap的键必须提供“<”运算符,QHash的键必须提供“==”运算符和一个名为qHash()的全局散列函数。

  3. QMultiHash
    是QHash的子类,用于处理多值映射的便利类。

5.容器类的迭代

迭代器为访问容器类里的数据项提供了统一的方法,Qt有两种迭代器:Java类型的迭代器与STL类型的迭代器。Qt还提供一个关键字foreach用于方便的访问容器里的所有数据。

  1. Java类型迭代器
    1)Java类型迭代器总表:对于每个容器类,有两个Java类型迭代器,一个用于只读操作,一个用于读写操作。
    2)顺序容器类的迭代器的使用
    QListIterator
    QMutableListIterator
    有对应的格式与接口函数,自己看书去吧。
    3)关联容器类的迭代器的使用
    同上。
  2. STL类型迭代器
    1)STL类型迭代器总表:同上。需修改数据用只读,因为速度更快。数组指针,++ 指向下一个数据,*返回数据项内容。key()返回键
    2)顺序容器类的迭代器的使用
    3)关联容器类的迭代器的使用
    Note:隐式共享----对象管理方法。一个对象被隐式共享,只是传递一个该对象的指针给使用者,而不实际复制对象数据,只有在使用者修改数据时,才实质复制共享对象给使用者。所以需要注意当一个迭代器在操作一个容器变量时,不要去复制这个容器变量。
  3. foreach关键字:遍历容器中的所有项。foreach是QtGlobal中定义的一个宏。对于“键–值”对自动访问值。foreach在遍历的时候其实创建了一个容器的副本,所以他修改不了容器的值。

Qt类库的模块

类根据功能划分为模块:Qt基本模块、Qt附加模块、增值模块、技术预览模块、Qt工具

  1. Qt基本模块:(常见的)core、gui、network、widgets
    用到那个模块需要在配置文件中添加(即.pro文件)

  2. Qt附加模块:用于解决某些特殊场景的问题(有辅助功能之嫌)

  3. 增值模块:具体有
    1)Qt for Device Creation:高效、易用、全集成的嵌入式设备应用程序开发工具
    2)Qt Quick Compiler。确实很增值,很实用:编译.qml源文件生成二进制应用程序的编译器,提高载入时间和代码安全性。

  • 点赞 1
  • 收藏
  • 分享
  • 文章举报
Nuoya_Ark 发布了5 篇原创文章 · 获赞 4 · 访问量 77 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: