目录
- 一、Qt核心特点
-
- 二、Qt全局定义(常用头文件)
-
- 三、容器类
- 1. 顺序容器
- 1)QList
- 2)QLinkedList
- 3)QVector
- 4)QStack
- 5)QQueue
- 2. 关联容器
- 1)QSet
- 2)QMap
- 3)QMUltiMap
- 4)QHash
- 5)QMultiHash
- 四、容器的迭代
- 1. Java型迭代器
- 1)顺序容器类的迭代器使用
- 2)关联容器的迭代器使用
- 2. STL型迭代器
-
- 3. foreach关键字
一、Qt核心特点
Qt core是Qt类库的核心,所有其他模块都依赖于此模块,若使用qmake来构建项目,Qt core类里的模块则是被自动加入的;
Qt为C++语言增加的特性,就是在Qt core的模块里实现的吗,这些扩展特性由Qt的元对象系统实现,包括信号与槽机制,属性系统、动态类型转化等。
1. 元对象系统
Qt的元对象系统 提供了对象之间通信的信号与槽机制、运行时类型信息和动态属性系统:
元对象由一下三个基础组成:
- QObject类是所有使用元对象系统的类的基类
- 在一个类的private声明Q_OBJECT宏,使得类可以使用元对象的特性,如动态属性、信号与槽
- MOC(元对象编译器)为每个QOject的子类提供必要的代码来实现元对象系统的特性
构建项目时,MOC工具读取C++源文件,发现类中有Q_OBJECT宏时,会为这个类生成另外一个包含有元对象支持代码的C++源文件,这个生成的源文件连同类的实现文件被一起被编译和链接
除了信号与槽机制外,元对象还提供了一些功能:
- QObject::metaObject()函数:返回类关联的元对象,元对象类QMetaObject包含了访问元对象的一些接口函数,比如 QMetaObject::className() 函数可在运行时返回类的名称字符串:
QObject *obj = new QPushButton;
obj->metaObject()->className();
- QMetaObject::newInstance()函数: 创建类的一个实例
- QObject::inherits(const char* className)函数:判断一个对象实例是否是名称为className的类或QObject的实例
QTimer * timer = new QTimer;
timer->inherits("QTimer");
timer->inherits("QObject");
timer->inherits("QAbstructButton");
- QObject::tr() 和 QObject::trUtf8()函数:可翻译字符串,用于多语言界面设计
- QObject::setProperty()和QObject::property()函数:用于通过属性名称动态 设置和获取属性值
- QObject及其子类,还可以使用 qobject_cast() 函数进行动态投射(类似于C++多态调用那样),他并不区分Qt内建类型和用户自定义类型
2. 信号与槽的关联方式
不管是那种类型的connect函数,最后都有一个参数Qt::connectionType type(是个枚举类型,缺省是 Qt::AutoConnection),有以下几种取值:
- Qt::AutoConnection:若信号的接受者和发送者在同一个线程,就使用Qt::DirectConnection方式;否则使用Qt::queuedConnection方式,在信号发射时自动确定关联方式
- Qt::DirectConnection:信号被发射时槽函数立即执行,槽函数和信号在同一个线程
- Qt::queuedConnection:在事件循环回到接收者线程后执行槽函数,槽函数与信号不在一个线程
- Qt::BlockingQueuedConnection:与Qt::queuedConnection类似,只是信号线程会阻塞知道槽函数执行完毕;当信号与槽函数在同一个线程时绝对不能使用此方式,否则会造成死锁
自定义信号及其使用
信号就是在类定义里声明的一个函数,但这个函数无需实现,只需发射(emit)
class QPerson : public QObject
{
Q_OBJECT
private:
int m_age=10;
public:
void incAge();
signals:
void ageChanged(int value);
};
信号函数必须是无返回值的函数,但是可以有参数,无需实现,只要在某些条件下发射信号
void QPerson::incAge()
{
m_age++;
emit ageChanged(m_age);
}
二、Qt全局定义(常用头文件)
1. <QtGlobal>头文件
<QtGlobal>头文件中包含了Qt类库的一些全局定义,包括基本数据类型、函数和宏,一般的Qt类的头文件都会包含该文件,so可以不用显式的包含次头文件
1)数据类型定义
为了确保在各个平台上各数据类型都有统一确定的长度,Qt为各种常见的数据类型定义了类型符号,如qint8就是signed char的类型定义;
<QtGlobal>中定义的数据类型如下:
qfloat16是Qt 5.9.0中新增的一个类,用于表示16位的浮点数,要使用的话,需包含<QFloat16>头文件
2)函数
<QtGlobal>包含的一些常用函数的定义,大部分是以模板类型作为参数,返回相应的模板类型,模板类型可以用其他类型替换;
一般要是以double或float为参数的,几乎都有两个参数版本的同名函数
一些常用的全局函数如下所示:
还有一些基础的数学运算函数在<QtMath>头文件中定义,如三角运算函数、弧度与角度间的黄钻换函数等
3)宏定义
<QtGlobal>中有很多宏定义,常用的宏定义有如下这些:
-
QT_VERSION:
表示Qt编译期版本,比如Qt编译期版本为5.9.0,则QT_VERSION为0x050901;
常用于条件编译设置,根据Qt版本不同,编译不同的代码段
-
QT_VERSION_CHECK:
是Qt版本号的一个整数表示
-
QT_VERSION_STR:
是Qt版本号的字符串
-
Q_BYTE_ORDER、Q_BIG_ENDIAN、Q_LITTLE_ENDIAN*:
Q_BYTE_ORDER表示系统内存中数据的字节序,Q_BIG_ENDIAN表示大端字节序,Q_LITTLE_ENDIAN表示小端字节序;
一般用于判断系统字节序
-
Q_DECL_IMPORT、Q_DECL_EXPORT:
用于导入或导出库的内容,常用与使用或设计共享库
-
Q_DECL_OVERRIDE:用于在类定义中重载一个虚函数,若重载的虚函数没有进行任何重载操作,编译器将会报错
-
Q_DECL_FINAL:
这个宏讲一个虚函数定义为最终级别,不能再被继承,或已定义一个类不能再被继承
-
Q_UNUSED(name):
该宏用于在函数中定义不在函数体里使用的参数,在函数里要是某变量没有被使用,也没有Q_UNUSED定义,编译期会出现参数未使用的警告
-
foreach(variable,container):
用于容器类的遍历
-
forever:
用于构造一个无限循环
-
qDebug(const char * message):
在debugger窗体显式信息,如编译期设置了Qt_NO_BEBUG_OUTPUT,则不做任何输出
三、容器类
Qt提供了多个基于模板的容器类,他们可以用于存储指定类型的数据项;
Qt的容器类比stl的容器类更轻巧、安全和易于使用,他们是隐式共享和可重入的,且他们进行了速度和存储优化,因此可以减少可执行文件的大小;
他们是线程安全的,可以在作为只读容器时被多个线程同时访问;
容器类是基于模板的类,如QList<T>,T是一个具体的类型,可以是int、float等简单类型,也可以是QString、QDate等类,但不能是QObject或其任何子类,T必须是一个可赋值的类型,即T必须提供一个缺省的构造函数,一个可拷贝构造函数和一个赋值运算符
Qt容器类分为顺序容器和关联容器;Qt还提供了foreach宏用于遍历容器内的所有数据项
1. 顺序容器
1)QList
QList是最常用的容器类,以数组列表形式实现,在其前面和后面增添数据很快,以下标方式访问数据项,也提供at()函数;
成员函数有:insert()、replace()、removeAt()、move()、swap()、append()、prepend()、removeFirst()和 removeLast()等;
2)QLinkedList
他是链式列表,数据项不是用连续的内存存储的,它基于迭代器访问数据项,并且插入和删除数据项的操作时间相同;
他不提供基于下标的访问方式,其余接口与QList基本相同
3)QVector
提供动态数组功能,以下标索引访问数据;
函数接口几乎与QList基本相同,QVector<T> 比 QList<T> 的性能更好,因为它的数据项是连续存储的
4)QStack
类似于堆栈的具有先进后出特性的容器类,push()和pop()是主要的接口函数;
#include <QStack>
#include <QDebug>
void TestQStack()
{
QStack<int> stack;
stack.push(10);
stack.push(20);
stack.push(30);
while (!stack.isEmpty())
qDebug()<< stack.pop();
}
5)QQueue
类似于队列的具有先进先出特性的容器类,enqueue()和dequeue()是主要的操作函数;
#include <QQueue>
#include <QDebug>
void TestQQueue()
{
QQueue<int> queue;
queue.enqueue(10);
queue.enqueue(20);
queue.enqueue(30);
while (!queue.isEmpty())
qDebug()<< queue.dequeue();
}
2. 关联容器
1)QSet
是基于散列表的集合模板类,存储数据的顺序是不定的,查找值的速度非常快;
QSet<T>内部就是QHash实现的;
#include <QSet>
#include <QDebug>
void TestQQueue()
{
QSet<QString> set;
set<<"dog"<<"cat"<<"tiger";
if(!set.contains("cat"))
{
qDebug<<"容器内不包含cat";
}
}
2)QMap
QMap<key,T>提供一个字典(关联数组),一个键映射到一个值;
QMap存储数据时按照键的顺序,若不在乎存储顺序,建议使用QHash更快;
#include <QMap>
#include <QDebug>
void TestQMap()
{
QMap<int,char> _map;
for(int i=97;i<123;i++)
{
_map[i]=i;
}
foreach(char c,_map)
{
qDebug()<<c;
}
qDebug()<<_map[100];
char upper_a=_map.value(65,'A');
qDebug()<<upper_a;
}
若在映射表中没有找到指定的键,会返回一个缺省构造值,如,若值得类型是字符串,会返回一个空字符串;
在使用value()查找键值时,还可以指定一个缺省的返回值:
timeout=map.value("TIMEOUT",30);
表示如果在map里找到键“TIMEOUT”了就返回关联的值,未找到就返回30
3)QMUltiMap
他是QMap的子类,用于处理多值映射的便利类;
QMultiMap不提供[]操作符,使用value()函数访问最新插入的键的单个值,若要获取一个键对应的值所有值,使用values()函数,返回值是QList<T>类型;
#include <QMultMap>
#include <QDebug>
void TestQMultiMap()
{
QMultiMap<char,QString> _multiMap;
_multiMap.insert('*',"pointer");
_multiMap.insert('*',"all");
_multiMap.insert('*',"multiplication sign");
qDebug()<<_multiMap.value('*');
QList<QString> _list=_multiMap.values('*');
foreach(QString str,_list)
{
qDebug()<<str;
}
for(int i=0;i<_list.size();i++)
{
qDebug()<<_list[i];
}
}
4)QHash
他是基于散列表来实现字典功能的模板类,具有非常快的查找速度;
QHash的数据项是无序的,QHash必须提供“==”运算符和一个QHash()的全局散列函数;
5)QMultiHash
QMultiHash 是 QHash 的子类,是用于处理多值映射的便利类,其用法与 QMultiMap 类似
四、容器的迭代
Qt有两种类型的迭代器:Java型迭代器 和 STL型迭代器
1. Java型迭代器
Qt提供有以下几种迭代器,对于每个容器类,有两个Java型迭代器,一个只读迭代器,一个读写迭代器:
容器类 | 只读迭代器 | 读写迭代器 |
---|
QList<T>, QQueue<T> | QListIterator<T> | QMutableListIterator<T> |
QLinkedList<T> | QLinkedListIterator<T> | QMutableLinkedList<T> |
QVector<T>, QStack<T> | QVectorIterator<T> | QVectorMutableIterator<T> |
QSet<T> | QSetIterator<T> | QSetMutableIterator<T> |
QMap<T>, QMultiMap<T> | QMapiterator<T> | QMutaleMapIterator<T> |
QHash<T>, QMultiHash<T> | QHashIterator<T> | QMutableHashIterator<T> |
1)顺序容器类的迭代器使用
Java类型的迭代器的指针不是指向一个数据项,而是指向数据项之间的位置:
QListIterator常用函数
- void toFront():迭代器移动到列表的最前面(第一个数据项之前)
- void toBack():迭代器移动到列表的最后面(最后一个数据项之后)
- bool hasNext():若迭代器不位于最后位置,返回true
- bool hasPrevious():若迭代器不位于最前面的位置,返回true
- const T & next():返回下一个数据项,并且迭代器后移一个位置
- const T & peekNext():返回下一个数据项,但迭代器不移动
- const T & previous():返回前一个数据项,并且迭代器前移一个位置
- const T & peekPrevious():返回前一个数据项,但迭代器不移动
QMutableListIterator是读写迭代器,可用于修改容器中的数据;
remove()函数移除next()函数刚刚跳过去的数据项,不会使迭代器失效;
setValue()函数可以修改刚刚跳过去的数据项的值;
#include <QList>
void Test()
{
QList<QString> list;
list<<"A"<<"B"<<"C"<<"D";
QListIterator<QString> i(list);
while(i.hasNext())
{
qDebug<<i.next();
}
i.toBack();
while(i.hasPrevious())
{
qDebug()<<i.previous();
}
QList<int> list2;
list2<<1<<2<<3<<4<<5;
QMutableListIterator<int> it(list2);
while(it.hasNext())
{
if(it.next() % 2==0)
{
it.remove();
}
}
}
2)关联容器的迭代器使用
对于关联容器的迭代器,普通函数接口同顺序性容器的哪些基本类似,主要是增加了key()和value()函数用于获取刚刚跳过的数据项的键和值;
void Test()
{
QMap<QString,QString> map;
map.insert("Paris","France");
map.insert("New York","USA");
map.insert("Mexico City","USA");
QMutableMapIterator<QString,QString> i(map);
while(i.hasNext())
{
if(i.next().endsWith("City"))
{
i.remove();
}
}
}
若是在多值容器里遍历,可用findNext()或 findPrevious()查找:
QMutableMapIterator<QString,QString> i(map);
while(i.findNext("USA"))
{
i.remove();
}
2. STL型迭代器
STL迭代器与Qt和STL的原生算法兼容,并且进行了速度优化,,因此它的效率更高;
类似的,对于每个容器类,也有两个STL型迭代器:比如对于QList<T>, 则有只读迭代器QList<T>::const_iterator 和 读写迭代器QList<T>::iterator;
STL型迭代器是数组的指针,所以“++”运算符使迭代器指向下一个数据项,“*”运算符返回数据内容:
end()函数指向一个虚拟的表示结尾的数据项,实际是无效的,一般作为循环结束条件;
1)顺序容器的迭代器使用
constBegin()和constEnd()是用于只读迭代器的,表示起始位置和结束位置;
QList<QString> list;
list<<"A"<<"B"<<"C"<<"D";
QList<Qstring>::const_iterator i;
for(i=list.constBegin();i!=list.constEnd();++i)
{
qDebug<< *i;
}
QList<QString>::reverse_iterator i2;
for(i2=list.rbegin();i2!=list.rend();++i2)
{
*i=i->toLower();
}
2)关联容器的迭代器使用
对于关联容器类QMap 和 QHash,迭代器的“*”操作符返回数据项的值,若想返回键,则用key()函数,对应的value()函数返回值:
QMap<int,int> map;
QMap<int,int>::const_iterator i;
for(i=map.constBegin();i!=map.constEnd();++i)
{
qDebug()<<i.key()<<":"<<i.values();
}
3. foreach关键字
如只是需要遍历容器,则可以使用foreach关键字;
foreach的语法是:foreach (variable,container)
QLinkedList<QString> list;
...
QString str;
foreach(str,list)
{
qDebug()<<str;
}
foreach(const QString &str,liat)
{
qDebug()<<str;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)