第3章 Qt简介
3.2 Qt核心模块
Qt是一个大库,由数个较小的库或者模块组成,最为常见的如下:core、gui、xml、sql、phonon、webkit,除了core和gui,这些模块都需要在qmake的工程文件中启用
QTextStream 流,Qdate 日期
3.3 Qt Create,用于Qt编程的集成开发环境
在Qt软件开发包 (Qt Software Development Kit,SDK)中包含有Qt Creator,其中包含了Qt和快速开始使用Qt 进行开发工作的所有东西
可使用拖放窗体布局来完成设计的Qt设计师也完全集成到了Qt Creator中
Qt Creator 用到的项目文件是 qmake 的.pro 文件,通过创建或编辑Qt Creator中已有的项目文件,可以完全避免命令行工具的使用
第4章 列表
只要有可能 ,就应当使用列表而不是数组
4.1 容器
列表 QList
4.2、迭代器
迭代器是一个提供对容器中的每一个元素进行间接访问的对象,它专门被设计用于在循环之中,三种迭代器模式:foreach循环,C++迭代器,Java风格的迭代器
QStringList实际上就是一个QList<QString>,使用split()函数和join()函数,在列表与字符串之间进行转换 相当简单
cpp
#include <QStringList>
#include <QDebug>
int main()
{
QString winter = "December, January, February";
QString spring = "March, April, May";
QStringList list;
list += winter;
list.append(spring);
qDebug() << list;
QString test = list.join(","); //list转换字符串
qDebug() << test;
QStringList list2 = test.split(",");//字符串转换list
qDebug() << list2;
Q_ASSERT(list2.size() == 6 );
foreach (const QString &str, list2) { //foreach循环
qDebug() << QString(" [%1] ").arg(str);
}
for(QStringList::iterator it = list2.begin();//C++迭代器
it!=list2.end(); ++it)
{
qDebug() << *it;
}
QListIterator<QString> itr( list2 );//Java风格的迭代器
while(itr.hasNext()){
qDebug() << itr.next();
}
return 0;
}
目录(有时称为文件夹),是文件的容器,目录可以包含符号链接,指向另外的文件或目录,对于处理文件或目录的大多数操作,可以使用符号链接而不是文件名称或路径名称
QDir 和 QDirIterator
cpp
#include <QDebug>
#include <QDir>
#include <QDirIterator>
int main()
{
QDir dir = QDir::current(); // QDir 类的静态成员函数current,成员函数 absolutePath
QDirIterator qdi (dir.absolutePath(), QDir::NoDot|QDir::Files, QDirIterator::Subdirectories);
while(qdi.hasNext()){ //hasNext、next 是 QDirIterator 类的成员函数
qDebug() << qdi.next();
}
return 0;
}
4.3 关系
三种关系:关联(只用于导航性)、聚合(无管理的包含关系)、组合(带管理的包含关系)
第7章 库与设计模式
库是一组代码模块,它按照可复用的方式组织,代码库中保存的是有用的、可复用的、编译后的代码,当用#include指令包含库模块的头文件时,就可以复用这个库模块
当复用来自于库中的任何模块时,其工作由链接器linker在链编build过程完成,可执行文件必须在运行时找到并动态地链接到编译后的库(称为运行时库),库lib是一个文件,它包含一个或者多个编译后文件,并对其进行了索引
C++库能够以多种途径被打包:开源包通常以压缩的档案文件形式发布,它包含全部的源代码、头文件以及链编脚本和文档;dev包 在Linux包管理程序中有时被称为-devel包,它通常以档案文件的形式发布,包含一个库以及相关的头文件;运行时库由lib文件组成,没有相关联的头文件,所以它只能用于执行已经用这个库链编过的应用
7.1 建立并复用库
qmake可以在工程文件里访问CPPLIBS环境变量,其访问语法是 $$(CPPBLIBS),qmake也可以包含其他的工程文件(片段)
工程为LIBS 和 INCLUDEPATH 变量 添加一些值,使它能够找到所 依赖的库和头文件,qmake无法知道用来构建工程所需要的外部库,如果工程依赖于某个外部库,则必须编辑这个工程文件,将它的值赋予变量INCLUDEPATH和LIBS
假设应用所需使用dataobjects库,其头文件位于CPPLIBS/dataobjects下,共享目标文件的库位于CPPLIBS下,那么必须如下这些行添加到工程文件中:
html
INCLUDEPAHT += $$(CPPLIBS)/dataobjects #头文件
LIBS += -L$$(CPPLIBS) # lib 搜索路径
LIBS += -ldataobjects # link with libdataobjects.so
组织库:依赖性管理,对于类,只要被复用者类的接口发生改变,就使得复用者的实现必须改变,则它们之间就存在依赖性:编译时依赖 和 链接时依赖,当设计类和库时,需要确保尽可能地减少不必要的或者无意的依赖性,对于类定义头文件,需遵循的一条规则是:如果可以使用 前置声明,就不要使用#include指令
安装库:当编写并测试完库之后,在链编过程结束后,它将被安装到由qmake变量DESTDIR指定的目录下,如果要迁移库,在windows系统中,可以将它的.dll文件复制到PATH变量中给出的合适目录下
7.3 框架与组件
在现代编程技术中,代码复用具有最高优先级,框架是一个通用类与约定的集合,其目的是提高设计的一致性,框架一般都具有文档丰富的公共API,API是库中公共函数、类和接口的描述,为了实现框架,可以采取设计模式
Qt是许多开源的面向对象框架中的一种,它提供一组可复用的组件,用于创建跨平台的应用
7.4 设计模式
设计模式可用于许多不同场合,其中 的大多数都描述如何根据职责来区分代码,这些模式被分成 三种 类别:创建模式、结构模式、行为模式
序列化器模式:QTextStream 和 QDataStream,序列化器是一种只负责读取或者写入对象的对象,Qt的QTextStream序列化器用于读写人可读的文件,而QDataStream序列化器用于读写结构化的二进制数据,这些类用 序列化模式实现的,被用于C++和Qt中,序列化器模式的思想是将I/O代码与类本身分开
反模式:软件设计反模式:输入杂乱、接口膨胀、竞争风险,面向对象设计反模式:循环依赖性、"上帝"对象(具有太多信息或者太多责任的对象),编程反模式:难以编码、魔幻数字、魔幻字符串,方法学反模式:复制--粘贴编程、一切从头开始
第8章 QObject,QApplication,信号和槽
QObject是Qt库中许多重要的类的基类,如QEvent,QApplication,QLayout和QWIDget,一个QObject可以有一个父对象和一些子对象,这是组合模式的另一种实现方式,它可以使用信号和槽,即观察者模式的一种实现,与其他QObject通信
QObject没有公有的复制函数或复制赋值运算符,向下到QObject类定义的结尾处有一个宏Q_DISABLE_COPY(QObject),它显式地确保任何QObject都不能被复制,这种不带复制构造函数策略的一个直接后果就是永远无法通过值传递方式向函数传递QObject
每个QObject都可以有(至多)一个父QObject,且可以拥有任意数量的子QObject,每个QObject都将指向各个子对象的指针存放在一个QObjectList中
每个QObject父对象都会管理自己的子对象,在调用QObject的析构函数时会自动销毁该对象的子对象,子对象列表会在各个QObject对象之间建立一种双向的关联:每个父对象都知道它的子对象的地址,每个子对象都知道其父对象的地址
给某个对象设置父对象,将会隐含地把此对象添加到父对象的子对象列表之中,重父化:把A对象设置B对象为父对象,会把A对象指针添加到B的子列表中,如果再把A对象设置C对象为父对象,A的指针会从B的子列表中删除,然后添加到C的子列表中
不应将父对象和基类混为一谈,父--子关系是为了描述对象运行时的约束和管理关系,基类派生关系是编译时各个类进行判定的一种静态关系
没有父对象的QObject应当在程序栈区中进行定义,哪些有父对象的QObject则应当在堆区动态创建出来
8.1 值和对象
C++类型可以分成两类:值类型和对象类型
值类型的例子有:Anything*,int,char,QString,QDate 和 QVariant(QVariant是一种特殊的联合体类型,可保存所有可复制的内置类型和编程人员定义的类型,QVariant已支持的类型:QList,QImage,QString,QMap,QHash类型),带有公有默认构造函数、复制构造函数和复制赋值运算符的任何类都是值类型的,QObject 的设计人员毫不犹豫地采用了"无复制"策略,该方法就是将赋值运算符与复制构造函数设置为private类型
在栈区创建 QList、QString、QHash、QImage或者其他 与 QVariant相关类型,Qt为你完成引用计数和内存管理
8.2 组合模式:父对象和子对象
**复合对象是包含可以包含子对象的类,组件对象是可以拥有一个父对象的类,**许多Qt类都用到了组合模式:QObject、QWIDget、QTreeWidgetItem、QDomNode、QHelpContentItem和QResource,在任何基于树的结构体中都可以找到组合模式
每个QObject都可以有不限数量的QObject子对象,这些子对象的地址会存放在一个特殊的QObject指针容器内,子对象在该列表中的出现次序是它们在添加到该列表中时的次序,QObject还提供两个名称为findChildren()的重载(递归)函数,每个都会返回一个满足特定条件的子对象列表
8.3 QApplication和事件循环
观察者模式,当任意数据模型对象发生状态改变时,就需要一种间接的方式来提醒观察者,观察者就是一些正在监听状态变化事件的对象
Qt的QEvent类封装了底层事件的概念,QEvent类是若干特定的事件类的基类,QEvent对象可以由窗口系统创建以响应用户的动作,事件循环是一个程序结构,它能够将事件划分优先级,排队并分派给一些对象,事件循环通常会一直运行,直到遇到某个终止事件,QApplication::exec()函数,应用程序的这个工作部分开始于该函数的调用,终止于该函数的返回
事件可认为是低级消息,目标是某个特定的对象,信号可以认为是高级消息,很可能会连接到许多槽上,只有在事件循环,信号才发送到槽上,这里的信号是指对事件进行封装的信号
8.4 Q_OBJECT
QObject支持一些普通C++对象通常所没有的特性:信号和槽;元对象、元属性、元方法;qobject_cast
编写C++代码和qmake工程文件时应该遵守的一些指导原则 :每个类的定义都应该放在各自对应的.h文件中;每个类的实现都应当放在相应的.cpp文件中;为避免头文件的多次包含,头文件应该封装起来;每个.cpp源文件都应当列举在工程文件的SOURCES变量中;每个头文件都应当列举在.pro工程文件的HEADERS变量中;Q_OBJECT宏必须出现在每个QObject派生类定义的头文件中
每个Q_OBJECT宏都会产生代码,需要使用元编译器moc进行预处理,QObject类应该是其基类列表中的第一个基类
8.5 信号和槽
信号是在类定义中给出的,类似于void函数声明的一种消息,它有参数列表却没有函数体,信号是一个类的接口的一部分,它看起来像函数,但不用同样的方式进行调用---它被此类的对象发射
**槽通常是一个void成员函数,**它可以像普通的成员函数一样进行调用,或者可以由QMetaObject系统进行间接调用
一个对象的信号可以与一个或多个对象的槽相连接,前提是这些对象存在并且参数列表从信号到槽都是赋值兼容的