QT基础入门
QT入门
- 创建qt项目
- 打印helloworld
- 使用 "按钮" 实现
- 使用标签实现
- 项目文件解析
- pro 文件解析
- widget.h 文件解析
- main.cpp 文件解析
- widget.cpp 文件解析
- widget.ui 文件解析
- Qt Creator 中的快捷键
- 使用帮助文档
- 认识对象模型(对象树)
- Qt 窗口坐标体系
创建qt项目
- qmake与cmake类似与自动给我们生成一个类似于Linux的Makefile文件来进行文件编译。
- 其中Widget是我们要创建的类名字,你可以选择它继承与谁,这里我们选继承QWidget
- 这一步是用来选择语法的为了走向国际化这里我们直接下一步就可以
- 选择对应的编译器
- 点击完成即可
- 创建之后
打印helloworld
使用 “按钮” 实现
纯代码实现:
可视化操作实现
- 双击:" widget.ui " 文件;
- 拖拽控件至 ui 界面窗口并修改内容;
- 构建并运行,效果如下所示:
使用标签实现
纯代码实现
可视化操作实现:
与上面步骤一致
项目文件解析
pro 文件解析
工程新建好之后,在工程目录列表中有一个后缀为 “.pro” 的文件, “.pro” 文件就是工程文件 (project)它是 qmake 自动生成的用于生产 makefile 的配置文件。如图所示:
主要内容如下
QT += core gui // Qt 包含的模块
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets //大于 Qt4 版本才包含 widget 模块
TARGET = QtFirst //应用程序名生成的 .exe 程序名称
TEMPLATE = app //模板类型,应用程序模板
SOURCES += main.cpp\ //源文件
widget.cpp //源文件
HEADERS += widget.h //头文件
“.pro” 文件的写法如下:
- 注释:从 “#” 开始,到这一行结束。
- QT += core gui // Qt 包含的模块 Qt5 包含的模块如下图所示:
- greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 这条语句的含义是,如果QT_MAJOR_VERSION 大于 4 也就是当前使用的 Qt5 及更高版本) 需要增加 widgets 模块。如果项目仅需支持 Qt5 , 也可以直接
添加 “QT += widgets” 一句。不过为了保持代码兼容 ,最好还是按照 QtCreator 生成的语句编写。 - 指定生成的应用程序名:TARGET = QtDemo
- TEMPLATE = app //模板。告诉 qmake 为这个应用程序生成哪种 makefile。下面是可供选择的模板:
- app:建立一个应用程序的 makefile。这是默认值,所以如果模板没有被指定,这个将被使用。
- lib :建立一个库的 makefile。
- vcapp:建立一个应用程序的 VisualStudio 项目文件。
- vclib: 建立一个库的 VisualStudio 项目文件。
- subdirs:这是一个特殊的模板,它可以创建一个能够进入特定目录的 makefile 并且为它调用make 的 makefile。
- 工程中包含的源文件:SOURCES += main.cpp/widget.cpp
- 工程中包含的头文件:HEADERS += widget.h
- 工程中包含的资源文件:RESOURCES += painter.qrc
- 工程中包含的 “ui” 设计文件:FORMS += widget.ui
10.配置信息:CONFIG += c++11 (使用 c++11 的特性) CONFIG 用来告诉 qmake 关于应用程序的配置信息。
widget.h 文件解析
在Qt中,如果要使用信号与槽(signal 和 slot)的机制 就必须加入 Q_OBJECT 宏;
Ui::Widget *ui; 这个指针是用前面声明的 namespace Ui 里的 Widget 类定义的,所以指针 ui 是指向可视化设计的界面,后面要访问界面上的组件,都需要通过这个指针 ui 去访问。
main.cpp 文件解析
说明:
- Qt 系统提供的标准类名 声明头文件没有 .h 后缀;
- Qt 一个类对应一个头文件,类名 就是 头文件名;
- QApplication 为应用程序类;QApplication a;(a为应用程序对象,有且仅有一个。)
- QApplication 管理图形用户界面应用程序的控制流和主要设置。
- QApplication 是 Qt 的整个后台管理的命脉。它包含主事件循环,在其中来自窗口系统和其它资源的所有事件处理和调度。它也处理应用程序的初始化和结束,并且提供对话管理。
- 对于任何一个使用 Qt 的图形用户界面应用程序,都正好存在一个 QApplication 对象,而不论这个应用程序在同一时间内是不是有 0、1、2 或更多个窗口。
- Widget w; //实例化窗口对象
- w.show(); //调用show函数显示窗口
- a.exec() :程序进入消息循环,等待对用户输入进行响应。这里 main()把控制权转交给Qt,Qt 完成事件处理工作,当应用程序退出的时候 exec() 的值就会返回。在 exec() 中,Qt 接受并处理用户和系统的事件并且把它们传递给适当的窗口部件。
widget.cpp 文件解析
widget.cpp 文件是类 Widget 的实现代码,所有在窗体上要实现的功能添加在此文件中;
widget.ui 文件解析
widget.ui 是窗体界面定义文件,是一个 XML 文件,定义了窗口上的所有组件的属性设置、布局,及其信号与槽函数的关联等。用 UI 设计器可视化设计的界面都由 Qt 自动解析,并以 XML 文件的形式保存下来。在设计界面时,只需在 UI 设计器里进行可视化设计即可,而不用管 widget.ui 文件是怎么生成的。
Qt Creator 中的快捷键
- 注释:ctrl + /
- 运行:ctrl + R
- 编译:ctrl + B
- 字体缩放:ctrl + 鼠标滑轮
- 查找:ctrl + F
- 整行移动:ctrl + shift + ⬆/⬇
- 帮助文档:F1
- 自动对齐:ctrl + i;
- 同名之间的 .h 和 .cpp 的切换:F4
- 生成函数声明的对应定义: alt + enter
使用帮助文档
- 标放到要查询的类名/方法名上, 直接按 F1
- Qt Creator 左侧边栏中直接用鼠标单击 “帮助” 按钮:
认识对象模型(对象树)
在 Qt 中创建很多对象的时候会提供一个 Parent 对象指针,下面来解释这个 parent 到底是干什么的。
- QObject 是以对象树的形式组织起来的。
- 当创建一个 QObject 对象时,会看到 QObject 的构造函数接收一个 QObject 指针作为参数,这个参数就是 parent,也就是父对象指针。
- 这相当于,在创建 QObject 对象时,可以提供一个其父对象,我们创建的这个 QObject 对象会自动添加到其父对象的 children() 列表。
- 当父对象析构的时候,这个列表中的所有对象也会被析构。(注意,这里的父对象并不是继承意义上的父类!)
- QWidget 是能够在屏幕上显示的一切组件的父类。
- QWidget 继承自 QObject ,因此也继承了这种对象树关系。一个孩子自动地成为父组件的一个子组件。因此,它会显示在父组件的坐标系统中,被父组件的边界剪裁。例如,当用户关闭一个对话框的时候,应用程序将其删除,那么,我们希望属于这个对话框的按钮、图标等应该一起被删除。事实就是如此,因为这些都是对话框的子组件。
- 当然,我们也可以自己删除子对象,它们会自动从其父对象列表中删除。比如,当我们删除了
一个工具栏时,其所在的主窗口会自动将该工具栏从其子对象列表中删除,并且自动调整屏幕显示。
Qt 引入对象树的概念,在一定程度上解决了内存问题:
- 当一个 QObject 对象在堆上创建的时候,Qt 会同时为其创建一个对象树。不过,对象树中对象的顺序是没有定义的。这意味着,销毁这些对象的顺序也是未定义的。
- 任何对象树中的 QObject 对象 delete 的时候,如果这个对象有 parent,则自动将其从 parent 的children() 列表中删除;如果有孩子,则自动 delete 每一个孩子。Qt 保证没有 QObject 会被delete 两次,这是有析构顺序决定。
如果 QObject 在栈上创建,Qt 保持同样的行为。正常情况下,这也不会发生什么问题。来看下面的代码片段:
作为父组件的 window 和作为子组件的 quit 都是 QObject 的子类(事实上,它们都是QWidget的子类,而QWidget 是 QObject 的子类)。这段代码是正确的,quit 的析构函数不会被调用两次,因为标准 C++ 要求,局部对象的析构顺序应该按照其创建顺序的相反过程。因此,这段代码在超出作用域时,会先调用 quit 的析构函数,将其从父对象 window 的子对象列表中删除,然后才会再调用window 的析构函数。
但是,如果我们使用下面的代码:
情况又有所不同,析构顺序就有了问题。我们看到,在上面的代码中,作为父对象的 window 会首先被析构,因为它是最后一个创建的对象。在析构过程中,它会调用子对象列表中每一个对象的析构函数,也就是说, quit 此时就被析构了。然后,代码继续执行,在 window 析构之后,quit 也会被析
构,因为 quit 也是一个局部变量,在超出作用域的时候当然也需要析构。但是,这时候已经是第二次调用 quit 的析构函数了,C++ 不允许调用两次析构函数,因此,程序崩溃了。
由此我们看到,Qt 的对象树机制虽然在一定程度上解决了内存问题,但是也引入了一些值得注意的事情。
Qt对象树如图:
Qt 窗口坐标体系
坐标体系:以左上⻆为原点(0,0),X向右增加,Y向下增加。
对于嵌套窗⼝,其坐标是相对于⽗窗⼝来说的。