QT初始项目分析
***.pro
#工程管理文件
#添加所需要的类库(核心、图形化界面设计、文字转为语音、网络编程)
QT += core gui texttospeech network
#如果QT版本大于4,需要添加widgets类库
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
#表示支持C++11
CONFIG += c++11
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
#源文件,在此处写入之后会自动更新
SOURCES += \
main.cpp \
mywnd.cpp
#头文件
HEADERS += \
mywnd.h
#ui文件
FORMS += \
mywnd.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
mywnd.h
//防止头文件重复包含
#ifndef MYWND_H
#define MYWND_H
//导入头文件
#include <QMainWindow>
//测试使用的按钮需要引入的头文件
#include <QPushButton>
//自定义命名空间
QT_BEGIN_NAMESPACE
namespace Ui { class Mywnd; }
QT_END_NAMESPACE
//继承自QMainWindow类,QT中的类权限和C++有所区别,一共有5种权限
class Mywnd : public QMainWindow
{
//与信号和槽函数的使用有关
Q_OBJECT
//信号函数
signals:
//是一个不完整的函数,只有声明,没有定义
void hug();
//槽函数
public slots:
//是一个完整的函数,有函数声明和定义,负责处理相关信号函数,此处测试没有写对应定义,所以注掉不然会报错
//void on_hug_slot();
public:
//使用了默认参数的构造函数,包含了无参构造的声明,参数是QWudget类的指针,指向函数的父组件
Mywnd(QWidget *parent = nullptr);
//析构函数的声明
~Mywnd();
private:
//声明一个指针成员指向ui文件转换成的C++文件
Ui::Mywnd *ui;
//声明要使用的测试组件指针,此处做测试使用,后续可不在此处声明,而是直接在要使用的地方进行声明及定义
QPushButton *btn;
};
#endif // MYWND_H
main.cpp
//引入头文件,该头文件位于当前工程目录下
#include "mywnd.h"
//此处要生成一个应用程序,所以引入应用程序文件
#include <QApplication>
int main(int argc, char *argv[])
{
//实例化一个应用程序对象,参数为主函数携带的所有参数
QApplication a(argc, argv);
//实例化自定义类的对象自动调用无参构造函数
Mywnd w;
//调用展示函数,将相关内容展示到界面上
w.show();
//调用轮询函数,等待事件发生
return a.exec();
}
mywnd.cpp
//引入当前工程下的头文件
#include "mywnd.h"
//引入ui文件转换生成的头文件
#include "ui_mywnd.h"
//定义自定义类,参数是指向父组件的QWidget指针
Mywnd::Mywnd(QWidget *parent)
//调用有参构造函数,初始化本函数中继承的父组件的私有成员以及本函数使用的ui组件,通过深拷贝的方式完成初始化
: QMainWindow(parent)
, ui(new Ui::Mywnd)
{
//调用ui文件的setupUi函数指向本组件
ui->setupUi(this);
//以后编程从此处开始写,不去更改主函数的内容
//给自定义组件开辟空间,并将本组件设定为按钮组件的父组件
this->btn = new QPushButton(this);
//更改自定义组件通过this指针可保证指向唯一,避免命名冲突
this->btn->setText("点击");
//更改ui组件通过ui指针进行操作,需要先在图形化设计界面先拖拽出一个按钮,不然就需要手动定义那样就失去了图形化设计的意义
ui->pushButton->setText("按钮2");
}
//自定义的析构函数定义
Mywnd::~Mywnd()
{
//释放ui指向的空间,此处不需要写释放btn指向空间的语句,因为QT有对象树模型,可以自动回收空间,前提是将组件绑定在父组件上,例如本例
delete ui;
}
测试结果
对象树模型用C++模拟实现
//通过C++模拟实现对象树模型
#include <iostream>
//对象树模型使用了链表,引入链表头文件
#include <list>
using namespace std;
//自定义Object类
class Object
{
//子组件链表
list<Object *> child;
public:
//构造函数,包含无参构造
Object(Object *parent = nullptr)
{
if(parent != nullptr)
{
//说明创建对象时,给定了父组件,说明要将自己的地址放到父组件的孩子链表中
parent->child.push_back(this);
}
}
//虚析构函数,将所有的子组件都释放掉
virtual ~Object()
{
//auto自动识别子组件的类型
for(auto p = child.begin(); p!=child.end(); p++)
{
//p中的内容才是子组件的地址,所以使用*p
delete *p;
}
}
};
//派生类A
class A : public Object
{
public:
//调用有参构造函数,初始化本函数中继承的父组件的私有成员
A(Object *parent = nullptr):Object(parent){cout<<"A构造函数"<<endl;}
//测试看看是否自动析构了
virtual ~A() {cout<<"A析构函数"<<endl;}
};
//派生类B
class B : public Object
{
public:
//调用有参构造函数,初始化本函数中继承的父组件的私有成员
B(Object *parent = nullptr):Object(parent){cout<<"B构造函数"<<endl;}
//测试看看是否自动析构了
virtual ~B() {cout<<"B析构函数"<<endl;}
};
int main()
{
//实例化A类对象、栈空间
A w;
//通过new初始化B类对象,并将w作为父组件
B *btn = new B(&w);
//对比未绑定
B *btn1 = new B();
//delete btn1;
return 0;
}
测试结果
手动释放后的测试结果
未手动释放的结果
·