文章目录
- Qt多界面创建的优化问题(main函数或主界面中创建?)---------------附带详细方法
-
- [0 背景](#0 背景)
- [1 方法一实践](#1 方法一实践)
- [2 方法二实践](#2 方法二实践)
- [3 两种方法对比](#3 两种方法对比)
Qt多界面创建的优化问题(main函数或主界面中创建?)---------------附带详细方法
0 背景
qt中,现在存在多个界面,例如登录界面、主界面、用户协议界面等,界面间存在相互调用,现在存在两种方法来创建这些界面。
方法一:是在main函数中创建这些界面并调用。
方法二:在主界面中创建其余界面,然后在main函数中创建主界面。
1 方法一实践
cpp
#include <QApplication>
#include "main_interface.h"
#include "login_dialog.h"
#include "agreement_dialog.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainInterface w;
LoginDialog l;
AgreementDialog agreementDialog;
QObject::connect(&l, &LoginDialog::show2MainInterface,
&w, &MainInterface::show);
QObject::connect(&l, &LoginDialog::openAgreement,
&agreementDialog, &AgreementDialog::show);
l.show();
return a.exec();
}
2 方法二实践
main函数:
cpp
#include <QApplication>
#include "main_interface.h"
#include "login_dialog.h"
#include "agreement_dialog.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainInterface w;
w.initializeInterface();
return a.exec();
}
主界面:
.h文件
cpp
class MainInterface : public QMainWindow
{
Q_OBJECT
public:
MainInterface(QWidget *parent = nullptr);
~MainInterface();
private:
Ui::MainInterface *ui;
private:
LoginDialog* loginDialog;
AgreementDialog* agreementDialog;
void initializeLoginDialog();
}
.cpp文件
cpp
MainInterface::MainInterface(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainInterface)
{
ui->setupUi(this);
//窗体无边框透明
this->setWindowFlag(Qt::FramelessWindowHint);
}
MainInterface::~MainInterface()
{
delete ui;
qDebug()<<"~MainInterface()";
}
void MainInterface::initializeLoginDialog()
{
//下面的创建会导致:
//对象树关系错误:将主窗口错误地设置为子窗口的父对象,当子窗口销毁时,Qt的对象树机制会尝试销毁所有子对象,可能导致主窗口被错误地销毁
// loginDialog = new LoginDialog(this);
// agreementDialog = new AgreementDialog(this);
loginDialog = new LoginDialog;
loginDialog->setAttribute(Qt::WA_DeleteOnClose, true); // 这会导致关闭时自动销毁
connect(loginDialog, &LoginDialog::successLogin,
this, &MainInterface::showMaximized);
connect(loginDialog, &LoginDialog::openAgreement,
this, [&]{
agreementDialog = new AgreementDialog;
agreementDialog->setAttribute(Qt::WA_DeleteOnClose, true);
connect(agreementDialog, &QWidget::destroyed, this, [this]{
qDebug()<<"避免野指针: agreementDialog";
agreementDialog = nullptr; // 避免野指针
});
agreementDialog->exec();
});
// agreementDialog, &AgreementDialog::exec);
connect(loginDialog, &QWidget::destroyed, this, [this]{
qDebug()<<"避免野指针: loginDialog";
loginDialog = nullptr; // 避免野指针
});
}
3 两种方法对比
| 对比维度 | 方法一(main函数集中创建) | 方法二(主界面分层创建) |
|---|---|---|
| 内存占用 | 程序启动时即加载所有界面,内存占用较高【预加载特性虽然提高了首次切换速度,但会导致程序启动时内存占用较高。当界面数量较多或界面本身较为复杂时,这种差异会更加明显。例如,一个包含四个复杂界面的应用,方法一的初始内存占用可能比方法二高出30%-50%。】 | 按需加载界面,初始内存占用较低【通过按需加载机制,能够更有效地利用系统资源。在资源受限的环境下(如嵌入式设备),这种差异尤为显著。然而,首次切换时的创建延迟需要通过合理设计来优化,例如预初始化部分界面或在后台线程中创建复杂界面。】 |
| 启动时间 | 较长,因需要初始化所有界面 | 较短,仅初始化主界面 |
| 首次切换性能 | 无延迟,界面已加载 | 可能有短暂延迟,因需要动态创建 |
| 后续切换性能 | 稳定无延迟 | 取决于界面复杂度,简单界面几乎无延迟 |
| 资源释放 | 需手动管理,易引发内存泄漏 | 利用Qt父子关系自动管理,资源释放更安全 |
| 代码组织性与维护性对比 | 1. 代码耦合度高:所有界面的创建和交互逻辑集中在main函数,导致代码结构混乱。 2. 可维护性差:修改或扩展界面功能时,需要在main函数中进行调整,容易引入错误。 3. 复用性低:界面创建和管理逻辑分散,难以复用到其他项目中。 | 1. 模块化设计:主界面类作为核心容器,其他界面作为其成员变量或子对象,符合"高内聚、低耦合"的设计原则。 2. 职责清晰:主界面负责管理界面生命周期和交互逻辑,各子窗口专注于自身功能实现。 3. 易于维护:修改或扩展界面功能时,只需在对应类中进行调整,不影响其他模块。 4. 良好的复用性:界面管理逻辑封装在主界面类中,便于复用到其他项目。 |
| 扩展性与适应性 | 1. 新增界面困难:每次添加新界面都需要修改main函数,违反了开闭原则。 2. 界面间交互复杂:跨界面通信需要直接引用对象,增加了耦合度。 3. 难以支持复杂交互:如多文档界面(MDI)、标签页切换等高级功能实现困难。 | 1. 灵活的界面管理:通过QStackedWidget、QMdiArea或QTabWidget等控件,可以轻松实现不同形式的多窗口管理 。 2. 清晰的界面间通信:利用Qt的信号槽机制,实现窗口间的解耦交互,提高系统灵活性。 3. 支持多种窗口布局:可适应不同业务场景需求,如简单切换、MDI界面或标签页模式 。 |
| 适用场景 | 1. 界面数量极少:如仅包含登录界面和主界面的简单应用; 2. 界面切换频率极高:如需要频繁切换且切换逻辑简单的场景; 3. 界面复杂度极低:如各界面仅包含少量简单控件; 4. 资源充足环境:如桌面应用且内存资源充足 | 1. 界面数量较多:如包含登录、主界面、配置、帮助、数据展示等多个模块; 2. 界面交互复杂:如需要多窗口协同工作或复杂的业务流程; 3. 界面类型多样:如需要同时支持对话框、MDI窗口、标签页等多种界面形式; 4. 资源受限环境:如嵌入式设备或需要长时间运行的后台应用; 5. 需求频繁变更:如需要快速迭代开发或功能模块经常调整的项目 |
| 使用 | 对于界面数量少、切换频繁、复杂度低的简单应用,可采用方法一,简化代码结构 | 对于中等复杂度应用,推荐采用方法二,结合QStackedWidget管理界面; 复杂应用,采用方法二并结合QMdiArea或QTabWidget等控件实现多文档界面或标签页切换 ; 对于高频使用的界面可预加载,低频使用的界面按需动态创建。 |
注意:Qt的半自动化内存管理机制虽然能自动释放子窗口,但仍需谨慎处理父子关系,避免循环引用等问题 。例如,若子窗口又持有主窗口的指针,且两者均设置为对方的父对象,就会形成循环引用,导致内存泄漏。