Qt:项目文件解析

目录

QWidget基础项目文件解析

.pro文件解析

widget.h文件解析

widget.cpp文件解析

widget.ui文件解析

main.cpp文件解析

认识对象模型

窗口坐标系


QWidget基础项目文件解析

.pro文件解析

工程新建好之后,在工程目录列表中有⼀个后缀为 ".pro" 的文件, ".pro" 文件就是工程文件 (project),它是 qmake 自动生成的用于生产 makefile 的配置文件。

双击进入该文件,该文件的核心内容如下: 

QT       += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
DEFINES += QT_DEPRECATED_WARNINGS
TARGET = QtTest
TEMPLATE = appSOURCES += \main.cpp \widget.cppHEADERS += \widget.hFORMS += \widget.ui
  • 注释:从"#"开始,直到该行结束
  • QT += core gui:Qt包含的模块

  • greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

这条语句的含义是,若QT_MAJOR_VERSION大于4,即当前使用的Qt5及更高版本,需要增加widgets模块。若项目仅需支持Qt5,也可以直接添加"QT += widgets"⼀句。不过为了保持代码兼容,最好还是按照Qt Creator生成的语句编写。

  • CONFIG += c++11

CONFIG用来告诉qmake关于应用程序的配置信息,上述语句说明使用c++11的特性

  • DEFINES += QT_DEPRECATED_WARNINGS

定义编译选项。QT_DEPRECATED_WARNINGS表示当Qt的某些功能被标记为过时的,那么编译器会发出警告。

  • TARGET = QtTest:指定生成的应用程序名
  • 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

widget.h文件解析

在Qt中,若要使用信号与槽(signal和slot)的机制就必须加入Q_OBJECT宏。

Ui::Widget *ui;这个指针是用前面声明的namespace Ui中的Widget类定义的(不是同一个Widget),所以指针ui指向可视化设计的界面,后面要访问界面上的组件,都需要通过这个指针ui去访问。

Ui:Widget继承自Ui_Widget类,Ui_Widget类位于ui_widget.h文件中,ui_widget.h文件是对widget.ui文件编译后自动生成的。


widget.cpp文件解析

widget.cpp文件是类Widget的实现代码,所有在窗体上要实现的功能添加在此文件中


widget.ui文件解析

widget.ui是窗体界面定义文件,是一个XML文件,定义了窗口上的所有组件的属性设置、布局,及其信号与槽函数的关联等。用UI设计器可视化设计的界面都由Qt自动解析,并以XML文件的形式保存下来。在设计界面时,只需在UI设计器里进行可视化设计即可,而不用管widget.ui文件是怎么生成的。


main.cpp文件解析

使用 Qt Creator 新建任意工程之后,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 接受并处理用户和系统的事件并且把它们传递给适当的窗口部件。

认识对象模型

在Qt中创建很多对象的时候会提供一个parent对象指针,这个parent到底是干什么的呢?

QObject是以对象树的形式组织起来的

  • 当创建一个QObject对象时,会看到QObject的构造函数接收⼀个QObject指针作为参数,这个参数就是parent,即父对象指针
  • 在创建QObject对象时,可以提供⼀个其父对象,创建的这个QObject对象会自动添加到其父对象的children()列表
  • 当父对象析构的时候,这个列表中的所有对象也会被析构(这里的父对象并不是继承意义上的父类)

这种机制在GUI程序设计中相当有用。如,一个按钮有一个QShortcut(快捷键)对象作为其子对象。当删除按钮的时候,这个快捷键理应被删除,这是合理的。

QWidget是能够在屏幕上显示的一切组件的父类

  • QWidget继承自QObject,因此也继承了这种对象树关系。一个孩子自动地成为父组件的⼀个子组件。因此,它会显示在父组件的坐标系统中,被父组件的边界剪裁。如:当用户关闭⼀个对话框的时候,应用程序将其删除,我们希望属于这个对话框的按钮、图标等应该⼀起被删除。因为这些都是对话框的子组件。
  • 我们也可以自己删除子对象,它们会自动从其父对象列表中删除。如:当删除了一个工具栏时,其所在的主窗口会自动将该工具栏从其子对象列表中删除,并且自动调整屏幕显示。

