摘要

我们使用的标准 C++,其设计的对象模型虽然已经提供了非常高效的 RTTI 支持,但是在某些方面还是不够灵活。比如在 GUI 编程方面,既需要高效的运行效率也需要强大的灵活性,诸如删除某窗口时可不想把子窗口用代码一个个去析构。Qt 将这两者的优点完美的结合在了一起,创造出了特有的对象模型(Qt Object Model)。


一,Qt的基本框架

在上一篇中,我们已经完成了Qt的安装和VS的环境配置。QT从入门到入土(一)——Qt5.14.2安装教程和VS2019环境配置 - 唯有自己强大 - 博客园 (cnblogs.com)

在讲解对象树之前,我们先来熟悉一下Qt的基本框架。首先新建一个项目:

  •  main.cpp分析

打开sources里面的main.cpp,可以看到以下代码:

注意:

  1. 每个Qt程序有且只能有一个QApplication对象,没有会报错。
  2. Qt里面的头文件和类名是一致的,知道头文件就知道类名,反之亦然
  3. Qt头文件是没有.h的,基本都是以大写的Q开头

根据以上的分析,我们可以得出Qt的程序框架代码:

#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
/*
在这里写你的代码
*/
return a.exec();
}
  • widget.h和widget.cpp分析

打开Headers里面的widget.h,和sources里面的widget.app,可以看到以下代码:

最上面的MyfirstQt.pro,是管理项目的文件,用来存储项目设置。

后缀为“.pro”的文件是项目的管理文件,文件名就是项目的名称,如本项目中的 MyfirstQt.pro。(类似与VS工程的.sln文件)

实例(用代码创建一个button):

帮助文档的快捷键:第一种方式:F1 第二种方式:Qt左侧按钮 第三种方式:D:\Qt\Qt5.14.2\5.14.2\mingw73_64\bin\assistant

因为创建一个button需要QPushButton 类,因此我们可以在帮助文档中查到相关的信息:

代码实现:

#include "widget.h"
#include "ui_widget.h"
#include<QPushButton>//按钮控件的头文件 Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this); //创建第一个按钮
QPushButton *btn=new QPushButton;
//不能用btn->show();//show是以顶层方式弹出控件
//让btn在widget窗口显示
btn->setParent(this);//this指向当前对象的指针(即widget的地址)
//显示文本
btn->setText("第一个按钮");
//创建第二个按钮
//注意:这种方法是按照按钮的大小创建窗口
QPushButton *btn2=new QPushButton("第二个按钮",this);
//移动btn2的位置(由于创建的两个按钮位置重叠了)
btn2->move(100,100);
//因此需要重置窗口大小
resize(600,400); //设置窗口标题
setWindowTitle("唯有自己强大");
}

二,对象模型(对象树)

什么是对象树?

我们常常听到 QObject 会用对象树来组织管理自己,那什么是对象树?

这个概念非常好理解。因为 QObject 类就有一个私有变量 QList<QObject *>,专门存储这个类的子孙后代们。比如创建一个 QObject 对象并指定父对象时,就会把自己加入到父对象的 childre() 列表中,也就是 QList<QObject *> 变量中。

父对象析构的时候,这个列表中的所有对象也会被析构。(注意,这 里的父对象并不是继承意义上的父类!)

举个例子,有一个窗口 Window,里面有 Label标签、TextEdit文本输入框、Button按钮这三个元素,并且都设置 Window 为它们的父对象。这时候我做了一个关闭窗口的操作,作为程序员的你是不是自然想到将所有和窗口相关的对象析构啊?古老的办法就是一个个手动 delete 呗。是不是很麻烦?Qt 运用对象树模式,当父对象被析构时,子对象自动就 delete 掉了,不用再写一大堆的代码了。

QWidget 是能够在屏幕上显示的一切组件的父类(QWidget 继承自 QObject,因此也继承了这种对象树关系。)

注意构建/析构 QObject 的顺序问题

正常情况下,最后被创建出来的会先被析构掉。就好比我有一个大桌子,上面先摆放一个盘子,再摆放一个碗。当我要把桌子撤掉的时候,会先撤掉碗,再撤掉盘子,最后撤掉桌子。

用代码来演示一下:

int main()
{
QWidget window;
QPushButton quit("Quit", &window);
}

后创建的 quit 对象指定了 window 为其父对象。那么关闭程序时,会先调用它的析构函数,然后调用 window 的析构函数。

这就牵扯到一个特殊情况:

int main()
{
QPushButton quit("Quit");
QWidget window; quit.setParent(&window);
}

如果反过来,由于 window 后创建,程序关闭时先调用 window 的析构函数(此时 quit 被第一次析构)。接着调用 quit 的析构函数(此时 quit 被第二次析构),这时由于被两次析构,所以出问题了。

这种特殊情况在编程中很隐蔽,不容易发现。因为编译的时候不会报错,只有运行时才会产生问题。

我们最好从开始就养成良好习惯,在 Qt 中,尽量在构 造的时候就指定 parent 对象,并且大胆在堆上创建。

三,Qt窗口坐标体系

Qt的窗口坐标系以左上角为原点,X 向右增加,Y 向下增加。(和opencv一样)

对于嵌套窗口,其坐标是相对于父窗口来说的。

