Qt core是Qt类库的核心,所有其他模块都依赖于此模块,若使用qmake来构建项目,Qt core类里的模块则是被自动加入的;
Qt为C++语言增加的特性,就是在Qt core的模块里实现的吗,这些扩展特性由Qt的元对象系统实现,包括信号与槽机制,属性系统、动态类型转化等。
Qt的元对象系统 提供了对象之间通信的信号与槽机制、运行时类型信息和动态属性系统:
元对象由一下三个基础组成:
构建项目时,MOC工具读取C++源文件,发现类中有Q_OBJECT宏时,会为这个类生成另外一个包含有元对象支持代码的C++源文件,这个生成的源文件连同类的实现文件被一起被编译和链接
除了信号与槽机制外,元对象还提供了一些功能:
QObject *obj = new QPushButton;
obj->metaObject()->className();//返回“QPushButton”
QTimer * timer = new QTimer;
timer->inherits("QTimer");//true
timer->inherits("QObject");//true;
timer->inherits("QAbstructButton");//false
不管是那种类型的connect函数,最后都有一个参数Qt::connectionType type(是个枚举类型,缺省是 Qt::AutoConnection),有以下几种取值:
自定义信号及其使用
信号就是在类定义里声明的一个函数,但这个函数无需实现,只需发射(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为各种常见的数据类型定义了类型符号,如qint8就是signed char的类型定义;
qfloat16是Qt 5.9.0中新增的一个类,用于表示16位的浮点数,要使用的话,需包含
一般要是以double或float为参数的,几乎都有两个参数版本的同名函数
一些常用的全局函数如下所示:
还有一些基础的数学运算函数在
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
Qt容器类分为顺序容器和关联容器;Qt还提供了foreach宏用于遍历容器内的所有数据项
QList是最常用的容器类,以数组列表形式实现,在其前面和后面增添数据很快,以下标方式访问数据项,也提供at()函数;
成员函数有:insert()、replace()、removeAt()、move()、swap()、append()、prepend()、removeFirst()和 removeLast()等;
他是链式列表,数据项不是用连续的内存存储的,它基于迭代器访问数据项,并且插入和删除数据项的操作时间相同;
他不提供基于下标的访问方式,其余接口与QList基本相同
提供动态数组功能,以下标索引访问数据;
函数接口几乎与QList基本相同,QVector
类似于堆栈的具有先进后出特性的容器类,push()和pop()是主要的接口函数;
#include
#include
void TestQStack()
{
QStack<int> stack;
stack.push(10);
stack.push(20);
stack.push(30);
while (!stack.isEmpty())
qDebug()<< stack.pop();//30 20 10
}
类似于队列的具有先进先出特性的容器类,enqueue()和dequeue()是主要的操作函数;
#include
#include
void TestQQueue()
{
QQueue<int> queue;
queue.enqueue(10);
queue.enqueue(20);
queue.enqueue(30);
while (!queue.isEmpty())
qDebug()<< queue.dequeue();//10 20 30
}
是基于散列表的集合模板类,存储数据的顺序是不定的,查找值的速度非常快;
QSet
#include
#include
void TestQQueue()
{
QSet<QString> set;
set<<"dog"<<"cat"<<"tiger";
if(!set.contains("cat"))
{
qDebug<<"容器内不包含cat";
}
}
QMap
QMap存储数据时按照键的顺序,若不在乎存储顺序,建议使用QHash更快;
#include
#include
void TestQMap()
{
//QMap存储数据是按照键的顺序
QMap<int,char> _map;
for(int i=97;i<123;i++)
{
_map[i]=i;
}
foreach(char c,_map)
{
qDebug()<<c;//按顺序a b c...输出
}
qDebug()<<_map[100];//d
char upper_a=_map.value(65,'A');
qDebug()<<upper_a;//A
}
若在映射表中没有找到指定的键,会返回一个缺省构造值,如,若值得类型是字符串,会返回一个空字符串;
在使用value()查找键值时,还可以指定一个缺省的返回值:
timeout=map.value("TIMEOUT",30);
表示如果在map里找到键“TIMEOUT”了就返回关联的值,未找到就返回30
他是QMap的子类,用于处理多值映射的便利类;
QMultiMap不提供[]操作符,使用value()函数访问最新插入的键的单个值,若要获取一个键对应的值所有值,使用values()函数,返回值是QList
#include
#include
void TestQMultiMap()
{
QMultiMap<char,QString> _multiMap;
//QMultiMap 不提供“[]”操作符
//_multiMap['0']="ss";
_multiMap.insert('*',"pointer");
_multiMap.insert('*',"all");
_multiMap.insert('*',"multiplication sign");
qDebug()<<_multiMap.value('*');//最新的值 multiplication sign
QList<QString> _list=_multiMap.values('*');
foreach(QString str,_list)
{
qDebug()<<str;//"multiplication sign"
//"all"
//"pointer"
}
for(int i=0;i<_list.size();i++)
{
qDebug()<<_list[i];//"multiplication sign"
//"all"
//"pointer"
}
}
他是基于散列表来实现字典功能的模板类,具有非常快的查找速度;
QHash的数据项是无序的,QHash必须提供“==”运算符和一个QHash()的全局散列函数;
QMultiHash 是 QHash 的子类,是用于处理多值映射的便利类,其用法与 QMultiMap 类似
Qt有两种类型的迭代器:Java型迭代器 和 STL型迭代器
Qt提供有以下几种迭代器,对于每个容器类,有两个Java型迭代器,一个只读迭代器,一个读写迭代器:
容器类 | 只读迭代器 | 读写迭代器 |
---|---|---|
QList |
QListIterator |
QMutableListIterator |
QLinkedList |
QLinkedListIterator |
QMutableLinkedList |
QVector |
QVectorIterator |
QVectorMutableIterator |
QSet |
QSetIterator |
QSetMutableIterator |
QMap |
QMapiterator |
QMutaleMapIterator |
QHash |
QHashIterator |
QMutableHashIterator |
Java类型的迭代器的指针不是指向一个数据项,而是指向数据项之间的位置:
QListIterator常用函数
QMutableListIterator是读写迭代器,可用于修改容器中的数据;
remove()函数移除next()函数刚刚跳过去的数据项,不会使迭代器失效;
setValue()函数可以修改刚刚跳过去的数据项的值;
#include
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();
}
}
}
对于关联容器的迭代器,普通函数接口同顺序性容器的哪些基本类似,主要是增加了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();
}
STL迭代器与Qt和STL的原生算法兼容,并且进行了速度优化,,因此它的效率更高;
类似的,对于每个容器类,也有两个STL型迭代器:比如对于QList
STL型迭代器是数组的指针,所以“++”运算符使迭代器指向下一个数据项,“*”运算符返回数据内容:
end()函数指向一个虚拟的表示结尾的数据项,实际是无效的,一般作为循环结束条件;
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();
}
对于关联容器类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();
}
如只是需要遍历容器,则可以使用foreach关键字;
foreach的语法是:foreach (variable,container)
QLinkedList<QString> list;
...
QString str;
foreach(str,list)
{
qDebug()<<str;
}
//第二种方式
foreach(const QString &str,liat)
{
qDebug()<<str;
}