对象树机制一定程度上解决了内存问题

  • 当一个QObject对象在堆上创建的时候,Qt会同时为其创建一个对象树。不过对象树中对象的顺序是没有定义的,即销毁这些对象的顺序也是未定义的
  • 任何对象树中的QObject对象delete时,若这个对象有parent,则自动将其从parent的children()列表中删除;若有孩子,则自动delete每一个孩子。Qt保证没有QObject会被delete两次,这是由析构顺序决定的

若QObject在栈上创建,Qt保持同样的行为。正常情况下也不会发生什么问题

作为父组件的window和作为子组件的quit都是QObject的子类。这段代码是正确的,quit的析构函数不会被调用两次,因为标准C++要求,局部对象的析构顺序应该按照其创建顺序的相反过程。因此,这段代码在超出作用域时,会先调用quit的析构函数,将其从父对象window的子对象列表中删除,然后才会再调用window的析构函数

上述代码的析构顺序就有了问题。在上面的代码中,作为父对象的window会先被析构,因为它是最后一个创建的对象。在析构过程中,它会调用子对象列表中每一个对象的析构函数,即quit此时就被析构了。然后代码继续执行,在window析构之后,quit也会被析构,因为quit也是⼀个局部变量,在超出作用域的时候当然也需要析构。但是,这时候已经是第⼆次调用quit的析构函数了,C++不允许调用两次析构函数,因此,程序崩溃了。

自定义MyPushButton类观察释放过程

mypushbutton.h:

#ifndef MYPUSHBUTTON_H
#define MYPUSHBUTTON_H#include <QPushButton>
#include <QDebug>class MyPushButton : public QPushButton
{Q_OBJECT
public:explicit MyPushButton(QWidget *parent = nullptr);~MyPushButton();//添加MyPushButton类的析构函数signals:};#endif // MYPUSHBUTTON_H

mypushbutton.cpp:

#include "mypushbutton.h"MyPushButton::MyPushButton(QWidget *parent) : QPushButton(parent)
{qDebug() << "我的按钮的构造函数被调用";
}MyPushButton::~MyPushButton()
{qDebug() << "我的按钮的析构函数被调用";
}

widget.cpp:

#include "widget.h"
#include "ui_widget.h"
#include "mypushbutton.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);MyPushButton* button = new MyPushButton(this);//传入this,将其设置到对象树中,当窗口关闭时就会自动调用其析构函数button->setText("我的按钮");
}Widget::~Widget()
{qDebug() << "Widget的析构函数被调用";delete ui;
}

对象树确保的是先释放子节点的内存,后释放父节点的内存。而析构函数的调用顺序则不⼀定遵守上述要求,因此看到子节点的析构执行顺序反而在父节点析构顺序之后

注意:调用析构函数和释放内存并非是同一件事情

总结:

Qt的对象树机制虽然在⼀定程度上解决了内存问题,但是也引入了⼀些值得注意的事情。这些细节在今后的开发过程中很可能时不时跳出来烦扰一下,所以最好从开始就养成良好习惯

注意:在Qt中,尽量在构造的时候就指定parent对象,并且大胆在堆上创建


窗口坐标系

坐标体系:以左上角度为原点(0,0),X向右增加,Y向下增加

对于嵌套窗口,其坐标是相对于父窗口而言的

可以使用代码设置控件在坐标系中的位置

#include "widget.h"
#include "ui_widget.h"
#include "mypushbutton.h"
#include <QPushButton>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);QPushButton* btn1 = new QPushButton("按钮1", this);btn1->move(200, 300);QPushButton* btn2 = new QPushButton("按钮2", this);qDebug() << "按钮1的坐标为:[" << btn1->x() << "," << btn1->y() << "]";qDebug() << "按钮2的坐标为:[" << btn2->x() << "," << btn2->y() << "]";
}Widget::~Widget()
{delete ui;
}

