Qt学习笔记(3):模板库
1.Qt的字符串类(QString)
Qt提供了QString类,他保存了16位Unicode值,提供了丰富的操作、查询和转换等函数。该类还进行了使用隐式共享、高效的内存分配策略等多方面的优化。
使用:
//跟string类类似
QString str = "Hello,";
QString str += "World!";
QString::append()具有与”+=“操作同样的功能。例如:
QString str1 = "Hello,";
QString str2 = "World!";
str1.append(str2);
str1.append("Hahaha!!");
组合字符串的另一个函数是QString::sprintf(),该函数支持的格式定义符和C++库中的函数sprintf()定义的一样。例如:
QString str;
str.sprintf("%s","Hello!");//str = "Hello";
str.sprintf("%s %s","Hello,""World!");//str = "Hello,World!";
QString还提供了另一种方便的字符串组合方式,使用QString::arg()函数。此函数的重载可以处理很多的数据类型。此外,一些重载具有额外的参数对字段的宽度,数字基数或者浮点数精度进行控制。通常,相对于函数QString::sprintf,函数QString::arg()是一个比较好的解决方案。因为她类型安全,完全支持Unicode,并且允许修改“%n”参数的顺序。例如:
QString str;
str = QString = ("%1 was born in %2.").arg("John").arg("1988");
//str = John was born in 1988.
其中,%1被替换为John,%2被替换为1988.
QString还提供了一些其他的组合字符串的方法:
1.insert()函数:在原字符串特定的位置插入另一个字符串。
2.prepend()函数:在原字符串的开头插入另一个字符床。
3.replace()函数:用指定的字符串代替原字符串中的某些字符。
trimmed()函数:移除字符串两端的空白字符。(包括’\n’,’\r’,’ ‘,’\t’等)
simplified()函数:移除字符串两端的空白字符,并用单个空格字符代替。
QString还可以用重载过的>= .< , <= , ==直接比较两个字符串。
localeAwareCompare(const QString &,const QString &):静态函数,比较前后两个字符串,前面的小返回负整数,等于返回0,大于返回正整数。该函数的比较是基于本地(local)字符集的,而且是平台相关的。通常,该函数用于显示一个有序的字符串列表。
compare(const QString&,const QString &,QT::CaseSensitivity);该函数可以指定是否进行大小写的比较。返回类似于localeAwareCompare()函数。
字符串转换的方法有:
1.toDouble();
2.toInt();
3.toLong();
4.toFloat();
5.toAscii();等等。
例如:
QString str = "123";
bool ok;
int hex = str.toInt(&ok,16);//将字符串转化为整形数值。
//其中第一个参数是bool类型,转换成功返回true,失败返回false;
容器类
Qt的大多数数据类型都可以存放到容器中,但是QObject及其他的子类(QWidget和Qdialog等)是不能够存储在容器中的。例如:
QList<QToolBar> list;//行不通
但是,可以使用QObject及其子类的指针:
QList<QToolBar *> list;
容器类也允许使用嵌套:
QHash< QString , QList<double> >
其中,QHash的键类型是QString,值的类型是QList<double>.注意,在后边两个 ‘>’ 之间的空格是必须的,否则C++可能会把它当成一个>>看待
Qt的容器类为遍历其中的内容提供了以下两种方法:
1.Java风格的迭代器
2.STL风格的迭代器,能够同Qt和STL的通用算法一起使用,并且在效率上也略胜一筹。
下面,我们讲一下QList类:
QList<T>是迄今为止最常用的容器类,她存储给定数据类型T的一列数据。继承自QList类的子类有QItemSelection,QQueue,QSignalSpy以及QStringList和QTextEventList.
QList不仅提供了可以在列表进行追加的QList::append()和QList::prepend()函数。
还提供了在列表中间完成插入操作的QList::insert的函数。
QList<T>维护了一个指针数组,该数组存储的指针指向QList<T>存储的列表项的内容。因此,QList<T>提供了基于下标的快速访问。
对于不同的数据类型,QList<T>存储的方式也不同。
1.对于T是一个指针类型或只有指针大小的基本类型,采用数组的方式存储。
2.对于T是一个存储对象的指针,则该指针指向实际存储的对象。
下面举个例子:
#include <QDebug>
int mian(int argc,char **argv)
{
QList<QString> list;//声明了一个QList<QString>栈对象
{
QString str("This is a test string");
list << str;//通过操作运算符“<<”将一个QString字符串存储到list中
}//花括弧的作用域表明,此时,QList<T>保存了对象的一个复制
qDebug()<<list[0]<<"How are you!";
return 0;
QLinkedList类
QLinkedList<T>是一个链式列表,它以非连续的内存块保存数据。
QLinkedList<T>不能使用下标,只能用迭代器访问他的数据项。与QList相比,当对一个很大的列表进行插入操作时,QLinkedList具有更高的效率。
QVector类
QVector<T>在相邻的内存中存储给定数据类型T的一组数组,在一个QVector的前部或者中间位置进行插入操作的速度是很慢的,这是因为这样的操作将导致内存中的大量数据移动。
QVector可以使用下标访问数据项,也可以使用迭代器访问数据项,继承QVector的子类有QPolyon、QPolygonF和QStack类。
Java风格迭代器:
容器类 只读迭代器 读写迭代器(记得右拉)
QList<T>,QQueue<T> QListIterator<T> QMutableListIterator<T>
QLinkedList<T> QLinkedListIterator<T> QMutableVectorIterator<T>
QVector<T>,QStack QVectorIterator<T> QMutableVectorIterator<T>
Java风格迭代器的迭代点位于列表项的中间,而不是直接指向某个列表项,因此他的迭代点或在一个列表项前,或在两个列表项之间或在一个列表项之后。
下面以QList为例,介绍Java风格的迭代器的两种用法QLinkedList和QVector具有和QList类相同的遍历接口。
#include <QCoreApplication>
#include <QDebug>//包含了QList的头文件
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QList<int> list;
list << 1 << 2 << 3 << 4;
//以该list为参数初始化一个QListIterator对象,此时迭代点在1前面。
QListIterator<int> i(list);
for(; i.hasNext();)//.hasNext检查当前迭代器后是否还有列表项,有则执行循环
{
//next将会跳过下一个列表项,即位于第一个列表项和第二个之间,
//并返回它跳过的列表项的内容
qDebug() <<i.next();
}
return a.exec();
}
输出结果为:(版本:Qt5.8.0)
1
2
3
4
以上讲述了对QListIterator<T>向后遍历的函数,而对列表遍历的函数还有如下几种:
QListIterator<T>::toBack();//将迭代点移动到最后一个列表项的后边。
QListIterator<T>::hasPrevious();//检查当前的迭代点之前是否具有列表项
QListIterator<T>::previous();//返回前一个列表项的内容并将迭代点移动到前一个列表项之前。
QListIterator<T>::toFront();//移动迭代点到列表的前端
QListIterator<T>::peekNext();//返回下一个列表项,但不移动迭代点。
QListIterator<T>::peekPreviour();//返回前一个但不移动
QListIterator<T>::findNext();//从当前迭代点向后查找指定的列表项,如果找到
返回true,此时迭代点位于匹配到的列表项后边,找不到返回false,位于列表的后端。
QListIterator是只读迭代器,他不能完成列表项的插入和删除,读写迭代器QMutableListIterator<T>才可以,他除了有基本的遍历外,还有insert()插入数据函数和remove删除数据功能和修改数据函数。
具体代码如下:
#include <QCoreApplication>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QList<int> list;
QMutableListIterator<int> i(list);
for(int j = 0; j < 10 ;j ++)
i.insert(j);
for(i.toFront();i.hasNext();)
qDebug()<<i.next();
for(i.toBack();i.hasPrevious();)
{
if(i.previous()%2 == 0)
i.remove();
else
i.setValue(i.peekNext() * 10);
}
for(i.toFront();i.hasNext();)
qDebug()<<i.next();
return a.exec();
}
输出结果是:
0
1
2
3
4
5
6
7
8
9
10
30
50
70
90
接下来,我们说说STL风格迭代器。
STL风格迭代器的API是建立在指针操作基础上的,例如“++”操作运算符移动迭代器到下一个项item,而“*”操作运算符返回迭代器指向的项。
不同于Java迭代器的是,STL风格的迭代器的迭代点直接指向列表项。
容器类 只读迭代器 读写迭代器
QList<T>,QQueue<T> QList<T>::const_iterator QList<T>::iterator
QLinkedList<T> QLinkedList::const_iterator QLinkedList<T>::iterator
QVector<T>,QStack<T> QVector<T>::const_iterator QVector<T>::iterator
使用STL风格的迭代器,具体代码如下:
#include <QCoreApplication>
#include <QDebug>
int main(int argc,char **argv)
{
QCoreApplication a(argc,argv);
QList<int> list;//初始化一个空的QList<int>列表
for(int j = 0;j < 10; j++)
{
//插入是个整数,该函数第一个参数是QList<T>::itreator类型,
//第二个是想要插入的值。
list.insert(list.end(),j);
}
QList<int>::iterator i;//初始化一个QList<int>::itrerator的读写迭代器
for(i = list.begin();i!=list.end();i++)
{
qDebug()<<(*i);
*i = (*i) * 10;
}
QList<int>::const_iterator ci;//初始化一个QList<int>::const_iterator的只读迭代器
for(ci = list.constBegin();ci != list.constEnd();++ci)
qDebug()<<*ci;//在控制台输出列表的所有值
return a.exec();
}
QMap类
QMap<Key,T>提供了Key类型的键到T类型的值的映射
通常,一个键对应一个值,并且按照键Key的顺序存储数据,为了能够支持一键多值的情况,QMap提供了QMap<Key,T>::insertMulti()和QMap<Key,T>::values()函数,存储一键多值的数据时,也可以使用QMultiMap<Key,T>容器,它继承自QMap类。
QHash类
QHash<Key,T>具有与QMap几乎完全相同的API,QHash维护着一张哈西表(Hash Table),哈希表的大小与QHash的数据项的数目相适应。
QHash以任意的顺序阻止它的数据,当存储数据的顺序无关紧要,建议使用QHash作为存放数据的容器,QHash也可以存储一键多值形式的数据,它的子类QMultiHash<Key,T>实现了一键多值的语义。
Java风格的迭代器
容器类 只读迭代器类 读写迭代器类
QMap<Key,T>,QMultiMap<Key,T> QMapIterator<Key,T> QMutableMapIterator<Key,T>
QHash<Key,T>,QMultiMap<Key,T> QHashIterator<Key,T> QMutableHashIterator<Key,T>
接下来示范一下在QMap中的插入,遍历和修改。
#include <QCoreApplication>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QMap<QString,QString> map;//创建一个QMap栈对象
map.insert("beijing","111");
map.insert("shanghai","021");
map.insert("nanjing","025");
QMapIterator<QString,QString> i(map);//创建一个只读迭代器
for(;i.hasNext();)//判断迭代器内列表是否读完
//下面语句是因为输出键的时候,不需要把迭代点移动到下一位,输出值需要
qDebug()<<""<<i.key()<<" "<<i.next().value();
QMutableMapIterator<QString,QString> mi(map);//创建一个读写迭代器
if(mi.findNext("111"))//查找对应的值,注意:这个不是键
mi.setValue("010");//修改数据
QMapIterator<QString,QString> modi(map);
qDebug()<<" ";
for(;modi.hasNext();)
qDebug()<<" "<<modi.key()<<" "<<modi.next().value();
return a.exec();
}
注意,迭代器的键还有数据数据类型必须键入,而且必须与接受的那个容器类的键和数据类型相同。比如:不可以使用
QMapIterator i(map);//迭代器没有说明它的Key和T的类型。
输出结果:
“beijing” “111”
“nanjing” “025”
“shanghai” “021”
“beijing” “010”
“nanjing” “025”
“shanghai” “021”
下面说说它的STL风格迭代器
容器类 只读迭代器 读写迭代器
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
代码:
#include <QCoreApplication>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QMap<QString,QString> map;
map.insert("beijing","111");
map.insert("shanghai","021");
map.insert("nanjing","025");
QMap<QString,QString>::const_iterator i;
for(i = map.begin();i != map.constEnd();i++)//++就是往后遍历
qDebug()<<" "<<i.key()<<" "<<i.value();
QMap<QString,QString>::iterator mi;
mi = map.find("beijing");//这里查找的是键
if(mi != map.end())
mi.value() = "010";//将寻到的键的位置的数据变成010;
QMap<QString,QString>::const_iterator modi;
qDebug()<<" ";
for(modi = map.constBegin();modi != map.constEnd();modi++)
qDebug()<<" "<<modi.key()<<" "<<modi.value();
return a.exec();
}
输出结果:
“beijng” “111”
“nanjing” “025”
“shanghai” “021”
“beijng” “010”
“nanjing” “025”
“shanghai” “021”
QVariant类
这个类类似与C++的联合,它不仅能够保存很多Qt类型的值,包括QColor、QBrush、QFont、QPen、QRect、QString和QSize等,也能够存放Qt的容器类型的值,Qt的很多功能都是建立在QVariant基础上的,如Qt的对象的属性及其数据库功能等。
下面介绍QVariant类的用法。
新建Qt Widgets Application,项目名为“myVariant",基类选择”QWidget",类名保持"Widget"不变,取消选择“创建界面”复选框,建好项目后,在widget.cpp文件中写入以下代码:
#include "widget.h"
#include <QDebug>
#include <QVariant>
#include <QColor>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
QVariant v(709);//声明一个QVariant变量v,并初始化为一个整数,此时,QVariant变量v包含了一个整数变量。
qDebug()<<v.toInt();//调用toInt函数将内容转化为整数输出。
QVariant w("How are you?");
qDebug()<<w.toString();
QMap<QString,QVariant> map;
map.insert("int",709);//这里两种表达都是可以的
map.insert("double",709.709);
map["string"] = "How are you?";//这是第二种表达
map["color"] = QColor(255,0,0);
//下面四句的输出格式可以看输出结果
qDebug()<<map["int"]<<map["int"].toInt();
qDebug()<<map["double"]<<map["double"].toDouble();
qDebug()<<map["string"]<<map["string"].toString();
//重点讲这句,在QVariant变量中保存了一个QColor对象,并使用模版
//QVariant::value()还原为QColor(),然后输出。由于QVariant是
//QtCore模块的类,所以它没有为QtGui模块中的数据类型(如:QColor、
//QImage、QPixmap等)提供转换函数,因此需要使用QVariant::value()函数
//或者QVariantValue()模块函数。
qDebug()<<map["color"]<<map["color"].value<QColor>();
QStringList sl;
sl<<"A"<<"B"<<"C"<<"D";
QVariant slv(sl);
//QVariant::type()函数返回存储在QVariant变量中的值的数据类型。QVariant::
//StringList是Qt定义的一个Variant::type枚举类型的变量。其他常用枚举请看下边表格
if(slv.type() == QVariant::StringList)
{
QStringList list = slv.toStringList();
for(int i = 0;i < list.size();i++)
qDebug()<<list.at(i);
}
}
Widget::~Widget()
{
}
输出结果:
709
“How are you?”
QVariant(int, 709) 709
QVariant(double, 709.709) 709.709
QVariant(QString, “How are you?”) “How are you?”
QVariant(QColor, QColor(ARGB 1, 1, 0, 0)) QColor(ARGB 1, 1, 0, 0)
“A”
“B”
“C”
“D”
Qt的常用的QVariant::type枚举类型变量