【Qt】深入探索Qt主窗口与菜单栏:构建高效用户界面的实践指南

news2025/2/28 23:42:01

文章目录

  • 前言
  • 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 的对象树了,意味着后续无法对这个对象树进行释放了

上诉程序如果窗口关闭,对象树释放,此时进程也就介绍了。进程结束,自然所有内存都回收给系统。上述内存泄漏也不会造成影响,但是如果这样的如果出现在一个多窗口的程序中。如果涉及到窗口的频繁跳转切换(窗口的频繁创建销毁),上述代码泄漏会更严重一些。但是实际上由于现在的计算机内存都比较充裕上述内存泄漏都还好。

服务器程序相比于客户端程序相比更害怕内存泄漏。

  1. 服务器要处理很多请求,每个请求泄漏一点,请求累积下来就会泄漏很多
  2. 服务器要 7 * 24 小时运行。

当然,即使如此,还是期望代码写的更规范一些。

QMenuBar* menuBar = this->menuBar();
  1. 如果 QMenuBar 已经存在,直接获取并返回
  2. 如果 QMenuBar 不存在,就先创建一个新的,再返回。
this->setMenuBar(menuBar);

如果是活的已经存在的 QMenuBar, 这里的设置就是自己替换自己,仍然对象树上

如在嵌入式,设备上内存泄漏的问题就比较重要了。

总结

本文详细介绍了Qt中主窗口(QMainWindow)的构成和功能,特别是菜单栏(QMenuBar)的创建和使用。通过一系列具体的代码示例,我们学习了如何创建菜单栏、添加菜单和菜单项、设置快捷键、嵌套子菜单、使用分割线以及添加图标,这些都是构建用户友好界面的关键步骤。同时,文章也指出了在Qt开发中可能遇到的内存泄漏问题,并提供了解决方案,强调了在开发过程中遵循良好编程实践的重要性。通过这些知识点,开发者可以更有效地利用Qt框架,创建出既美观又实用的应用程序界面。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DELPHI通过WebService进行数据交互

WebService是一种可以跨语言和平台的数据交互模式&#xff0c;使用非常广泛&#xff0c;与JSon数据格式结合&#xff0c;更是当前非常流行的一种模式&#xff0c;本章针对DELPHI通过WebService进行数据的交互做一个相对简单例子应用。 本文使用的DELPHI 版本为&#xff1a;DEL…

Linux基础之程序地址空间

目录 一、程序地址空间的基本概念 二、程序地址空间的结构​编辑 三、虚拟地址和物理地址的关系 四、为什么要使用程序地址空间 一、程序地址空间的基本概念 要理解我们的程序地址空间&#xff0c;首先就要认识下面这张图&#xff1a; 这张图上所表示的内容&#xf…

java中写word换行符 poi 换行

省流&#xff1a; 表格外的文本&#xff0c;使用“\r”或者“(char)11”来换行&#xff0c;建议用"\r"。 表格内的文本&#xff0c;使用“(char)11”来换行。 正文&#xff1a; 测试用word文档&#xff1a; t1.doc内容如下&#xff1a; t2.doc内容如下&#xff…

基于xilinx fpga RFSOC系列的Ultrascale+ RF Data Converter ip详解说明

目录 1 概述2 IP功能2.1 ADC性能2.2 DAC性能3 IP端口4 代码框架4.1 ADC功能框图4.2 DAC功能框图5 收发数据时序5.1 ADC数据格式5.2 DAC数据格式6 时钟配置6.1 ADC/DAC参考时钟7 数据格式配置模式7.1 ADC的配置模式7.1.1 Real -> real;7.1.2 Real ->IQ;7.1.3 IQ -> IQ;…

掌握2个手机数据恢复软件,快速恢复丢失的数据!

我们使用手机存储了大量的个人和重要数据&#xff0c;包括照片、视频、联系人、短信等等。然而&#xff0c;数据丢失的风险也随之增加。不小心删除、手机损坏、系统崩溃等问题都可能导致宝贵的数据消失。 幸运的是&#xff0c;现在有许多强大而高效的手机数据恢复软件可以帮助…

CSS transform 三大属性 rotate、scale、translate

transform 浏览器支持定义和用法translate位移函数rotate旋转函数scale缩放函数 浏览器支持 表格中的数字表示支持该属性的第一个浏览器版本号。 紧跟在 -webkit-, -ms- 或 -moz- 前的数字为支持该前缀属性的第一个浏览器版本号。 定义和用法 transform 属性向元素应用 2D…

2024电工杯B题保姆级分析完整思路+代码+数据教学

2024电工杯B题保姆级分析完整思路代码数据教学 B题题目&#xff1a;大学生平衡膳食食谱的优化设计及评价 接下来我们将按照题目总体分析-背景分析-各小问分析的形式来 总体分析&#xff1a; 题目要求对两份一日膳食食谱进行营养分析和调整&#xff0c;然后设计优化的平衡膳…

Python 造数据神器Faker