200与300都代表着像素点

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/14855.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

BiGRU双向门控循环单元多变量多步预测,光伏功率预测(Matlab完整源码和数据)

代码地址&#xff1a;BiGRU双向门控循环单元多变量多步预测&#xff0c;光伏功率预测&#xff08;Matlab完整源码和数据) BiGRU双向门控循环单元多变量多步预测&#xff0c;光伏功率预测 一、引言 1.1、研究背景和意义 随着全球对可再生能源需求的不断增长&#xff0c;光伏…

数据结构与算法-递归

单路递归 二分查找 /*** 主函数&#xff1a;执行二分查找。* * param a 要搜索的数组&#xff08;必须是已排序的&#xff09;* param target 目标值* return 返回目标值在数组中的索引&#xff1b;如果未找到&#xff0c;则返回 -1*/ public static int binarySearch(int[] …

【STM32F1】一种使用通用定时器实现各个通道独立输出不同指定数量脉冲的方法

一种使用通用定时器实现独立通道输出指定数量脉冲的方法 一种使用通用定时器实现独立通道输出指定数量脉冲的方法概述实验平台配置步骤1. 初始化定时器与GPIO2. 设置定时器工作模式3. 编写脉冲计数逻辑4. 调整参数以满足要求注意事项 代码实现电机结构体配置&#xff0c;GPIO配…

【Java基础】序列化、反序列化和不可变类

Hi~&#xff01;这里是奋斗的明志&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f331;&#x1f331;个人主页&#xff1a;奋斗的明志 &#x1f331;&#x1f331;所属专栏&#xff1a;Java基础面经 &#x1f4da;本系列文章为个…

android apk反编译

使用解压工具解压apk&#xff0c;使用dex2jar解析其中的dex文件为jar文件&#xff0c;再使用jd-gui将class反编译为java文件 1 工具下载 dex2jar下载 https://github.com/pxb1988/dex2jar/releases 直接去github上下载最新发布版本 注意&#xff0c;如果后面使用过程中遇到No…

PAT乙级( 1009 说反话 1010 一元多项式求导)C语言版本超详细解析

1009 说反话 给定一句英语&#xff0c;要求你编写程序&#xff0c;将句中所有单词的顺序颠倒输出。 输入格式&#xff1a; 测试输入包含一个测试用例&#xff0c;在一行内给出总长度不超过 80的字符串。字符串由若干单词和若干空格组成&#xff0c;其中单词是由英文字母&#x…

C++20导出模块及使用

1.模块声明 .ixx文件为导入模块文件 math_operations.ixx export module math_operations;//模块导出 //导出命名空间 export namespace math_ {//导出命名空间中函数int add(int a, int b);int sub(int a, int b);int mul(int a, int b);int div(int a, int b); } .cppm文件…

鸿蒙接入支付宝SDK后模拟器无法运行,报错error: install parse native so failed.

鸿蒙项目接入支付宝后&#xff0c;运行提示error: install parse native so failed. 该问题可能由于设备支持的 Abi 类型与 C 工程中的不匹配导致. 官网error: install parse native so failed.错误解决办法 根据官网提示在模块build-profile.json5中添加“x86_64”依然报错 问…

MongoDB开发规范

分级名称定义P0核心系统需7*24不间断运行&#xff0c;一旦发生不可用&#xff0c;会直接影响核心业务的连续性&#xff0c;或影响公司名誉、品牌、集团战略、营销计划等&#xff0c;可能会造成P0-P2级事故发生。P1次核心系统这些系统降级或不可用&#xff0c;会间接影响用户使用…

nodejs - vue 视频切片上传,本地正常,线上环境导致磁盘爆满bug

nodejs 视频切片上传&#xff0c;本地正常&#xff0c;线上环境导致磁盘爆满bug 原因&#xff1a; 然后在每隔一分钟执行du -sh ls &#xff0c;发现文件变得越来越大&#xff0c;即文件下的mp4文件越来越大 最后导致磁盘直接爆满 排查原因 1、尝试将m3u8文件夹下的所有视…

微信小程序如何使用decimal计算金额

第三方库地址&#xff1a;GitHub - MikeMcl/decimal.js: An arbitrary-precision Decimal type for JavaScript 之前都是api接口走后端计算&#xff0c;偶尔发现这个库也不错&#xff0c;计算简单&#xff0c;目前发现比较准确 上代码 导入js import Decimal from ../../uti…

unity学习29:摄像机camera相关skybox 和 Render Texture测试效果

目录 1 摄像机 1.1 每个Scene里都自带一个摄像机 camera 1.2 可以创建多个camera 1.3 下面先看backgroundtype: 2 backgroundtype: 天空盒 skybox 2.1 清除标志,清除&#xff1a;天空盒 自选天空盒 2.2 window /Asset Store 2.3 导入skybox 3 backgroundtype: 纯色…

ximalaya(三) playUriList值解密--webpack

本文主要介绍解密音频播放url参数。 本文仅代表个人理解&#xff0c;如有其他建议可在评论区沟通。 声明 仅仅记录一下自己的学习方法&#xff0c;不作为其他参考、更不作为商业用途。如有侵犯请联系本人删除 目标地址&#xff1a;aHR0cHM6Ly93d3cueGltYWxheWEuY29tL3NvdW5k…

C# Winform怎么设计串口,客户端和相机控件界面显示

首先我们必须把这个类创建好 INIAPI using System; using System.Text; using System.Runtime.InteropServices;namespace Ini {public class IniAPI{#region INI文件操作/** 针对INI文件的API操作方法&#xff0c;其中的节点&#xff08;Section)、键&#xff08;KEY&#x…

【redis】数据类型之hash

Redis中的Hash数据类型是一种用于存储键值对集合的数据结构。与Redis的String类型不同&#xff0c;Hash类型允许你将多个字段&#xff08;field&#xff09;和值&#xff08;value&#xff09;存储在一个单独的key下&#xff0c;从而避免了将多个相关数据存储为多个独立的key。…

Qt:Qt Creator项目创建

目录 认识Qt Creator Qt Creator概览 使用Qt Creator新建项目 选择项目模板 选择项目路径 选择构建系统 填写类信息设置界面 选择语言和翻译文件 选择Qt套件 选择版本控制系统 最终效果 认识Qt Creator Qt Creator概览 从开始菜单或者快捷方式打开Qt Creator集成开…

家用报警器的UML 设计及其在C++和VxWorks 上的实现01

M.W.Richardson 著&#xff0c;liuweiw 译 论文描述了如何运用 UML&#xff08;统一建模语言&#xff09;设计一个简单的家用报警器&#xff0c;并实现到 VxWorks 操作系统上。本文分两个部分&#xff0c;第一部分描述了如何用 UML 设计和验证家用报警器的模型&#xff0c;以使…

node.js + html + Sealos容器云 搭建简易多人实时聊天室demo 带源码

node.js html Sealos容器云 搭建简易多人实时聊天室demo 带源码 前言功能介绍&#xff08;demo演示&#xff09;sealos官网配置node.js 编写服务端代码前端ui 调用接口整体项目目录部署到服务器 前言 hello哦盆友们&#xff0c;这次我们来十几行代码做一个超简单的多人聊天…

CPP集群聊天服务器开发实践(一):用户注册与登录

目录 1 客户端用户注册与登录 1.1 主要思想 1.2 网络层 1.3 业务层 1.4 数据层 1.5 测试结果 1 客户端用户注册与登录 1.1 主要思想 实现网络层、业务层、数据层的解耦&#xff0c;提高系统的可维护性。 网络层&#xff1a;主要实现对客户端连接、客户端读写请求的捕获…

【C语言】数 组与指针:深度剖析与等价表达

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C语言 文章目录 &#x1f4af;前言&#x1f4af;数组与指针的基本关系&#x1f4af;数组与指针的互换使用数组下标与指针的等价性 &#x1f4af;六个表达式的等价性&#x1f4af;指针运算的注意事项&#x1f4af;数组…