> 文档中心 > Qt学习笔记(1)

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(); }
  1. 第一行包含了自己写的Widget类,也就是说,一般要包含自定义类的头文件,这点跟C++一样
  2. 第二行包含了一个应用程序类头文件
  3. 第三行是一个标准main函数 ,argc是命令行参数个数,argv是命令行参数数组
  4. 下面QApplication a创建了一个应用程序对象,而且把main函数参数传递给了应用程序
  5. 当创建了一个窗口时,默认是不可见的,必须使用show方法让他出现
  6. 最后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对于不同数据类型不同的存储方式:

  1. 如果存储的类型大小跟指针大小一样,那就直接储存他的值
  2. 如果是一个对象指针,那该指针指向实际存储的对象

其实他们使用起来跟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();   

 常用的还有一些图形和时间,用到的时候可以查文档,很方便的!