文章目录
- 前言
- 1. 什么是Main Window?
- 2. 详细了解一下其中的 菜单栏:
- 2.1. 创建菜单栏
- 2.2. 添加快捷键
- 2.3. 添加子菜单
- 2.4. 添加分割线
- 2.5. 添加图标
- 3. 内存泄漏问题:
- 总结
前言
在现代软件开发中,用户界面的设计对于提升用户体验至关重要。Qt框架作为功能强大的跨平台开发工具,提供了丰富的组件和工具来帮助开发者构建复杂的应用程序。本文将深入探讨Qt中的主窗口(QMainWindow
)及其菜单栏(QMenuBar
)的创建和使用,包括菜单栏的创建、菜单项的添加、快捷键的设置、子菜单的嵌套、分割线的使用以及图标的添加。此外,文章还将讨论内存泄漏问题,以及如何在Qt中避免这类问题,确保应用程序的稳定性和性能。
前面学习的所有代码,都是基于 QWidget
(控件),QWidget
更多的是作为别的窗口的一个部分。
1. 什么是Main Window?
QMainWindow
是⼀个为用户提供主窗口程序的类,继承自 QWidget
类,并且提供了⼀个预定义的布局。QMainWindow
包含 ⼀个菜单栏(menu bar)、多个工具栏(tool bars)、多个浮动窗口(铆接部件)(dock widgets)、⼀个状态栏(status bar) 和⼀个中心部件(central widget),它是许多应用程序的基础,如文本编辑器,图片编辑器等。如下图为 QMainwindow
中 各组件所处的位置:
-
菜单栏(Menu Bar):
Qt 中的菜单栏是通过QMenuBar
这个类来实现的。⼀个主窗口最多只有⼀个菜单栏。位于主窗口顶部、主窗口标题栏下面。
-
工具栏(Tool Bar Area):
工具具栏是应用程序中集成各种功能实现快捷键使用的⼀个区域。可以有多个,也可以没有,它并不是应用程序中必须存在的组件。它是⼀个可移动的组件,它的元素可以是各种窗口组件,它的元素通常以图标按钮的方式存在。如下图为工具栏的示意图:
-
铆接部件/子窗口(Dock Widget Area)
一个主窗口往往可以是由多个子窗口所构成的。
-
中央控件(Central Widget)
窗口最核心的部分
-
状态栏(Status Bar)
用于显示一些信息供用户去参考。
2. 详细了解一下其中的 菜单栏:
Qt 中的菜单栏是通过 QMenuBar
这个类来实现的。⼀个主窗口最多只有⼀个菜单栏。位于主窗口顶部、主窗口标题栏下面。
菜单栏中包含菜单. 菜单中包含菜单项。
一个主窗口最多只有一个菜单栏,工具栏,本质上就是菜单中的一些选项的“快捷方式”
QAction
动作
2.1. 创建菜单栏
“在这里输入” 可以在这里添加菜单了
菜单栏(
QMenuBar
) -> 菜单(QMenu
) -> 菜单项(QAction
)
由于当前每个菜单都是空着的,点上去没反应,添加后有反应。
使用代码去创建菜单结构:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 1.先创建一个菜单栏
QMenuBar* menuBar = new QMenuBar();
this->setMenuBar(menuBar);
// 2. 创建菜单
QMenu* menu1 = new QMenu("文件");
QMenu* menu2 = new QMenu("编辑");
QMenu* menu3 = new QMenu("视图");
menuBar->addMenu(menu1);
menuBar->addMenu(menu2);
menuBar->addMenu(menu3);
// 3. 给菜单添加菜单项
QAction* action1 = new QAction("新建");
QAction* action2 = new QAction("打开");
QAction* action3 = new QAction("保存");
QAction* action4 = new QAction("另存为");
QAction* action5 = new QAction("退出");
menu1->addAction(action1);
menu1->addAction(action2);
menu1->addAction(action3);
menu1->addAction(action4);
menu1->addAction(action5);
}
MainWindow::~MainWindow()
{
delete ui;
}
怎样使它点击的时候有反应呢?
QAction* action1 = new QAction("新建");
QAction* action2 = new QAction("打开");
QAction* action3 = new QAction("保存");
QAction* action4 = new QAction("另存为");
QAction* action5 = new QAction("退出");
被点击的时候会触发一个信号!triggered 触发
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 1.先创建一个菜单栏
QMenuBar* menuBar = new QMenuBar();
this->setMenuBar(menuBar);
// 2. 创建菜单
QMenu* menu1 = new QMenu("文件");
QMenu* menu2 = new QMenu("编辑");
QMenu* menu3 = new QMenu("视图");
menuBar->addMenu(menu1);
menuBar->addMenu(menu2);
menuBar->addMenu(menu3);
// 3. 给菜单添加菜单项
QAction* action1 = new QAction("新建");
QAction* action2 = new QAction("打开");
QAction* action3 = new QAction("保存");
QAction* action4 = new QAction("另存为");
QAction* action5 = new QAction("退出");
menu1->addAction(action1);
menu1->addAction(action2);
menu1->addAction(action3);
menu1->addAction(action4);
menu1->addAction(action5);
// 4. 给 action 添加信号槽
connect(action1, &QAction::triggered, this, &MainWindow::handle);
connect(action5, &QAction::triggered, this, &MainWindow::close); // close 是Qt自带关闭窗口的槽函数
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::handle()
{
qDebug() << "触发新建操作!";
}
2.2. 添加快捷键
给菜单和菜单项设置快捷键
设置好的快捷键就可以搭配 alt 来进行使用了
QMenu* menu1 = new QMenu("文件(&F)");
通过给文本添加 &F
这样的操作,就是添加了快捷键 alt+F
与,QLabel
,中设置伙伴的方式比较相似,当然使用 QShortcut
也可以实现同样的效果但是太麻烦了。
给菜单项同样可以添加快捷键:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QMenuBar* menBar = new QMenuBar();
this->setMenuBar(menBar);
QMenu* menu1 = new QMenu("文件(&F)");
QMenu* menu2 = new QMenu("视图(&V)");
menBar->addMenu(menu1);
menBar->addMenu(menu2);
// 创建四个菜单项
QAction* action1 = new QAction("action1(&Q)");
QAction* action2 = new QAction("action2(&W)");
QAction* action3 = new QAction("action3(&E)");
QAction* action4 = new QAction("action4(&R)");
menu1->addAction(action1);
menu1->addAction(action2);
menu2->addAction(action3);
menu2->addAction(action4);
// 如果不绑定槽函数,通过快捷键选中也没啥反应
connect(action1, &QAction::triggered, this, &MainWindow::handle1);
connect(action2, &QAction::triggered, this, &MainWindow::handle2);
connect(action3, &QAction::triggered, this, &MainWindow::handle3);
connect(action4, &QAction::triggered, this, &MainWindow::handle4);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::handle1()
{
qDebug() << "handle1" ;
}
void MainWindow::handle2()
{
qDebug() << "handle2" ;
}
void MainWindow::handle3()
{
qDebug() << "handle3" ;
}
void MainWindow::handle4()
{
qDebug() << "handle4" ;
}
2.3. 添加子菜单
菜单栏 -> 菜单 -> 菜单项
菜单栏->菜单->子菜单->菜单项
QMenuBar
可以通过 addMenu
添加菜单的,QMenu
也提供了 addMenu
。
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QMenuBar* menuBar = new QMenuBar();
this->setMenuBar(menuBar);
QMenu* menuParent = new QMenu("父菜单");
QMenu* menuChild = new QMenu("子菜单");
menuBar->addMenu(menuParent);
menuParent->addMenu(menuChild);
QAction* action1 = new QAction("菜单项1");
QAction* action2 = new QAction("菜单项2");
menuChild->addAction(action1);
menuChild->addAction(action2);
QMenu* menuChild2 = new QMenu("子菜单2");
menuChild->addMenu(menuChild2);
}
MainWindow::~MainWindow()
{
delete ui;
}
2.4. 添加分割线
菜单里菜单特别多,就可以通过分割线进行分组
QMenu
中提供了 addSeparator
这样的函数
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QMenuBar* menuBar = new QMenuBar();
this->setMenuBar(menuBar);
QMenu* menu = new QMenu("菜单");
menuBar->addMenu(menu);
QAction* action1 = new QAction("菜单项1");
QAction* action2 = new QAction("菜单项2");
menu->addAction(action1);
menu->addSeparator();
menu->addAction(action2);
}
MainWindow::~MainWindow()
{
delete ui;
}
2.5. 添加图标
Qlcon 类, qrc
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QMenuBar* menuBar = new QMenuBar();
this->setMenuBar(menuBar);
QMenu* menu = new QMenu("菜单");
menuBar->addMenu(menu);
QAction* action1 = new QAction("菜单项1");
action1->setIcon(QIcon(":/open.png"));
QAction* action2 = new QAction("菜单项2");
action2->setIcon(QIcon(":/save.png"));
menu->addAction(action1);
menu->addAction(action2);
}
MainWindow::~MainWindow()
{
delete ui;
}
如果给 QMenu
设置图标,当前 QMenu
是长在 QMenuBar
上的,此时文本就不显示,图标就覆盖了文本。
QMenu
是子菜单,图标和文本都是能显示的。
3. 内存泄漏问题:
QMenuBar* menuBar = new QMenuBar();
this->setMenuBar(menuBar);
如果咱们创建项目,没有勾选生成ui,文件,此时上述代码是可以的,如果勾选了自动生成 ui 文件,上述代码则会引起内存泄漏。
自动生成 ui 文件:Qt已经给你生成了一个 QMenuBar
了。
之前程序已经创建好了一个 QMenuBar
, 当设置新的 QMenuBar
进来的时候, 就会导致旧的 QMenuBar
脱离了 Qt 的对象树了,意味着后续无法对这个对象树进行释放了
上诉程序如果窗口关闭,对象树释放,此时进程也就介绍了。进程结束,自然所有内存都回收给系统。上述内存泄漏也不会造成影响,但是如果这样的如果出现在一个多窗口的程序中。如果涉及到窗口的频繁跳转切换(窗口的频繁创建销毁),上述代码泄漏会更严重一些。但是实际上由于现在的计算机内存都比较充裕上述内存泄漏都还好。
服务器程序相比于客户端程序相比更害怕内存泄漏。
- 服务器要处理很多请求,每个请求泄漏一点,请求累积下来就会泄漏很多
- 服务器要 7 * 24 小时运行。
当然,即使如此,还是期望代码写的更规范一些。
QMenuBar* menuBar = this->menuBar();
- 如果
QMenuBar
已经存在,直接获取并返回 - 如果
QMenuBar
不存在,就先创建一个新的,再返回。
this->setMenuBar(menuBar);
如果是活的已经存在的 QMenuBar
, 这里的设置就是自己替换自己,仍然对象树上
如在嵌入式,设备上内存泄漏的问题就比较重要了。
总结
本文详细介绍了Qt中主窗口(QMainWindow
)的构成和功能,特别是菜单栏(QMenuBar
)的创建和使用。通过一系列具体的代码示例,我们学习了如何创建菜单栏、添加菜单和菜单项、设置快捷键、嵌套子菜单、使用分割线以及添加图标,这些都是构建用户友好界面的关键步骤。同时,文章也指出了在Qt开发中可能遇到的内存泄漏问题,并提供了解决方案,强调了在开发过程中遵循良好编程实践的重要性。通过这些知识点,开发者可以更有效地利用Qt框架,创建出既美观又实用的应用程序界面。