QT从入门到入土(二)——对象模型(对象树)和窗口坐标体系的更多相关文章

  1. Qt对象模型之二:对象树与元对象系统

    一.对象树的概念 Qt中使用对象树(object tree)来组织和管理所有的QObject类及其子类的对象.当创建一个QObject时,如果使用了其他的对象作为其父对象(parent),那么这个 Q ...

  2. QT从入门到入土(三)——信号和槽机制

    摘要 信号槽是 Qt 框架引以为豪的机制之一.所谓信号槽,实际就是观察者模式.当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号 (signal).这种发出是没有目的的,类似广播 ...

  3. QT从入门到入土(四)——多线程(QtConcurrent::run())

    引言 在前面对Qt多线程(QThread)做了详细的分析:QT从入门到入土(四)--多线程(QThread) - 唯有自己强大 - 博客园 (cnblogs.com) 但是最近在做项目时候,要将一个函 ...

  4. QT从入门到入土(一)——Qt5.14.2安装教程和VS2019环境配置

    引言 24岁的某天,承载着周围人的关心,一路南下.天晴心静,听着斑马,不免对未来有些彷徨.但是呢,人生总要走陌生的路,看陌生的风景,所幸可以听着不变的歌,关心自己的人就那么多.就像是对庸常生活的一次越 ...

  5. QT从入门到入土(八)——项目打包和发布

    引言 新手上路可谓是困难重重,你永远不知道下一个困难会在什么时候出现,在完成了运动控制卡封装发布过程中可谓是举步维艰.因此记录一下qt5+vs2019的打包发布方法. 打包一般分为两步: 将编译后的e ...

  6. QT从入门到入土(三)——文件的读写操作

     引言 文件的读写是很多应用程序具有的功能,甚至某些应用程序就是围绕着某一种格式文件的处 理而开发的,所以文件读写是应用程序开发的一个基本功能. Qt 提供了两种读写纯文本文件的基本方法: 用 QFi ...

  7. QT从入门到入土(四)——多线程

    引言 前面几篇已经对C++的线程做了简单的总结,浅谈C++11中的多线程(三) - 唯有自己强大 - 博客园 (cnblogs.com).本篇着重于Qt多线程的总结与实现. 跟C++11中很像的是,Q ...

  8. QT从入门到入土(九)——TCP/IP网络通信(以及文件传输)

    引言 TCP/IP通信(即SOCKET通信)是通过网线将服务器Server端和客户机Client端进行连接,在遵循ISO/OSI模型的四层层级构架的基础上通过TCP/IP协议建立的通讯.控制器可以设置 ...

  9. QtCore是Qt的精髓(包括五大模块:元对象系统,属性系统,对象模型,对象树,信号槽)

    作者:小豆君的干货铺链接:https://www.zhihu.com/question/27040542/answer/218384474来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业 ...

随机推荐

  1. 重新整理 .net core 实践篇————配置系统之盟约[五]

    前言 在asp .net core 中我们会看到一个appsettings.json 文件,它就是我们在服务中的各种配置,是至关重要的一部门. 不管是官方自带的服务,还是我们自己编写的服务都是用它来实 ...

  2. scrapy奇技淫巧1

    Request传递值到callback回调函数 def parse(self, response): request = scrapy.Request('http://www.example.com/ ...

  3. XShell本地上传文件到Ubuntu上及从Ubuntu下载文件到本地

    使用XShell本地上传文件到Ubuntu上及从Ubuntu下载文件到本地. 1.第一种方法是最常用的 :如果下载了Xshell和Xftp,Ctrl+Alt+F就可以选择文件的互传了!(虚拟机/云服务 ...

  4. IOS IAP 自动续订 之 利用rabbitmq延时队列自动轮询检查是否续订成功

    启用针对自动续期订阅的服务器通知: - 官方地址: - https://help.apple.com/app-store-connect/#/dev0067a330b - 相关字段, 相关类型地址:  ...

  5. clone() java 简单的复制

      Java的复制有的 deepcopy 和 shapecopy 之分,这里简单的采用shapecopy  的 clone ( ) 方法, 但是指向的是同一个对象, 关于对象的问题,这里不做展开: / ...

  6. 'utf-8' codec can't decode byte 0xd5 in position XXX: invalid continuation byte问题

    找了一下午,各种资料搜集,愣是没搜出来答案. 结果今天早上,做一个小小的改变,就整出来了... 步骤如下: 1.打开excel,全选数据 2.新建记事本,粘贴,选择脚本,更改字体: 3.新建Excel ...

  7. OpenGL在图形管道中调用了什么用户模式图形驱动程序(UMD)?

    OpenGL在图形管道中调用了什么用户模式图形驱动程序(UMD)? 图形硬件供应商,需要为显示适配器编,编写用户模式显示驱动程序.用户模式显示驱动程序,是由Microsoft Direct3D运行时加 ...

  8. MinkowskiBroadcast广播

    MinkowskiBroadcast广播 MinkowskiBroadcastAddition广播加法 class MinkowskiEngine.MinkowskiBroadcastAddition ...

  9. 人工智能AI智能加速卡技术

    人工智能AI智能加速卡技术 一. 可编程AI加速卡 1. 概述: 这款可编程AI加速器卡具备 FPGA 加速的强大性能和多功能性,可部署AI加速器IP(WNN/GNN,直接加速卷积神经网络,直接运行常 ...

  10. vulhub-struct2-s2-005

    0x00 漏洞原理   s2-005漏洞的起源源于S2-003(受影响版本: 低于Struts 2.0.12),struts2会将http的每个参数名解析为OGNL语句执行(可理解为java代码).O ...