qt模版库
字符串类
相比于C++提供的两种字符串:C风格的char 字符串和字符串类string,qt提供的字符串类QString的功能更为强大。
QString类保存16位Unicode值,提供了丰富的操作、查询和转换等函数。该类还进行使用了隐式共享、高效的内存分配策略等多方面的优化。
操作字符串
- QString提供了一个二元的“+”操作符用于组合两个字符串,并且提供了一个“+=”操作符用于将一个字符串追加到另一个字符串的末尾。
QString str1 = "Welcome";
str1 = str1 + "to you !";
QString str2 = "hello, ";
str2 += "World! ";
- QString::append()函数具有与“+=”操作符同样的功能,实现在一个字符串的末尾追加另一个字符串,例如:
QString str1 = "Welcome ";
QString str2 = "to ";
str1.append(str2); //str1 = "Welcome to"
str1.append("you! "); //str1 = "Welcome to you! "
- 组合字符串的另一个函数是QString::sprintf(),此函数支持的格式定义符和C++库中的函数sprintf()定义是一样的,例如:
QString str;
str.sprintf("%s", "Welcome "); // str = "Wlecome "
str.sprintf("%s", " to you! "); //str = " to you! "
str.sprintf("%s %s", "Welcome ", "to you! "); // str = "Welcome to you! "
- Qt还提供了另一种方便的字符串组合方式,使用QString::arg()函数,此函数的重载可以处理很多数据类型。此外,一些重载具有额外的参数对字段的宽度、数字基数或者浮点数精度进行控制。通常,相对于函数QString::sprintf(),函数QString::arg()是一个比较好的解决方案,因为它类型安全,完全支持Unicode,并且允许改变“%n”参数的顺序,例如:
QString str;
Str = QString("%1 was born in %2.").arg("John").arg(1998);//Str = "John was born in 1998"
其中,%1被替换成了“John”,%2被替换成了 “1998”。
- QString也提供了一些其他组合字符串的方法,包括以下方式:
- insert()函数:在源字符串特定位置插入另一个字符串。
- prepend()函数:在源字符串开头插入另一个字符串。
- replace()函数:用指定的字符串代替源字符串中的某些字符。
- 很多时候,去掉一个字符串两端的空白(空白字符包括回车符“\n”、换行字符“\r”,制表符“\t”和空格字符“ ”)非常有用。
- QString::trimmed()函数:移除字符串两端的空白字符。
- QString::simplified()函数:移除字符串两端的空白字符,使用单个空格字符 “ ”代替字符串中出现的空白字符。
QString str = " Welcome \t to \n you! ";
str = str.trimmed(); // str = "Welcome \t to \n you!"
str = str.simplified(); //str = "Welcome to you!"
查询字符串数据
- 函数QString::startsWith() 判断一个字符串是否以某个字符串开头。此函数具有两个参数,一个参数指定了一个字符串,第二个参数指定了是否大小写敏感(默认情况是大小写敏感的)。
QString str = "Welcome to you!";
str.startWith("Welcome", Qt::CaseSensitive); //返回true
str.startWith("to you", Qt::CaseSensitive); //返回false
- 函数QString::endsWith()类似于QString::startsWith(),此函数判断一个字符串是否以某个字符串结尾。
- 必将两个字符串也是经常使用到的功能,QString提供了以下几种比较手段:
- operator<(const QString &):比较一个字符串是否小于另一个字符串,如果是返回true。
- operator<=(const QString &):比较一个字符串是否小于等于另一个字符串,如果是返回true。
- operator==(const QString &):比较一个字符串是否等于另一个字符串,如果是返回true。
- operator>=(const QString &):比较一个字符串是否大于等于另一个字符串,如果是返回true。
- localeAwareCompare(const QString &, const QString &):静态函数,比较前后两个字符串,如果前面字符串小于后面的字符串,则返回负整数;如果等于返回0;如果大于则返回正整数。(该函数的比较是基于本地字符集的,与平台相关)
- compare(const QString &, const QString &, Qt::CaseSensitivity):该函数可以指定是否进行大小写的比较,而大小写的比较是完全基于Unicode编码值的。
字符串的转换
QString类提供了丰富的转换函数,可以将字符串转换为数值类型或者其他的字符编码集。
- QString::toInt()函数将字符串转换为整型数值,类似还有toDouble()、toFloat()、toLong()、toLongLong()等等。
QString str = "125";
bool ok;
int hex = str.toInt(&ok, 16);//ok = true, hex = 293
int dev = str.toInt(&ok, 10);//ok = true, dev = 125
- QString提供的字符编码集的转换函数会返回一个const char *类型版本的QByteArray,即构造函数QByteArray(const char *)构造的QByteArray对象。这个类具有一个字节数组,它既可以存储原始字节(raw bytes),也可以存储传统的以“\0”结尾的8位字符串。在Qt中,使用QByteArray比使用const char *更方便,且QByteArray也支持隐式共享,转换函数有以下几种:
- toAscii():返回一个ASCII编码的8位字符串。
- toLatin1():返回一个Latin-1(ISO8859-1)编码的8位字符串。
- toUtf8():返回一个UTF-8编码的8位字符串。
- toLocal8Bit():返回一个系统本地(locale)编码的8位字符串。
QString str = "Welcome to you!";
QByteArray ba = str.toAscii();
qDebug() << ba;
ba.append("Hello, World!");
qDebug() << ba.data();
容器类
qt提供了一组统一的基于模版的容器类。对比C++的标准模版库中的容器类,Qt的这些容器更轻量、更安全并且更容易使用。此外,Qt的容器类在速度、内存消耗和内联(inline)代码等方面进行了优化。
存储在Qt容器中的数据必须是可赋值的数据类型,也就是说,这种数据类型必须提供一个默认的构造函数、一个复制构造函数和一个赋值操作运算符。
这样的数据类型包含了通常使用的大多数数据类型,包括基本数据类型(如int、double等)和Qt的一些数据类型(如QString、QData、QTime等)。不过,Qt的QObject及其子类是不能干存储在容器中的(可以存储类指针)。
QList<QToolBar> list; //error
QList<QToolBar*> list; //success
Qt的容器类是可以嵌套的。例如:
QHash<QString, QList<double> > hash;
- 其中,QHash的键类型为QString,值类型为QList。注意,在最后两个“>”符号之间要保留一个空格,否则编译器会错认成“>>”操作符。
Qt的容器类为遍历其中内容提供了以下两种方法:
- java风格迭代器(java-style iterators)
- STL风格的迭代器(STL-style iterators),能够同Qt和STL的通用算法一起使用,并且在效率上更胜一筹。
QList类、QLinkedList类和QVector类
经常使用的Qt容器类有QList、QLinkedList和QVector等。在开发一个较高性能需求的应用程序时,我们需要了解这些容器类的运行效率。下面列出了这几个类的时间复杂度比较:
容器类 | 查找 | 插入 | 头部添加 | 尾部添加 |
---|---|---|---|---|
QList | O(1) | O(n) | Amort O(1) | Amort O(1) |
QLinkedList | O(n) | O(1) | O(1) | O(1) |
QVector | O(1) | O(n) | O(n) | Amort O(1) |
QList类
QList是最常用到的容器类,它存储给定的数据类型T的一列数值。继承自QList类的子类有QItemSelection、QQueue、QSignalSpy及QStringList和QTestEventList。
QList不仅提供了可以在列表中进行追加的 QList::append() 和 QList::prepend() 函数,还提供了可以在列表中间完成插入操作的函数 QList::inseert() ,相对于任何其他的Qt容器类,为了可执行代码尽可能少,QList被高度优化。
QList维护了一个指针数组,该数组存储的指针指向QList 存储的列表项的内容。因此,QList 提供了基于下标的快速访问。
对于不同的数据类型,QList 采取不同的存储策略,存储策略有以下几种:
- 如果T是一个指针类型或指针大小的基本类型(即所占字节数和基本类型所占字节数相同),QList会将数值直接存储在它的数组中。
- 如果QList存储对象的指针,则该指针指向实际存储的对象。
例如:
#include <QDebug>
int main()
{
//声明一个QList<QString>栈对象
QList<QString> list;
{
QString str("This is a test string");
list << str;//通过“<<”运算符将QString字符串存储到该列表中
}//使用花括号进行作用域表明,此时QList<T>保存了对象的复制。
qDebug() << list[0] << "How are you! ";
return 0;
}
QLinkedList类
QLinkedList是一个链式列表,它以非连续的内存块存储数据。
QLinkedList 不能使用下标,只能使用迭代器访问它的数据。与QList相比,当对一个很大的列表项进行插入操作时,QLinkedList具有更高的效率。
QVector类
QVector在相邻的内存中存储给定数据类型T的数值。在一个QVector的前部或者中间位置进行插入操作的速度是很慢的,这是因为这样的操作将导致内存中的大量数据被移动,这是有QVector的存储数据方式决定的。
QVector既可以使用下标访问数据,也可以使用迭代器访问数据。集成自QVector类的子类有QPolygon、QPolygonF和QStack。
Java风格迭代器遍历容器
Java风格的迭代器同STL风格的迭代器相比,使用起来更简单方便,不过这也是以轻微的性能损耗为代价的。对于每一个容器类,Qt都提供了两种类型的Java风格迭代器数据类型,即只读访问和读写访问,其分类如下:
容器类 | 只读迭代器类 | 读写迭代器类 |
---|---|---|
QList, QQueue | QListIterator | QMutableListIterator |
QLinkedList | QLinkedListIterator | QMutableLinkedListIterator |
QVector, QStack | QVectorIterator | QMutableVectorIterator |
Java风格迭代器的迭代点(Java-style iterators point)位于列表项的中间,而不是直接指向某个列表项。因此,它的迭代点或者在第一个列表项的前面,或者在两个列表项之间,或者在最后一个列表项之后。
下面以QList为例,介绍Java风格的两种迭代器的用法。QLinkedList和QVector具有和QList相同的遍历接口。
- 示例
#include <QCoreApplication>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QList<int> list;
list << 1 << 2 << 3 << 4 << 5;
QListIterator<int> i(list);
for(; i.hasNext();)
qDebug() << i.next();
return a.exec();
}
上面使用的 i.hasNext()是对列表进行向后遍历的函数,而对列表进行向前遍历的函数有以下几种:
QListIterator<T>::toBack() :将迭代点移动到最后一个列表项的后面。
QListIterator<T>::hasPrevious() :检查当前迭代点之前是否具有列表项。
QListIterator<T>::previous() :返回前一个列表项的内容并将迭代点移动到前一个列表项之前。
此外:
toFront():移动迭代点到列表的前端(第一个列表项前面)
peekNext():返回下一个列表项,但不移动迭代点。
peekPrevious():返回前一个列表项,但不移动迭代点。
findNext():从当前迭代点开始向后查找指定的列表项,如果找到返回true,否则返回false。
findPrevious():与findNext()类似,不同的是它的方向是向前的,查找操作完成后的迭代点在匹配项的前面或整个列表的前端。
实现QList读写遍历方法:
#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.hasHext(); )
qDebug() << i.next();
for(i.toBack(); i.hasPrevious(); )
{
if(i.previous() % 2 == 0)
i.remove();
else
i.setValue(i.peekNext() * 10);
}
for(i.toPront(); i.hasNext(); )
qDebug() << i.next();
return a.exec();
}
STL风格迭代器遍历容器
对于每一个容器类,Qt都提供了两种类型的STL风格迭代器数据类型:
- 提供只读访问
- 提供读写访问
由于只读访问类型的迭代器的运行速度要比读写访问迭代器的运行速度快,所以应尽可能地使用只读类型的迭代器。STL风格迭代器的两种分类如下:
容器类 | 只读迭代器 | 读写迭代器 |
---|---|---|
QList,QQueue | QList::const_iterator | QList::iterator |
QLinkedList | QLinkedList::const_iterator | QLinkedList::iterator |
QVector, QStack | QVector::const_iterator | QVector::iterator |
STL风格迭代器的API是建立在指针操作的基础上的。例如“++”操作运算符移动迭代器到下一个选项(item),而“ * ”操作符返回迭代器指向的项。
示例:
#include <QCoreApplication>
#include <QDebug>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QList<int> list;
for(int j = 0; j< 10; j++)
list.insert(list.end(), j);
QList<int>::iterator i;
for(i = list.begin(); i != list.end(); ++i)
{
qDebug() << (*i);
*i = (*i) * 10;
}
QList<int>::const_iterator ci;
for(ci = list.constBegin(); ci != list.constEnd(); ++ci)
qDebug() << *ci;
return a.exec();
}
QMap类和QHash类
QMap类和QHash类具有非常类似的功能,它们的差别仅在于:
- QHash具有比QMap更快的查找速度;
- QHash以任意的顺序存储数据向,而QMap总是按照键Key的顺序存储数据。
- QHash的键类型Key必须提供operator==() 和一个全局的qHash(Key) 函数,而QMap的键类型Key编写提供operator<()函数。
二者的时间复杂度比较如下:
容器类 | 键查找 | – | 插入 | – |
---|---|---|---|---|
平均值 | 最坏情况 | 平均情况 | 最坏情况 | |
QMap | O(log n) | O(log n) | O(log n) | O(log n) |
QHash | Amort.O(1) | O(n) | Amort.O(1) | O(n) |
- 注:Amort.O(1)表示,如果仅完成一次操作,则可能会有O(n)行为;如果多次操作(如n次操作),则平均结果是O(1)。
QMap类
QMap<Key,T>提供了一个从类型为Key的键到类型为T的 值的映射。
通常,QMap存储的数据形式是一个键对应一个值,并且安装键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风格迭代器遍历容器
对于每一个容器类,Qt都提供了两种类型的Java风格迭代器数据类型:
- 提供只读访问;
- 提供读写访问;
容器类 | 只读迭代器类 | 读写迭代器类 |
---|---|---|
QMap<Key,T> , QMultiMap<Key,T> | QMapIterator<Key,T> | QMutableMapIterator<Key,T> |
QHash<Key,T>, QMultiHash<Key,T> | QHashIterator<Key,T> | QMutableHashIterator<Ket,T> |
示例代码:
#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");
//创建一个只读迭代器
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();
}
STL风格迭代器遍历容器
对于每一个容器类,Qt都提供了两种类型的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.constBegin(); i != map.constEnd(); ++i)
qDebug() << " " <<i.key() <<" " <<i.value();
//创建一个读写迭代器
QMap<QString,QString>::iterator mi;
mi = map.find("beijing");
if(mi != mi.end())
mi.value() = "010";
qDebug() << "修改后:";
QMap<QString,QString>::const_iterator modi;
for(modi = map.constBegin(); modi != map.constEnd(); ++modi)
qDebug() << " " <<modi.key() <<" " <<modi.value();
return a.exec();
}
QVariant类
QVariant类类似于C++的联合(union)数据类型,它不仅能够保存很多Qt类型的值,包括QColor、QBrush、QFont、QPen、QRect、QString和QSize等,也能够存放Qt的容器类型的值。Qt的很多功能都是建立在QVarient基础上的,比如Qt的对象属性及数据库功能等。
示例:
新建Qt Widget项目,取消选择“创建界面”复选框,建好项目后在widget.cpp文件中编写以下代码:
#include "widget.h"
#include <QDebug>
#include <QVariant>
#include <QColor>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
QVariant v(709);
qDebug() <<v.toInt();
QVariant w("How are you! ");
qDebug() << w.toString();
QMap<QString, QVariant> map;
map["int"] = 709; //输入整形
map["double"] = 709.709; //输入浮点型
map["string"] = "How are you!"; //输入字符串
map["color"] = QColor(255, 0, 0); //输入QColor类型的值
//调用相应的转换函数输出
qDebug() << map["int"] <<map["int"].toInt();
qDebug() << map["double"] << map["double"].toDouble();
qDebug() << map["string"] << map["string"].toString();
qDebug() << map["color"] << map["color"].value<QColor>();
QStringList sl; //创建一个字符串列表
sl << "A" << "B" << "C" << "D";
QVariant slv(sl); //将该列表保存到一个QVariant变量中
if(slv.type() == QVariant::StringList)
{
QStringList list = slv.toStringList();
for(int i = 0; i < list.size(); ++i)
{
qDebug() << list.at(i); //输出列表内容
}
}
}
Widget::~Widget()
{
}
示例说明:
- QVariant v(709):声明一个QVariant变量v,并且初始化为一个整数,此时变量v中包含一个整数变量。
- qDebug() << v.toInt();调用QVariant::toInt()函数将变量中包含的内容转换成整数并输出。
- if(slv.type() == QVariant::StringList):QVariant::type()函数返回存储在QVariant变量中的值的数据类型。QVariant::StringList是Qt定义的一个QVariant::type枚举类型的变量,其他常用的枚举类型变量如下:
变量 | 对应的类型 | 变量 | 对应的类型 |
---|---|---|---|
QVariant::Invalid | 无效类型 | QVariant::Time | QTime |
QVariant::Region | QRegion | QVariant::Line | QLine |
QVariant::Bitmap | QBitmap | QVariant::Palette | QPalette |
QVariant::Bool | bool | QVariant::List | QList |
QVariant::QBrush | QBrush | QVariant::SizePolicy | QSizePolicy |
QVariant::Szie | QSize | QVariant::String | QString |
QVariant::Char | QChar | QVariant::Map | QMap |
QVariant::Color | QColor | QVariant::StringList | QStringList |
QVariant::Cursor | Qcursor | QVariant::Point | QPoint |
QVariant::Date | QDate | QVariant::Pen | QPen |
QVariant::DateTime | QDateTime | QVariant::Pixmap | QPixmap |
QVariant::Double | double | QVariant::Rect | QRect |
QVariant::Font | QFont | QVariant::Image | QImage |
QVariant::Icon | QIcon | QVariant::UserType | 用户自定义类型 |
算法及正则表达式
首先介绍Qt的 和 模块中几种常用算法,然后再介绍基本的正则表达式。
常用算法
#include "widget.h"
#include <QApplication>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a0(argc, argv);
double a = -19.3, b = 9.7;
double c = qAbs(a);//返回a的绝对值
double max = qMax(b, c);//返回两个数值中最大值
int bn = qRound(b);//返回一个与浮点数最接近的整数值。
int cn = qRound(c);
qDebug() << "a = " << a;
qDebug() << "b = " << b;
qDebug() << "c = qAbs(a) = " << c;
qDebug() << "qMax(b,c)" << max;
qDebug() << "bn = qRound(b) = " << bn;
qDebug() << "cn = qRound(c) = " << cn;
qSwap(bn, cn);//交换两个数的值
qDebug() <<"qSwap(bn, cn) : " << "bn = " << bn << ", cn = " << cn;
return a0.exec();
}
基本的正则表达式
使用正则表达式可以方便地完成处理字符串的一些操作,如验证、查找、替换和分割等。Qt的QRegExp类是正则表达式的表示类,它基于Perl的正则表达式语言,完全支持Unicode。
正则表达式由表达式(expressions)、量词(quantifiers)和断言(assertions)组成。
- 最简单的表达式是一个字符。字符集可以使用表达式如“[AEIOU]”,表示匹配所有的大写元音字母;使用“[^AEIOU]” 则表示匹配所有非元音字母,即辅音字母;连续的字符集可以使用表达式“[a-z]”,表示匹配所有的小写英文字母。
- 量词说明表达式出现的次数。如“x[1,2]”表示“x”可以至少有一个,最多两个。
在计算机语言中,标识符通常要求以字母或下划线开头,后面可以是字母、数字和下划线。满足条件的标识符表示为:
" [A-Za-z_]+[A-Za-z_0-9]* "
其中,表达式中的“+”表示“[A-Za-z]”至少出现一次,可以出现多次;“ * ”表示“[A-Za-z_0-9]”可以出现0次或者多次。
- 类似的正则表达式的量词如下:
量词 | 含义 | 量词 | 含义 |
---|---|---|---|
E? | 匹配0次或1次 | E[n,] | 至少匹配n次 |
E+ | 匹配1次或者多次 | E[,m] | 最多匹配m次 |
E* | 匹配0次或多次 | E[n,m] | 至少匹配n次,最多匹配m次 |
E[n] | 匹配n次 | – | – |
- 正则表达式的断言:
符号 | 含义 | 符号 | 含义 |
---|---|---|---|
^ | 表示在字符串开头进行匹配 | \B | 非单词边界 |
$ | 表示在字符串结尾进行匹配 | (?=E) | 表示表达式后缀紧随E才匹配 |
\b | 单词边界 | (?!E) | 表示表达式后不跟随E才匹配 |
控件
本节简单介绍几个常用的控件,以便对Qt的控件有一个初步认识。
按钮组(Buttons)
按钮组如图所示:
具体如下 :
- Push Button:按钮。
- Tool Button:工具按钮。
- Radio Button:单选按钮。
- Check Box:复选框
- Command Link Button:命令链接按钮。
- Dialog Button Box:对话框按钮盒。
示例:
-
新建项目“PushButtonTest”,基类选择QWideget选项,取消“创建界面”复选框。
-
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
};
#endif // WIDGET_H
- widget.cpp
#include "widget.h"
#include <qapplication.h>
#include <qpushbutton.h>
#include <qfont.h>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
setMinimumSize(200, 120);
setMaximumSize(200, 120);
QPushButton *quit = new QPushButton("Quit", this);
quit->setGeometry(62, 40, 75, 30);
quit->setFont(QFont("Times", 18, QFont::Bold));
connect(quit, SIGNAL(clicked()), qApp, SLOT(quit()));
}
Widget::~Widget()
{
}
- main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.setGeometry(100, 100, 200, 120);
w.show();
return a.exec();
}
- 执行结果
输入部件(Input Widgets)
输入部件(Input Widgets)如下图:
- Combo Box:组合框。
- Font Combo Box:字体组合框。
- Line Edit:行编辑框。
- Text Edit:文本编辑框。
- Plain Text Edit:纯文本编辑框。
- Spin Box:数字显示框(自旋盒)。
- Double Spin Box:双自旋盒。
- Time Edit:时间编辑。
- Date Edit:日期编辑。
- Date/Time Edit:日期/时间编辑。
- Horizontal Scroll Bar:横向滚动条。
- Vertical Scroll Bar:垂直滚动条。
- Horizontal Slider:横向滑块。
- Vertical Slider:垂直滑块。
- Key Sequence Edit:按键序列编辑框。
QDateTime类
Date/Time Edit对应于QDateTime类,在Qt5中可以使用它获得系统时间。通过QDateTime::currentDateTime()来获取本地系统的时间和日期信息。可以通过date()和time()来返回datetime中的日期和时间部分。典型代码如下:
QLabel *datalbel = new QLabel();
QDateTime *datatime = new QDateTime(QDateTime::currentDateTime());
datalbel->setText(datatime->date().toString());
datalbel->show();
QTimer类
定时器(QTimer)的使用非常简单,只需要以下几个步骤就可以完成定时器的应用。
- 新建一个定时器
QTimer *timer_clock = new QTimer(parent);
- 连接这个定时器的信号和槽,利用定时器的timeout()。
connect(timer_clock, SIGNAL(timeout()), this, SLOT(slottimedone());
即定时时间一刀就会发生timeout()信号,从而触发slottimedone()槽去完成某件事情。
- 开启定时器,并设定定时周期。
定时器定时有两种方式:start(int time)和setSingleShot(true)。其中,start(int time)表示每隔“time”毫秒会重启定时器,可以重复触发定时,利用stop()将定时器关闭;而setSingleShot(true)是仅启动定时器一次。
time_clock->start(2000);
显示控件组(Display Widgets)
显示控件组(Display Widgets)如下图所示:
- Label:标签。
- Text Browser:文本浏览器。
- Graphics View:图像视图
- Calendar Widget:日历。
- LCD Number:液晶数字。
- Progress Bar:进度条。
- Horizontal Line:水平线。
- Vertical Line:垂直线。
- OpenGL Widget:开放式图形库工具。
- QQuick Widget:嵌入QML工具。
Graphics View
Graphics View 对应于QGraphicsView类,提供了Qt5的图像视图框架。
Text Browser
Text Browser 对应于QTextBrowser类,QTextBrowser类继承自QTextEdit,而且仅是只读的,对里面的内容并不能继续更改,但是相对于QTextEdit来讲,它还具有链接文本的作用。
modified : const bool //通过布尔值来说明内容是否被修改
openExternalLinks : bool
openLinks : bool
readOnly : const bool
searchPaths : QStringList
source : QUrl
undoRedoEnabled : const bool
通过以上属性设置,可以设定QTextBrowser是否允许外部链接,是否为只读属性,外部链接的路径及链接内容,是否可以进行撤销等操作。
QTextBrowser还提供了几种比较有用的槽函数。
virtual void backward();//上一页
virtual void forward();//下一页
virtual void home(); //主页
可以通过链接这几个槽函数来达到“翻页”的效果。
QQuickWidget
QQuickWidget是Qt5.3发布的一个组件,传统的QWidget程序可以用它来嵌入QML代码,为Qt开发者将桌面应用迁移到Qt Quick提供了方便,但目前QML中尚不能嵌入其他非QML窗口,因为QML的渲染机制和QWidget是不一样的。
空间间隔组(Spaacers)
- Horizontal Spacer:水平间隔。
- Vertical Spacer:垂直间隔。
布局管理组(Layouts)
- Vertical Layout:垂直布局,
- Horizontal Layout:水平布局。
- Grid Layout:网格布局。
- Form Layout:表单布局。
容器组(Containers)
- Group Box:组框。
- Scroll Area:滚动区域。
- Tool Box:工具箱。
- Tab Widget:标签小部件。
- Stackerd Widget:堆叠部件。
- Frrame:帧。
- Widget:小部件。
- MDI Area:MDI区域。
- Dock Widget:停靠窗体部件。
- QAxWidget:封装flash的ActiveX控件。
Widget对应的QWidget类的用法
Widget是使用Qt编写的图像用户界面(GUI)应用程序的基本生成块。每个GUI组件,如按钮、标签或文本编辑器,都是一个Widget,并可以放置在现有的用户界面中或作为单独的窗口显示。每种类型的组件都是由QWidget的特殊子类提供的,而QWidget自身又是QObject的子类。
QWidget是所以QtGUI界面类的基类,它接收鼠标、键盘及其他窗口事件,并在显示器上绘制自己。
通过传入QWidget构造函数的参数(或者调用QWidget::setWindowFlags() 和 QWidget::setParent() 函数)可以指定一个窗口部件的窗口标识(window flag)和父窗口部件。
窗口部件的窗口标识(window flag)定义了窗口部件的窗口类型和窗口提示(hint)。窗口类型指定了窗口部件的窗口系统属性(window-system properties),一个窗口部件只能有一个窗口类型,窗口提示定义了顶层窗口的外观,一个窗口可以由多个提示。
没有父窗口部件的Widget对象是一个窗口,窗口通常具有一个窗口边框(frame)和一个标题栏。而子窗口部件通常处在父窗口部件的内部,没有窗口边框和标题栏。
QWidget窗口部件的构造函数为:
QWidget(QWidget *parent = 0, Qt::WindowFlags f = 0);
/*
parent:指定窗口部件的父窗口部件。如果为0则新建窗口部件蒋帅一个窗口。否则新建窗口将会出现在父窗口部件的界面内部。
f:指定了新窗口的窗口标识。默认是0,及Qt::Widget.
*/
示例:
- 创建窗口
QWidget *window = new QWidget();
window->resize(320, 240);
window->show();
QPushButton *button = new QPushButton(QObject::tr("Press me"), window);
button->move(100, 100);
button->show();
- 使用布局:
QWidget *window = new QWidget();
//新建label进行布局
QLabel *label = new QLabel(QObject::tr("Name:"));
QLineEdit *lineEdit = new QLineEdit();
QHBoxLayout *layout = new QHBoxLayout();
layout->addWidget(label);
layout->addWidget(lineEdit);
window->setLayout(layout);
window->resize(320, 240);
window->show();
QPushButton *button = new QPushButton(QObject::tr("Press me"), window);
button->move(20, 20);
button->show();
- 设计复杂关系的窗口视图
QWidget *window = new QWidget();
QLabel *queryLabel = new QLabel();
QLineEdit *queryEdit = new QLineEdit();
QTableView *resultView = new QTableView();
QHBoxLayout *queryLayout = new QHBoxLayout();
queryLayout->addWidget(queryLabel);
queryLayout->addWidget(queryEdit);
QVBoxLayout *mainLayout = new QVBoxLayout();
mainLayout->addLayout(queryLayout);
mainLayout->addWidget(resultView);
window->setLayout(mainLayout);
window->show();
项目视图组(Item Views)
- List View:清单视图。
- Tree View:树视图。
- Table View:表视图。
- Column View:列视图。
Table View与Table Widget的区别
具体如下表:
区别点 | QTableView | QTableWidget |
---|---|---|
继承关系 | – | QTableWidget集成子QTableView |
使用数据模型setModel | 可以使用setModel设置数据模型 | setModel是私有函数,不能使用该函数设置数据模型 |
显示复选框setCheckState | 没有函数实现复选框 | QTableWidgetItem类中的setCheckState(Qt::Checked):可以设置复选框。 |
与QSqlTableModel 绑定 | QTableView能与QSqlTableModel绑定 | QTableWidget不能与QSqlTableModel绑定 |
- 模型:所有的模型都是基于QAbstractItemModel类,该类是抽象基类。
- 视图:所有的视图都从抽象基类QAbstractItemView继承。
Qt5中引入了模型/视图框架用于完成数据与表现的分离,这在Qt5中成为InterView框架,类似于常用的MVC设计模式。
MVC设计模式是起源于Smalltalk语言的一种与用户界面相关的设计模式。MVC包括三个元素:模型(model)表示数据;视图(view)表示用户界面;控制(controller)定义了用户在界面上的操作。同使用MVC模式,有效地分离了数据和用户界面,使得设计更为灵活,更能适应变化。
示例:
- 简单使用:
QSqlTableModel *model = new QSqlTableModel();
model->setTable("employee");
model->setEditStrategy(QSqlTableModel::OnManualSubmit);
model->select();
model->removeColumn(0);
model->setHeaderData(0, Qt::Horizontal, QObject::tr("Name"));
model->setHeaderData(1, Qt::Horizontal, QObject::tr("Salary"));
QTableView *view = new QTableView();
view->setModel(model);
view->show();
* 视图与模型绑定,模型必须使用new创建,否则视图不能随模型的改变而改变。
// QStandardItemModel model(4, 2); 错误,没有使用new创建。
QStandardItemModel *model = new QStandardItemModel(4, 2); //正确,应该使用new创建model。
model->setHeaderData(0, Qt::Horizontal, QObject::tr("Label"));
model->setHeaderData(1, Qt::Horizontal, QObject::tr("Quantity"));
ui->tableView->setModel(model);
for(int row = 0; row <4 ; ++row)
{
for(int column = 0; column < 2; ++column)
{
QModelIndex index = model->index(row, column, QModelIndex());
model->setData(index, QVariant((row + 1) *(column + 1)));
}
}
项目控件组(Item Widgets)
- List Widget:清单控件。
- Tree Widget:树形控件。
- Table Widget:表控件。
树形控件实例
树形控件QTree Widget,其中控件的树节点成为QTreeWidgetItem,这种控件有时很有用处。例如,在飞信软件群发短信时选择联系人的界面中就用到这种有复选框的树形控件。
接下来实现一个简单的树形控件实例。
1、新建项目,保持“创建界面”复选框选择状态。
2、双击“widget.ui”文件,打开Qt的设计器,拖拽一个QTreeWidget控件到widget窗口中。
3、添加以下代码
- widget.cpp
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
init();
connect(ui->treeWidget, SIGNAL(itemChanged(QTreeWidgetItem *, int)), this, SLOT(treeItemChanged(QTreeWidgetItem *, int)));
}
Widget::~Widget()
{
delete ui;
}
void Widget::init()
{
ui->treeWidget->clear();
//第一个分组
QTreeWidgetItem *group1 = new QTreeWidgetItem(ui->treeWidget);
group1->setText(0, "group1");
group1->setFlags(Qt::ItemIsUserCheckable |Qt::ItemIsEnabled |Qt::ItemIsSelectable);
group1->setCheckState(0, Qt::Unchecked);
QTreeWidgetItem *subItem11 = new QTreeWidgetItem(group1);
subItem11->setFlags(Qt::ItemIsUserCheckable |Qt::ItemIsEnabled |Qt::ItemIsSelectable);
subItem11->setText(0, "subItem11");
subItem11->setCheckState(0, Qt::Unchecked);
QTreeWidgetItem *subItem12 = new QTreeWidgetItem(group1);
subItem12->setFlags(Qt::ItemIsUserCheckable |Qt::ItemIsEnabled |Qt::ItemIsSelectable);
subItem12->setText(0, "subItem12");
subItem12->setCheckState(0, Qt::Unchecked);
QTreeWidgetItem *subItem13 = new QTreeWidgetItem(group1);
subItem13->setFlags(Qt::ItemIsUserCheckable| Qt::ItemIsEnabled | Qt::ItemIsSelectable);
subItem13->setText(0, "subItem13");
subItem13->setCheckState(0, Qt::Unchecked);
QTreeWidgetItem *subItem14 = new QTreeWidgetItem(group1);
subItem14->setFlags(Qt::ItemIsUserCheckable| Qt::ItemIsEnabled | Qt::ItemIsSelectable);
subItem14->setText(0, "subItem14");
subItem14->setCheckState(0, Qt::Unchecked);
//第二个分组
QTreeWidgetItem *group2 = new QTreeWidgetItem(ui->treeWidget);
group2->setText(0, "group2");
group2->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
group2->setCheckState(0, Qt::Unchecked);
QTreeWidgetItem *subItem21 = new QTreeWidgetItem(group2);
subItem21->setFlags(Qt::ItemIsUserCheckable| Qt::ItemIsEnabled | Qt::ItemIsSelectable);
subItem21->setText(0, "subItem21");
subItem21->setCheckState(0, Qt::Unchecked);
QTreeWidgetItem *subItem22 = new QTreeWidgetItem(group2);
subItem22->setFlags(Qt::ItemIsUserCheckable| Qt::ItemIsEnabled | Qt::ItemIsSelectable);
subItem22->setText(0, "subItem22");
subItem22->setCheckState(0, Qt::Unchecked);
QTreeWidgetItem *subItem23 = new QTreeWidgetItem(group2);
subItem23->setFlags(Qt::ItemIsUserCheckable| Qt::ItemIsEnabled | Qt::ItemIsSelectable);
subItem23->setText(0, "subItem23");
subItem23->setCheckState(0, Qt::Unchecked);
QTreeWidgetItem *subItem24 = new QTreeWidgetItem(group2);
subItem24->setFlags(Qt::ItemIsUserCheckable| Qt::ItemIsEnabled | Qt::ItemIsSelectable);
subItem24->setText(0, "subItem24");
subItem24->setCheckState(0, Qt::Unchecked);
}
void Widget::treeItemChanged(QTreeWidgetItem *item, int column)
{
QString itemText = item->text(0);
//选中时
if(Qt::Checked == item->checkState(0))
{
QTreeWidgetItem *parent = item->parent();
int count = item->childCount();
if(count > 0)
{
for(int i = 0; i <count; i++)
{
//子字节也选中
item->child(i)->setCheckState(0, Qt::Checked);
}
}
else {
//是子节点
updateParentItem(item);
}
}
else if (Qt::Unchecked == item->checkState(0)) {
int count = item->childCount();
if(count > 0)
{
for(int i = 0; i <count; i++)
{
//子字节也选中
item->child(i)->setCheckState(0, Qt::Unchecked);
}
}
else {
//是子节点
updateParentItem(item);
}
}
}
void Widget::updateParentItem(QTreeWidgetItem *item)
{
QTreeWidgetItem *parent = item->parent();
if(parent == NULL)
{
return ;
}
//选中子节点个数
int selectedCount = 0;
int childCount = parent->childCount();
for(int i = 0; i <childCount; i++)
{
QTreeWidgetItem *childItem = parent->child(i);
if(childItem->checkState(0) == Qt::Checked)
{
selectedCount++;
}
}
if(selectedCount <= 0)
{
//未选中状态
parent->setCheckState(0, Qt::Unchecked);
}
else if (selectedCount > 0 &&selectedCount <childCount) {
//部分选中
parent->setCheckState(0, Qt::PartiallyChecked);
}
else if (selectedCount == childCount) {
//选中状态
parent->setCheckState(0, Qt::Checked);
}
}
- widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTreeWidget>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
void init();
void updateParentItem(QTreeWidgetItem *item);
public slots:
void treeItemChanged(QTreeWidgetItem *item, int column);
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
- 执行结果