“在哪里走散,你都会找到我~”
前篇,我们仅仅对Qt创建了第一个简单的项目。相比于使用其他IDE创建工程项目,Qt会为自动创建诸如:.pro、.h\.cpp、.iu等文件,这些文件到底是什么?我们在使用Qt时 应该怎样去看待?
——前言
Qt项目文件解析
(1) .pro文件
当我们将工程文件创建好了之后,在⼯程⽬录列表中有⼀个后缀为”.pro” 的⽂件,这个“.pro”文件就是工程文件。它是由qmake自动产生的,用于生产makefile配置的文件。
什么是makefile?
一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。
makefile在Linux中使用得较为频繁,其工作目的就是完成源文件编译。在Qt Creator中已经把整个过程中的编译细节封装好了,对于使用者的我们来说,不用在意里面的内容:
(2)widget \main.cpp⽂件解析
当我们使用Qt Creator创建项目时,会自动为我们写好完整调用的main函数。
在Qt中,着重强调类的封装。Qt ⼀个类对应⼀个头⽂件,类名 就是 头⽂件名。
QApplication 为应⽤程序类: 要想编写一个Qt的图形化界面程序,必须要有一个QApplication对象。
除此之外,还会为我们创建在新建项目时,选择的“Widget”:
这里提到了两个概念,一个是“Q_OBJECT”,另一个是“对象树”。
Q_OBJECT宏:
这是一个Qt内置的一个宏。当代码被替换展开后,就是一堆代码块。Qt中一个很重要的机制就是“信号和槽”。如果想要使用这一个机制,就必须包含这个宏。
对象树:
Qt中引入了“对象树”机制。这个树到底是做什么的呢?我们在这里就把它简单地认为是一个对象资源管理的机制。当我们创建一个Qt对象,就可以将它挂在对象树上,由它来控制这个资源的释放销毁。似乎同“垃圾回收”机制类似,但它对性能的影响很小。
(3)widget.ui ⽂件解析
当我们点击这个文件时,Qt Creator会为我们Qt Design上:
当我们再次返回到编辑,点击这个.ui文件时,就会变成这样:
如果你了解过前端,那么你看到这样神似的代码,似乎会联想到“.html”。不过,虽然它们极其相似,但.ui文件是由”xml”格式输写的。
在xml中,有哪些标签,表示什么含义都是通过程序员自定义的。此处的xml中的标签,就是大佬们开发的专属Qt的标签。至于每个标签是啥含义呢,并不需要我们去关心,我们只需要知道.ui文件本质上是一个xml格式的文件即可。
当我们对当前.ui文件进行编译,打开左上方项目的“展开Expoler”:
找到同层目录下的新目录。这些以“build-xx”开头的新目录,这是我们将Qt程序启动后,自动生成的临时文件:
我们打开ui文件:
所以,ui文件的本质,最终会被Qt Creator翻译成C++文件,并编译到可执行程序之中。
其中,我们还能看到由qmake自动生成的makefile。
Qt对象树
在 Qt 中创建很多对象的时候会提供⼀个 Parent 对象指针,这些Parent指针都需要被进行构造,可是,为什么需要构造这些Parent指针呢?
对于C\C++ 程序员而言,该语言为了追求性能,并没有提供类似“垃圾回收”的机制。所以,当使用程序申请堆上空间、或者是文件描述符、套接字等系统资源,需要由程序员手动回收。可是!只要是人工操作,就可能失误,就会出现申请的资源不能得到及时释放,从而让系统内的资源被占用,系统剩余资源越来越少,导致机器变卡甚至宕机……上述的种种,换句话说,也就是“资源泄露”。
(1) QObject
在Qt中,QObject是对象模型的核心。它是以“对象树”的形式组织起来的。
当创建一个QObject对象时,会看到 QObject 的构造函数接收⼀个 QObject 指针作为参数,这个参数就是 parent,也就是⽗对象指针。
这相当于,在创建 QObject 对象时,可以提供⼀个其⽗对象,我们创建的这个 QObject 对象会⾃动添加到其⽗对象的 children() 列表。
当⽗对象析构的时候,这个列表中的所有对象也会被析构。
如何理解QWidget 是能够在屏幕上显⽰的⼀切组件的⽗类?
QWidget 继承自QObject。当然不止QWidget,几乎所有的类对象都会去继承这个QObject。也是因为这种继承,也继承了这种对象树的关系。
使用对象树,把这些内容组织起来,等到合适的时机(窗口关闭\进程结束等等),把这些对象统一进行释放。
•Qt 引⼊对象树的概念,在⼀定程度上解决了内存问题。
释放规则:
当⼀个 QObject 对象在堆上创建的时候,Qt 会同时为其创建⼀个对象树,而对象树中对象的
顺序是没有定义的。 任何对象树中的 QObject 对象 delete 的时候,如果这个对象有 parent,则⾃动将其从 parent 的children() 列表中删除;如果有孩⼦,则⾃动 delete 每⼀个孩⼦。
(2) 自定义类挂对象树
比如现如今,我们想要我们自定义的类MyLabel,继承QLabel,并尝试将其挂在对象树上:
Qt 窗⼝坐标体系 与 日志输出
坐标体系:以左上⻆为原点(0,0),X向右增加,Y向下增加。其中(0,0)坐标的位置指的是Widget对象的左上角。
我们在.ui文件中,能看到的“画板”,其本质上就是QWidget窗口:
我们在这个窗口中添加一个”按钮Button”:
我们还可以通过代码的方式,创建一个Button,并把它显示在最终程序运行的窗口上:
编码问题:
现在,我们想使用std::cout 作为日志输出打印在Qt Creator中的观察台中:
我们会发现,从屏幕输出的文字完完全全是乱码!
关于乱码的问题,有且仅有一个原因,就是编码方式不匹配!目前汉字字符集最常见的两种方式就是:UTF-8(utf8) 和 GBK。我们Windows简体中文版自带的就是按照GBK的编码方式,对汉字进行翻译的。相反Linux中,使用的汉字编码集为utf8。
GBK. 使用两个字节表示一个汉字。
UTF-8/utf8 变长编码。表示一个符号,使用的字节数有变化,2~4。但汉字一般又3个字节表示。
因此,在Qt中如果想要通过打印日志的方式,观察程序、调试信息,最好使用Qt提供的qDebug。虽然cout也不是不能用,但是std::cout内部不会对编码作任何处理,在持有不同编码集中使用,会导致乱码;