Qt学习笔记(1)
目录
一.pro文件解析
二.源文件解析
三.常用快捷键
四.重要的数据类型
1.字符串类
(1)QByteArray
(2)QString
2.container容器类
(1)QList类,QLinkedList类以及QVector类
(2)QMap类和QHash类
3.QVariant类型(变体数据类型)
一.pro文件解析
- Qt的项目文件,注释需要使用#号
如果自己写的话,需要在前面写上项目编译时需要加载的模块:
#加载模块QT+= core gui
Qt4以上的版本,gui跟Widgets分开了,Qt4及之前的版本是没有Widgets的,都在gui里面 ,所以在这里加上:
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
接下来需要指定C++版本,默认c++11
CONFIG += c++11
如果你想知道Qt不推荐使用的API,在你使用时给你警告,可以加入下面的代码:
DEFINES += QT_DEPRECATED_WARNINGS
如果你不想使用过时的API,可以加入这样的代码(这里表示禁用6.0.0之前弃用的API):
DEFINES + = QT_DISABLE_DEPRECATED_BEFORE = 0x060000
添加项目头文件和源文件,一般会自动添加:
# 项目中的源文件 删除后,项目里不会显示所有的源文件SOURCES += \ main.cpp \ widget.cpp# 项目中的头文件HEADERS += \ widget.h
还有一些默认的部署规则:
qnx: target.path = /tmp/$${TARGET}/bin #嵌入式else: unix:!android: target.path = /opt/$${TARGET}/bin #unix!isEmpty(target.path): INSTALLS += target
一些常用的qmake变量总结:
.pro中变量 | 含义 | 示例 |
---|---|---|
TEMPLATE | 模板变量指定生成makefile(app:应用程序/lib:库) | TEMPLATE = app |
QT | 指定加载的Qt模块(core/gui/widgets...) | QT += widgtes |
DESTDIR | 指定生成的应用程序放置的目录 | DESTDIR += ../bin |
TARGET | 指定生成的应用程序名 | TARGET = hello |
HEADERS | 工程中包含的头文件 | HEADERS += hello.h |
FORMS | 工程中包含的.ui设计文件 | FORMS += hello.ui |
SOURCES | 工程中包含的源文件 | SOURCES += main.cpp hello.cpp |
RESOURCES | 工程中包含的资源文件 | RESOURCES += qrc/hello.qrc |
LIBS | 引入的lib文件的路径 -L:引入路径 | LIBS += -L. |
CONFIG | 用来告诉qmake关于应用程序的配置信息 | CONFIG+= qt warn_on release |
UI_DIR | 指定.ui文件转化成ui_*.h 文件的存放目录 |
UI_DIR += forms |
RCC_DIR | 指定将.qrc文件转换成qrc_*.h 文件的存放目录 |
RCC_DIR += ../tmp |
MOC_DIR | 指定将含Q_OBJECT的头文件转换成标准.h文件的存放目录 | MOC_DIR += ../tmp |
OBJECTS_DIR | 指定目标文件(obj)的存放目录 | OBJECTS_DIR += ../tmp |
DEPENDPATH | 程序编译时依赖的相关路径 | DEPENDPATH += . forms include qrc sources |
INCLUDEPATH | 头文件包含路径 | INCLUDEPATH += . |
DEFINES | 增加预处理器宏(gcc的-D选项)。 | DEFINES += USE_MY_STUFF |
QMAKE_CFLAGS | 设置c编译器flag参数 | QMAKE_CFLAGS += -g |
QMAKE_CXXFLAGS | 设置c++编译器flag参数 | QMAKE_CXXFLAGS += -g |
QMAKE_LFLAGS | 设置链接器flag参数 | QMAKE_LFLAGS += -rdynamic |
二.源文件解析
以main函数为例子:
#include "widget.h"//自定义的类,派生与QWidget#include int main(int argc, char *argv[]) { QApplication a(argc, argv); Widget w; w.show(); return a.exec(); }
- 第一行包含了自己写的Widget类,也就是说,一般要包含自定义类的头文件,这点跟C++一样
- 第二行包含了一个应用程序类头文件
- 第三行是一个标准main函数 ,argc是命令行参数个数,argv是命令行参数数组
- 下面QApplication a创建了一个应用程序对象,而且把main函数参数传递给了应用程序
- 当创建了一个窗口时,默认是不可见的,必须使用show方法让他出现
- 最后return a.exec():程序进入消息循环,等待可能的输入进行响应。这里就是main()函数将控制权转交给Qt,Qt完成事件处理工作,当应用程序退出的时候,exec()函数的值就会返回。在exec()函数中,Qt接收并处理用户和系统的事件并且将它们传递给适当的窗口部件。
三.常用快捷键
- 运行 Ctrl + r
- 编译 Ctrl + b
- 注释 Ctrl + /
- 字体缩放 Ctrl + 鼠标滚轮
- 查找/替换 Ctrl + f
- 整行移动 Ctrl + Shift + ↑ 或 ↓
- 自动对齐 Ctrl + i
- 帮助文档
- 第一种:Qt Creator 直接查看 F1
- 第二种:打开独立的帮助文档程序 assistant
- 同名.h 和 .cpp 之间的切换 F4
- 快速添加函数的定义 Alt + Enter
鼠标移动到函数申明上
- 修改变量名,并应用到所有用到该变量的地方 Ctrl + Shift +r
- 快速打开输出窗口 Alt + 数字键(1-8)
-
书签功能,即在某行代码处进行标记,方便以后找到。书签也可以添加文字标注。
-
按Ctrl + M 添加/删除书签
-
按Ctrl + . 查找并移动到下一个标签
-
四.重要的数据类型
1.字符串类
(1)QByteArray
严格来说,它是字节数组,相当于C语言中char*的升级版,他有很多API跟接下来要讲的QString类型很像,所以会比较详细一点:
QByteArray(QByteArray &&other) //移动构造QByteArray(const QByteArray &other) //拷贝构造QByteArray(int size, char ch) //size大小的,元素都是ch的字节数组QByteArray(const char *data, int size = -1) //这里有缺省,不用自己算长度,很方便,如果自己写的size比长度小,则会截取size长度的,不过这样有风险
上面是构造函数,比较常规,接下来看追加操作:
append(const QByteArray &ba) //跟重载的+=号是一样的//如果追加的是一个空字节数组,则没有分配额外内存,即共享;如果非空,则进行深拷贝后连接append(char ch)append(int count, char ch)append(const char *str)append(const char *str, int len)append(const QString &str)//其他比较常规
访问:
at(int i) const //跟[]重载一样back() const //最后一个//访问可以用迭代器,返回的都是迭代器,跟C++用法一样iterator QByteArray::begin()iterator QByteArray::end()const_iterator QByteArray::cbegin() constconst_iterator QByteArray::cend() const
清空,删除,插入,替换,查找,判断:
//清空,并且置为空clear()//删除QByteArray &QByteArray::remove(int pos, int len);//从大字符串中删除len个字符, 从第pos个字符的位置开始删除void QByteArray::chop(int n);// 从字符数组的尾部删除 n 个字节void QByteArray::truncate(int pos);// 从字节数组的 pos 位置将数组截断 (前边部分留下, 后边部分被删除)//插入prepend(const QByteArray &ba) 头插法prepend(char ch)prepend(int count, char ch)prepend(const char *str)prepend(const char *str, int len)//下面等价于appendpush_back(const QByteArray &other)push_back(char ch)push_back(const char *str)//下面等价于prependpush_front(const QByteArray &other)push_front(char ch)push_front(const char *str)//替换,函数都挺简单replace(int pos, int len, const QByteArray &after)replace(int pos, int len, const char *after)replace(int pos, int len, const char *after, int alen)replace(char before, const char *after)replace(char before, const QByteArray &after)replace(const char *before, const char *after)replace(const char *before, int bsize, const char *after, int asize)replace(const QByteArray &before, const QByteArray &after)// 将字节数组中的 子字符串 before 替换为 afterreplace(const QByteArray &before, const char *after)replace(const char *before, const QByteArray &after)replace(char before, char after)replace(const QString &before, const char *after)replace(char before, const QString &after)replace(const QString &before, const QByteArray &after)//查找和判断// 判断字节数组中是否包含子字符串 ba, 包含返回true, 否则返回falsecontains(const QByteArray &ba) const;contains(const char *ba) const;// 判断字节数组中是否包含子字符 ch, 包含返回true, 否则返回falsecontains(char ch) const;// 判断字节数组是否以字符串 ba 开始, 是返回true, 不是返回falsestartsWith(const QByteArray &ba) const;startsWith(const char *ba) const;// 判断字节数组是否以字符 ch 开始, 是返回true, 不是返回falsestartsWith(char ch) const;// 判断字节数组是否以字符串 ba 结尾, 是返回true, 不是返回falseendsWith(const QByteArray &ba) const;endsWith(const char *ba) const;// 判断字节数组是否以字符 ch 结尾, 是返回true, 不是返回falseendsWith(char ch) const;
类型转换,功能很强大,几乎什么类型都有:
// 将QByteArray类型的字符串 转换为 char* 类型char *QByteArray::data();const char *QByteArray::data() const;// int, short, long, float, double -> QByteArray// 其他重载的同名函数可参考Qt帮助文档, 此处略QByteArray &QByteArray::setNum(int n, int base = 10);QByteArray &QByteArray::setNum(short n, int base = 10);QByteArray &QByteArray::setNum(qlonglong n, int base = 10);QByteArray &QByteArray::setNum(float n, char f = 'g', int prec = 6);QByteArray &QByteArray::setNum(double n, char f = 'g', int prec = 6);[static] QByteArray QByteArray::number(int n, int base = 10);[static] QByteArray QByteArray::number(qlonglong n, int base = 10);[static] QByteArray QByteArray::number(double n, char f = 'g', int prec = 6);// QByteArray -> int, short, long, float, doubleint QByteArray::toInt(bool *ok = Q_NULLPTR, int base = 10) const;short QByteArray::toShort(bool *ok = Q_NULLPTR, int base = 10) const;long QByteArray::toLong(bool *ok = Q_NULLPTR, int base = 10) const;float QByteArray::toFloat(bool *ok = Q_NULLPTR) const;double QByteArray::toDouble(bool *ok = Q_NULLPTR) const;// std::string -> QByteArray[static] QByteArray QByteArray::fromStdString(const std::string &str);// QByteArray -> std::stringstd::string QByteArray::toStdString() const;
大小写转换以及万金油参数:
// 所有字符转换为大写QByteArray QByteArray::toUpper() const;// 所有字符转换为小写QByteArray QByteArray::toLower() const;// 返回字节数组对象中字符的个数int QByteArray::length() const;int QByteArray::size() const;int QByteArray::count() const;// 返回字节数组对象中 子字符串ba 出现的次数int QByteArray::count(const QByteArray &ba) const;int QByteArray::count(const char *ba) const;// 返回字节数组对象中 字符串ch 出现的次数int QByteArray::count(char ch) const;
(2)QString
这个可以看作是C++的string类型,带编码。
由于上面很多操作都有比较详细,这里贴一下其他独有的操作:
字符串格式转换:
C语言中有sprintf()函数,QString也提供了一个asprintf()函数。
QString res = QString::asprintf("fileName:%s size:%d","./av.jpg",20); qDebug()<<res<<endl;
不过QString还提供的另一种格式化字符串输出的函数arg(),更为方便。
QString arg(const QString &a, int fieldWidth = 0, QChar fillChar = QLatin1Char( ' ' )) const;QString arg(int a, int fieldWidth = 0, int base = 10, QChar fillChar = QLatin1Char( ' ' )) const;//用于填充字符串中的%1,%2…为给定格式的整形数字,其中第一个参数是要填充的数字,第二个参数为最小宽度,第三个参数为进制,第四个参数为当原始数字长度不足最小宽度时用于填充的字符// 示例程序QString str = QString("%1 %2 %3").arg(1).arg(2);str = str.arg("hello");qDebug()<<str<<endl; //"hello 2 1"QString text = QString("%1:%2:%3").arg(1,2,10,QChar('0')).arg(35).arg(59);qDebug()<<text<<endl; //"01:35:59"
2.container容器类
Qt提供了一组通用的基于模板的容器类。对比C++的标准模板库中的容器类,Qt的这些容器更轻量、更安全并且更容易使用。此外,Qt的容器类在速度、内存消耗和内联(inline)代码等方面进行了优化(较少的内联代码将会减少可执行程序的大小)。存储在Qt容器中的数据必须是可赋值的数据类型,也就是说,这种数据类型必须提供一个默认的构造函数(不需要参数的构造函数)、一个复制构造函数和一个赋值操作运算符。
Qt提供了两种遍历容器的风格:
java风格的迭代器和stl风格的迭代器。java风格的迭代器更容易使用并提供高级功能,而STL风格的迭代器稍微更高效,可以与Qt和STL的通用算法一起使用。这里只写STL的风格:
容器 | 只读迭代器 | 读写迭代器 |
---|---|---|
QList,QQueue | QList::const_iterator | QList::iterator |
QLinkedList | QLinkedList::const_iterator | QLinkedList::iterator |
QVector,QStack | QVector::const_iterator | QVector::iterator |
QSet | QSet::const_iterator | QSet::iterator |
QMap,QMultiMap | QMap::const_iterator | QMap::iterator |
QHash,QMultiHash | QHash::const_iterator | QHash::iterator |
下面来讲解一些常用的容器类:
(1)QList类,QLinkedList类以及QVector类
这三个里面提供的API十分类似,他们一般可以互换,但是会产生性能差别,这也是在使用他们的时候需要注意的。
其中,“Amort.O(1)”表示,如果仅完成一次操作,可能会有O(n)行为;但是如果完成多次操作(如n次),平均结果将会是O(1)。
QList可以理解为一个指针数组,该数组存储的指针指向QList存储的列表项的内容,当项目容量小时,可以实现快速的插入和删除;QVertor则可以理解为普通数组,但是前插一般不太合适,数据结构决定性能;QLinkList是一个真正意义上的链表,不能使用下标,只能使用迭代器访问它的数据项。与QList相比,当对一个很大的列表进行插入操作时,QLinkedList具有更高的效率。
其中,稍微了解一下QList对于不同数据类型不同的存储方式:
- 如果存储的类型大小跟指针大小一样,那就直接储存他的值
- 如果是一个对象指针,那该指针指向实际存储的对象
其实他们使用起来跟C++的用起来没有什么区别,这里就简单地复习一些常用的操作(以 QList为例子):
QList list;//增加数据list.push_back("尾插");list.push_front("头插");list<<"I"<<"love"<<"Qt"; //流插入list.append("添加"); //可以无参构造list.insert(0,"ll"); //下标插入,也可以用迭代器,会插在迭代器的后面,并返回当前迭代器//遍历for(auto v:list){ qDebug()<<v;}//STL风格QList::iterator iter;for(iter = list.begin();iter != list.end();iter ++){ qDebug()<<*iter;}//java风格QListIterator iterJava(list);while(iterJava.hasNext()){ qDebug()< ["A", "C", "D", "E", "B", "F"]void move(int from, int to)void swap(QList &other)//交换下标i j的元素 void swapItemsAt(int i, int j)//和其他容器互转std::list toStdList() constQVector toVector() const[static] QList fromSet(const QSet &set)[static] QList fromStdList(const std::list &list)[static] QList fromVector(const QVector &vector)//判断函数int count(const T &value) constint count() constint size() constint length() constbool empty() constbool isEmpty() const//如果列表第一项/后一项等于value,则返回true; 否则返回false。 bool startsWith(const T &value) const bool endsWith(const T &value) const//预分配空间大小 void reserve(int alloc)
Qt还有一个类型是QStringList类型,继承于QList,可以用QList里面的函数,也可以使用下面这些更为方便的函数来处理字符串:
- 判断是否包含某个字符串
bool contains(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) constbool contains(QLatin1String str, Qt::CaseSensitivity cs = Qt::CaseSensitive) constbool contains(QStringView str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
- 过滤:返回包含子字符串str的所有字符串的列表
QStringList filter(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) constQStringList filter(QStringView str, Qt::CaseSensitivity cs = Qt::CaseSensitive) constQStringList filter(const QRegExp &rx) constQStringList filter(const QRegularExpression &re) const
- 查找
//从左往右查找int indexOf(const QRegExp &rx, int from = 0) constint indexOf(QStringView str, int from = 0) constint indexOf(QLatin1String str, int from = 0) constint indexOf(QRegExp &rx, int from = 0) constint indexOf(const QRegularExpression &re, int from = 0) const//从右往左查找 int lastIndexOf(const QRegExp &rx, int from = -1) constint lastIndexOf(QStringView str, int from = -1) constint lastIndexOf(QLatin1String str, int from = -1) constint lastIndexOf(QRegExp &rx, int from = -1) constint lastIndexOf(const QRegularExpression &re, int from = -1) const
- 连接:将QStringList中的所有字符串连接为一个字符串,每个元素由给定的分隔符(可以是空串)分隔。
//支持流插入 <<QString join(const QString &separator) constQString join(QStringView separator) constQString join(QLatin1String separator) constQString join(QChar separator) const
- 删除:从QStringList中删除重复的元素。 返回已删除元素的数量。
int removeDuplicates()
- 替换:返回一个字符串列表,其中每个字符串在找到before文本时都将before文本替换为after文本
QStringList &replaceInStrings(const QString &before, const QString &after, Qt::CaseSensitivity cs = Qt::CaseSensitive)QStringList &replaceInStrings(QStringView before, QStringView after, Qt::CaseSensitivity cs = Qt::CaseSensitive)QStringList &replaceInStrings(const QString &before, QStringView after, Qt::CaseSensitivity cs = Qt::CaseSensitive)QStringList &replaceInStrings(QStringView before, const QString &after, Qt::CaseSensitivity cs = Qt::CaseSensitive)QStringList &replaceInStrings(const QRegExp &rx, const QString &after)QStringList &replaceInStrings(const QRegularExpression &re, const QString &after)
- 排序:升序
void sort(Qt::CaseSensitivity cs = Qt::CaseSensitive)
(2)QMap类和QHash类
QMap类和QHash类具有非常类似的功能,它们的差别仅在于:
- QHash具有比QMap更快的查找速度。
- QHash以任意的顺序存储数据项,而QMap总是按照键Key顺序存储数据。
- QHash的键类型Key必须提供operator==()和一个全局的qHash(Key)函数,而QMap的键类型Key必须提供operator<()函数。
跟C++有点不一样的是,这里添加数据用的是Key类型,不是数对,不过用法差不多;这里也提供一键多值的添加数据的函数,不过最好使用QMultiMap容器。
- 添加数据
//插入新的键值对,如果已经有一个键为key的项,则该项的值将被value替换;如果有多个键为key的项,则最近插入的项的值将被value替换。 QMap::iterator insert(const Key &key, const T &value)QMap::iterator insert(QMap::const_iterator pos, const Key &key, const T &value)//插入新的键值对,如果在map中已经有一个具有相同键的项,这个函数将创建一个新的项 QMap::iterator insertMulti(const Key &key, const T &value)QMap::iterator insertMulti(QMap::const_iterator pos, const Key &key, const T &value)
- 获取数据
T &first()const T &first() constconst Key &firstKey() constconst Key key(const T &value, const Key &defaultKey = Key()) const QList keys() constQList keys(const T &value) constT &last()const T &last() constconst Key &lastKey() const//返回一个列表,该列表包含映射中的所有键。 在映射中出现多次的键在返回的列表中只出现一次。 QList uniqueKeys() const//将其他map中的所有项目插入到该map中。 QMap &unite(const QMap &other)const T value(const Key &key, const T &defaultValue = T()) constQList values() constQList values(const Key &key) constT &operator[](const Key &key)const T operator[](const Key &key) const
- 删除数据
void clear()QMap::iterator erase(QMap::iterator pos)int remove(const Key &key)T take(const Key &key)
- 查找
bool contains(const Key &key) const/* 返回两个迭代器迭代器1:是指向当前 map 容器中第一个大于或等于 key 的键值对的迭代器(lowerBound())。迭代器2:是指向当前 map 容器中第一个大于 key 的键值对的迭代器。(upperBound())*/QPair equal_range(const Key &key)QPair equal_range(const Key &key) constQMap::iterator find(const Key &key)QMap::const_iterator find(const Key &key) constQMap::iterator lowerBound(const Key &key)QMap::const_iterator lowerBound(const Key &key) constQMap::iterator upperBound(const Key &key)QMap::const_iterator upperBound(const Key &key) const
- 判断
int count(const Key &key) constint count() constint size() constbool empty() constbool isEmpty() const
- QMultiMap
- 插入和替换:插入新的键值对。
- 如果已经有一个键为key的项,则该项的值将被value替换。
- 如果有多个键为key的项,则最近插入的项的值将被value替换。
typename QMap::iterator replace(const Key &key, const T &value)
- QHash
- 添加数据
QHash::iterator insert(const Key &key, const T &value)QHash::iterator insertMulti(const Key &key, const T &value)
- 获取数据
const Key key(const T &value) constconst Key key(const T &value, const Key &defaultKey) constQList keys() constQList keys(const T &value) constQList uniqueKeys() constQHash &unite(const QHash &other)const T value(const Key &key) constconst T value(const Key &key, const T &defaultValue) constQList values() constQList values(const Key &key) const
- 删除数据
void clear()QHash::iterator erase(QHash::const_iterator pos)QHash::iterator erase(QHash::iterator pos)QPair equal_range(const Key &key)QPair equal_range(const Key &key) constint remove(const Key &key)T take(const Key &key)
- 查找
bool contains(const Key &key) constQHash::iterator find(const Key &key)QHash::const_iterator find(const Key &key) const
- 判断
int count(const Key &key) constint count() constint size() constbool empty() const
QMultiHash
typename QHash::iterator replace(const Key &key, const T &value)
- 案例
class Grade //班级{public: Grade(int number, const QString& GradeName) :number(number),name(GradeName) {} friend QDebug operator<<(QDebug out, const Grade& stu); friend bool operator==(const Grade& left, const Grade& right); friend uint qHash(const Grade& stu, uint seed = 0);private: int number; //班级号 QString name; };QDebug operator<<(QDebug out, const Grade& stu){ out << "[" << stu.number <<"," << stu.name << "]"; return out;}bool operator==(const Grade& left, const Grade& right){ return (left.number == right.number);}uint qHash(const Grade& stu, uint seed){ return stu.number;}int main(int argc, char *argv[]){ QCoreApplication a(argc, argv); QHash hash; hash.insert(Grade(1403, "安卓"), "张三"); hash.insert(Grade(1406, "苹果"), "李四"); qDebug() << hash; return a.exec();}
3.QVariant类型(变体数据类型)
QVariant类类似于C++的联合(union)数据类型,它不仅能够保存很多Qt类型的值,包括QColor、QBrush、QFont、QPen、QRect、QString和QSize等,也能够存放Qt的容器类型的值。Qt的很多功能都是建立在QVariant基础上的,如Qt的对象属性及数据库功能等。
- 将标准类型转换为QVariant类型
// 这类转换需要使用QVariant类的构造函数, 由于比较多, 大家可自行查阅Qt帮助文档, 在这里简单写几个QVariant(int val);QVariant(bool val);QVariant(double val);QVariant(const char *val);QVariant(const QByteArray &val);QVariant(const QString &val);......// 使用设置函数也可以将支持的类型的数据设置到QVariant对象中// 这里的 T 类型, 就是QVariant支持的类型void setValue(const T &value);// 该函数行为和 setValue() 函数完全相同[static] QVariant fromValue(const T &value);
例子:
QVariant v(5);QVariant v;v.setValue(5);QVariant v = QVariant::fromValue(5);int i = v.toInt(); // i is now 5QString s = v.toString(); // s is now "5"
- 判断 QVariant中封装的实际数据类型
Type是枚举类型
//获取类型,返回的是一个枚举类型;如QVariant::Int ...Type type() const;//获取类型名const char *typeName() const;//根据类型id(枚举)获取类型名(字符串)[static] const char *typeToName(int typeId);//根据类型名(字符串)获取类型id(枚举)[static] Type nameToType(const char *name);
下面是常用的枚举类型变量:
- 将QVariant对象转换为实际的数据类型
//在转换之前可以先判断能够转换成对应的类型bool canConvert(int targetTypeId) constbool canConvert() constbool toBool() const;QByteArray toByteArray() const;double toDouble(bool *ok = Q_NULLPTR) const;float toFloat(bool *ok = Q_NULLPTR) const;int toInt(bool *ok = Q_NULLPTR) const;QString toString() const;......T value() const//v.value();
常用的还有一些图形和时间,用到的时候可以查文档,很方便的!