Linux环境下QT开发(三)——QT编程基础
在上一篇文章中,我们完成了第一个程序——HelloWorld。在这篇文章中,我将介绍一些QT编程基础知识,让我们由此进入QT的世界!
本系列文章主要参考自《Qt 5.9 C++开发指南》,一本很适合初学者的书,此外,该文章还需要你有一定的C++基础哟
本篇文章对应为该书中的第三章,但只介绍最基础部分,目前掌握这些就可以了
一、QT中的数据类型
QT为了统一不同平台上变量占用内存的大小,对一些常用变量进行了封装,在<QtGloabl>
中都有定义,具体可参照下表
QT数据类型 | 等效定义 | 字节数 |
---|---|---|
qint8 | signed char | 1 |
qint16 | signed short | 2 |
qint32 | signed int | 4 |
qint64 | long long int | 8 |
qlonglong | long long int | 8 |
quint8 | unsigned char | 1 |
quint16 | unsigned short | 2 |
quint32 | unsigned int | 4 |
quint64 | unsigned long long | 8 |
qulonglong | unsigned long long int | 8 |
uchar | unsigned char | 1 |
ushort | unsigned short | 2 |
uint | unsigned int | 4 |
ulong | unsigned long | 8 |
qreal | double | 8 |
qfloat | 2 |
另外,QT还对string类进行了封装,可以使用QString类。
当然,在QT中也可以使用C++本身的int之类的数据类型,但使用这些数据不但符合QT的代码风格,而且更可以保证跨平台通用性,那为什么不入乡随俗呢?
二、函数
<QtGlobal>
中定义了一些常用函数,这些函数多以模板作为传入参数,也返回对应的模板类型
函数 | 功能 |
---|---|
T qAbs(const T &value) | 返回变量value的绝对值 |
const T &qBound(const T &min,const T &value,const T &max) | 返回value限定在min至max范围之内的值 |
bool qFuzzyCompare(double p1,double p2) | 若p1和p2近似相等,返回true |
bool qFuzzyIsNull(double d) | 如果参数d约等于0,返回true |
double qInf() | 返回无穷大的数 |
bool qIsFinite(double d) | 若d是一个有限的数,返回true |
bool qIsInf(double d) | 若d是一个无限大的数,返回true |
bool qIsNaN(double d) | 若d不是一个数,返回true |
const T &qMax(const T &value1,const T &value2) | 返回value1和value2中较大的值 |
const T &qMin(const T &value1,const T &value2) | 返回value1和value2中较小的值 |
qint64 qRound64(double value) | 将value近似为最接近qint64整数 |
int qRound(double value) | 将value近似为最接近的int整数 |
int qrand() | 标准C++中rand()函数的线程安全型版本,返回0至RAND_MAX之间的伪随机数 |
void qrand(uint seed) | 标准C++中srand()函数的线程安全型版本,使用种子seed对伪随机数序列初始化 |
三、容器类
QT的容器类比标准模板库(STL)中的容器类更轻巧、安全和易于使用。
此外,它们还是线程安全的,也就是说它们作为只读容器时可以被多个线程访问。
容器类是基于模板的类,如常用的QList<T>
,T是一个具体类型,可以使int、float等简单类型,也可以是QString、QDate等类,但不能是QObject或任何其子类。T必须是一个可赋值的类型,即T必须提供一个缺省的构造函数,一个可复制的构造函数和一个赋值运算符。
总的来说就是普通数据类型都可以作为模板的具体类型来构建容器,具体QObject类是什么,哪些是它的子类,我们后面再说。
QT的容器类分为顺序容器和关联容器。
(一)顺序容器类
顺序容器类包括QList、QLinkedList、QVector、QStack和QQueue。
- QList
常用函数
函数 | 功能 |
---|---|
insert() | 插入 |
replace() | 替换 |
removeAt() | 删除 |
move() | 移动 |
swap() | 交换 |
append() | 添加 |
prepend() | 添加 |
removeFirst() | 移除 |
removeLast() | 移除 |
isEmpty() | 判断是否为空 |
size() | 返回元素个数 |
QList还提供像数组一样的下标访问方式
例如:
QList<QString> list;
list<<"one"<<"two"<<"three";
QString str1=list[1];
QString str0=list.at(0);
- QLinkedList
QLinkedList<T>
除了不提供基于下标索引的数据项访问外,其他接口函数与QList基本相同 - QVector
QVector支持下标访问,性能比QList更高 - QStack
QStack<T>
是提供类似于队列先入先出(FIFO)操作的容器类。enqueue()
和dequeue()
是主要的操作函数。
例如:
QQueue<int> queue;
queue.enqueue(10);
queue.enqueue(20);
while(!queue.isEmpty())
cout<<queue.dequeue()<<endl;
结果:10,20
(二)关联容器类
关联容器类包括QMap、QMultiMap、QHash、QMultiHash、QSet。
- QSet
例如:
QSet<QString> set;
set<<"dog"<<"cat";
if(!set.contains("mouse")
set<<"mouse";
- QMap
QMap<Key,T>
提供一个字典(关联数组),一个键映射到一个值。
例如:
QMap<QString,int> map;
map["one"]=1;
map["two"]=2;
map.insert("three",3);
map.remove("two");
int num1 =map["one"];
int num2 =map.value("two");
如果在映射表中没有找到指定的键,会返回一个缺省的构造值。使用value()函数查找时,还可以指定一个缺省值
int num = map.value("my_num",10);
- QMultiMap
QMultiMap是QMap的子类,是用于处理多值映射的便利类。QMap正常情况下不允许多值映射,除非使用QMap::insertMulti()添加键值对。
QMultiMap::insert()等效于QMap::insertMulti(),QMultiMap::replace()等效于QMap::insert()
例如:
QMultiMap<QString,int> map1,map2,map3;
map1.insert("num",100);
map1.insert("num",200);
map2.insert("num",300);
map3=map1+map2; //map3.size()==3
QMultiMap不提供"[ ]"操作符,使用value()函数访问最新插入的键的单个值。如果要获取一个键对应的所有值,使用values()函数,返回值是QList<T>
类型。
例如:
QList<int> values =map.values("num");
for(int i=0;i<values.size();i++)
cout<<values.at(i)<<endl;
- QHash
QHash<Key,T>
和QMap功能和用法相似,但QMap的键必须提供<
运算符,QHash的键必须提供==
运算符和一个名称为qHash()的全局散列函数。 - QMultiHash
与QMultiMap相似
四、容器类的迭代
QT有两种迭代器类:Java类型的迭代器和STL类型的迭代器。
Java类型的迭代器更易于使用,且提供一些高级功能,而STL类型的迭代器效率更高。
(一)Java类型的迭代器
容器类 | 只读迭代器 | 读写迭代器 |
---|---|---|
QList<T> ,QQueue<T> | QListIterator<T> | QMutableListIterator<T> |
QLinkedList<T> | QLinkedListIterator<T> | QMutableLinkedListeIterator<T> |
QVevtor<T> ,QStack<T> | QVectorIterator<T> | QMutableVectorIterator<T> |
QSet<T> | QSetIterator<T> | QSetIterator<T> |
QMap<Key,T> ,QMultiMap<Key,T> | QMapIterator<Key,T> | QMutableMapIterator<Key,T> |
QHash<Key,T> ,QMultiHash<Key,T> | QHashIterator<Key,T> | QMutableHashIterator<Key,T> |
- 顺序容器类的迭代器使用
Java类型迭代器的指针不是指向一个数据项,而是在数据项之间。
以QListIterator<T>
为例说明顺序容器类的迭代器常用方法
函数名 | 功能 |
---|---|
void toFront() | 迭代器移动到列表的最前面(第一个数据项之前) |
void toBack() | 迭代器移动到列表的最后面(最后一个数据项之后) |
bool hasNext() | 如果迭代器不是位于列表最后位置,返回true |
const T &next() | 返回下一个数据项,并且迭代器后移一个位置 |
const T &peekNext() | 返回下一个数据项,但是不移动迭代器位置 |
bool hasPrevious() | 如果迭代器不是位于列表的最前面,返回true |
const T &previous() | 返回前一个数据项,并且迭代器前移一个位置 |
const T &peekPrevious() | 返回前一个数据项,但是不已的迭代器指针 |
例如:
QList<int> list;
list<<1<<2<<3<<4<<5;
QMutableListIterator<int> i(list);
while(i.hasNext()){
if(i.next()%2!=0)
i.remove();
}
remove()函数移除next()函数刚刚跳过的一个数据项,不会使迭代器失效。
setValue()函数可以改变数据项的值。
2. 关联容器类的迭代器使用
关联容器类迭代器具有和上表一样的函数,主要是增加了key()和value()函数用于获取刚刚跳过的数据项的键和值。
在多值容器类里遍历,可以使用findNext()或findPrevious()查找下一个或上一个值,例如:
while(i.findNext("USA"))
i.remove();
(二)STL类型迭代器
与Java类型迭代器不同,STL类型迭代器直接指向数据项。
- 顺序容器类的迭代器
容器类 | 只读迭代器 | 读写迭代器 |
---|---|---|
QList<T> ,QQueue<T> | QList<T>::const_iterator | QList<T>::iterator |
QLinkedList<T> | QLinkedList<T>::const_iterator | QLinkedList<T>::iterator |
QVevtor<T> ,QStack<T> | QVector<T>::const_iterator | QVector<T>::iterator |
QSet<T> | QSet<T>::const_iterator | QSet<T>::iterator |
QMap<Key,T> ,QMultiMap<Key,T> | QMap<Key,T>::const_iterator | QMap<Key,T>::iterator |
QHash<Key,T> ,QMultiHash<Key,T> | QHash<Key,T>::const_iterator | QHash<Key,T>::iterator |
例如:
QList<QString> list;
list <<"A"<<"B"<<"C"<<"D";
QList<QString>::const_iterator i;
for(i=list.constBegin();i!=list.constEnd();i++)
qDebug()<<*i;
constBegin()和constEnd()用于只读迭代器,表示其实和结束位置。
- 关联容器类的迭代器
如果想返回键,使用key()函数,对应的,用value()函数返回一个项的值。 - QT很多函数返回值为QList或QStringList,但因为QT使用了隐式共享,所以并不费事。隐式共享简单的就是只读的时候共享内存,修改的时候再拷贝一份新的。
因为有隐式共享,所以当有一个迭代器在操作容器变量时,不要复制这个容器变量。
五、QT宏定义之foreach
QT有很多宏定义,但这里只介绍这个foreach。
foreach(变量,容器)
例如:
QLinkedList<QString> list;
...
QString str;
foreach(str,list)
qDebug()<<str;
foreach也可以使用大括号,使语句更复杂
对于QMap和QHash,foreach会自动访问键值对里得值,例如:
foreach(str,map.keys())
qDebug()<<str<<":"<<map.value(str);
对于多值映射,可以使用双重foreach
请注意:foreach不能修改原来容器中的数据项
六、总结
好啦,看到这里希望你能学会这些基础知识,这些基础知识就能满足很多开发需求了,你已经不再是一个QT小白了。
我辛苦的搬运了一天书上的内容,才有了这篇文章,哈哈!当初学QT的时候我都没那么认真,不过这样做还是很值得的,现在为了写博客也为了兴趣想好好学一学,很有收获了。