大家好&#xff0c;在编写代码过程中&#xff0c;我们经常需要一些假数据来进行测试或者演示。手动创建这些数据不仅耗时&#xff0c;而且容易出错。幸运的是&#xff0c;Python有一个非常有用的库叫做Faker&#xff0c;它可以生成各种类型的假数据&#xff0c;从名字、地址到公…

ios 原生项目迁移flutter第一天环境

由于公司已经有第一个吃螃蟹的项目组&#xff0c;我在迁移的时候想着站在巨人的肩膀上&#xff0c;但是搭配环境一定要问清楚对方flutter版本&#xff0c;路径也要安排好&#xff0c;不然就不行。 对着自己的项目照着葫芦画瓢&#xff0c;我刚开始为了配置管理图个方便随便放&…

基于Python实现 HR 分析(逻辑回归和基于树的机器学习)【500010104】

介绍 数据集说明 此数据集包含与员工有关的综合属性集合&#xff0c;从人口统计细节到与工作相关的因素。该分析的主要目的是预测员工流动率并辨别导致员工流失的潜在因素。 在这个数据集中&#xff0c;有14,999行&#xff0c;10列&#xff0c;以及这些变量&#xff1a;满意度…

GPU集合通信库在B站的应用和改进

1. 背景 上篇文章 万字长文解析&#xff1a;大模型需要怎样的硬件算力 深入探讨了大型语言模型&#xff08;LLMs&#xff09;在硬件资源方面的需求和面临的挑战&#xff0c;详尽地阐述了如何进行大模型的硬件选型&#xff0c;以及在实际工作中如何根据模型的特定需求来优化硬件…

安装petalinux工具

petalinux 并不是一个特殊 Linux 内核&#xff0c;而是一套开发环境配置的工具&#xff0c;降低 uboot、内核、 根文件系统的配置的工作量&#xff0c;可以从 Vivado 的导出硬件信息自动完成相关软件的配置。 petalinux 是赛灵思基于 buildroot 工具链为自家处理器方便适配 Li…

每周刷题第三期

个人主页&#xff1a;星纭-CSDN博客 系列文章专栏&#xff1a;Python 踏上取经路&#xff0c;比抵达灵山更重要&#xff01;一起努力一起进步&#xff01; 目录 题目一&#xff1a;环形链表 题目二&#xff1a;删除有序数组中的重复项 题目三&#xff1a;有效的括号 题…

spring-boot-starter-mail 发送带附件的邮件信息

背景 项目使用的事ruoyi低代码开发平台ruoyi中有常见的web端下载excel的方式&#xff0c;但是这种方式是直接把输出流写到一个response中&#xff0c;而不是给一个outputstream&#xff0c;如果是给一个outputstream的话&#xff0c;就可以写入到一个固定的文件中去了 解决思路…

P2. 配置MySQL和用户注册登录模块

P2. 配置MySQL和用户注册登录模块 0 概述Tips1 预备知识1.1 SpringBoot 常用模块1.2 pojo层的实现1.3 mapper层的实现1.4 controller层调试CRUD 2 Spring Security2.1 Spring Security 介绍2.2 Spring Security 对接数据库2.3 密码的加密 3 Jwt验证3.1 传统Session验证方式3.2 …

Langchain-Chatchat的markdownHeaderTextSplitter使用

文章目录 背景排查步骤官方issue排查测试正常对话测试官方默认知识库Debug排查vscode配置launch.json命令行自动启动condadebug知识库搜索测试更换ChineseRecursiveTextSplitter分词器 结论 关于markdownHeaderTextSplitter的探索标准的markdown测试集Langchain区分head1和head…

小白跟做江科大32单片机之学习准备

1.安装好51MDK之后&#xff0c;出现不能正常安装支持包的情况 在线安装支持包——>在keil5软件下点击这个&#xff0c;即可进入更新支持包界面 进去之后找这个 国产的可以找和这个 最后有这个就可以了

【人工智能项目】小车障碍物识别与模型训练(完整工程资料源码)

实物演示效果: 一、绪论: 1.1 设计背景 小车障碍物识别与模型训练的设计背景通常涉及以下几个方面: 随着自动驾驶技术的发展,小车(如无人驾驶汽车、机器人等)需要能够在复杂的环境中自主导航。障碍物识别是实现这一目标的关键技术之一,它允许小车检测并避开路上的障碍物…

JavaScript 动态网页实例 —— 表格处理

表格是网页设计中必不可少的内容之一。本章首先介绍HTML中普通表格的组成结构,然后,在此基础上,介绍如何使用JavaScript设置表格的属性。随后,更具体地介绍操作表格元素的一般方法,主要是对表格行、列的动态增删操作。有了这些基础,在本章的最后介绍对表元的操作,即如何…

C语言 | Leetcode C语言题解之第108题将有序数组转换为二叉搜索树

题目&#xff1a; 题解&#xff1a; struct TreeNode* helper(int* nums, int left, int right) {if (left > right) {return NULL;}// 选择任意一个中间位置数字作为根节点int mid (left right rand() % 2) / 2;struct TreeNode* root (struct TreeNode*)malloc(sizeo…