[Qt] 窗口 | 菜单栏MenuBar

devtools/2025/1/16 15:09:02/

目录

QMainWindow 概述

一、菜单栏

1、创建菜单栏

2、在菜单栏中添加菜单

3、创建菜单项

4、在菜单项之间添加分割线

5、添加快捷键

6、添加子菜单

7、添加图标

综合示例


QMainWindow 概述

Qt 窗口是通过 QMainWindow 类来实现的。

  • QMainWindow 是一个为用户 提供主窗口程序的类。
  • 该类继承自 QWidget,并提供了一个预定义的布局
  • QMainWindow 包含一个菜单栏(Menu Bar)、多个工具栏(Tool Bars)、多个浮动窗口(铆接部件)(Dock Widgets)、⼀个状态栏(Status Bar)和一个中心部件(Central Widget),它是许多应用程序的基础,如文本编辑器,图片编辑器等。

如下图为 QMainwindow 中各组件所处的位置


一、菜单栏

Qt 中的菜单栏是通过 QMenuBar 这个类来实现的。一个主窗口最多只有一个菜单栏,位于主窗口顶部、主窗口标题栏下面。

菜单栏中包含菜单,菜单中包含菜单项。

工具栏本质上就是把菜单中一些比较常用的选项直接放到工具栏里,直接点工具栏中的按钮就能快速生效。


1、创建菜单栏

(1)方式一

菜单栏的创建可以借助于 QMainWindow 类提供的 menuBar() 函数来实现。menubar() 函数原型如下:

如果我们自己创建的项目没有勾选自动生成 ui 文件,那么上述代码是没有问题的。但如果勾选了自动生成 ui 文件(Qt 已经给我们生成了一个 QMenuBar),那么上述代码就会引起内存泄漏

程序自己已经创建好了一个 QMenuBar,当设置新的 QMenuBar 进来时,就会导致旧的 QMenuBar 脱离了 Qt 的对象树,意味着后续就无法对这个对象进行释放了。

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

(2)方式二(更合理的写法)

在堆上动态创建。

如果是获取到已经存在的 QMenuBar,那么这里的设置就是自己替换自己,仍然在对象树上。

使用 setMenuBar 把菜单栏放到窗口中。


2、在菜单栏中添加菜单

创建菜单,并通过 QMenu 提供的 addMenu() 函数 来添加菜单。

// 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、创建菜单项

在 Qt 中,并没有专门的菜单项类(QMenuBarItem),可以通过 QAction 类,抽象出公共的动作,如在菜单中添加菜单项。

 // 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);

QAction 可以给菜单栏使用,也可以给工具栏使用。

4、在菜单项之间添加分割线

在菜单项之间可以添加分割线。分割线如下图所示,添加分割线是通过 QMenu 类提供的 addSeparator() 函数来实现:

示例:

5、添加快捷键

在设置菜单的 title 时,在字母前加 & 符号。

示例:

 QMenuBar* menuBar = new QMenuBar();this->setMenuBar(menuBar);QMenu* menu1 = new QMenu("文件(&F)");QMenu* menu2 = new QMenu("视图(&V)");menuBar->addMenu(menu1);menuBar->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);

!不绑定槽函数, 通过快捷键选中也没啥反应

效果展示:

按下 Alt 键,再按 F,其显示的 W 下面会有下划线,表示是有快捷键的,快捷键为 W。

6、添加子菜单
  • 菜单栏 -> 菜单 -> 菜单栏
  • 菜单栏 -> 菜单 -> 子菜单 -> 子菜单 -> 菜单栏

QMenu 也提供了 addMenu,通过这个操作可以给某个菜单项添加子菜单。

示例:

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);

7、添加图标

按照之前设置图标的方法:

    QMenuBar* menuBar = new QMenuBar();this->setMenuBar(menuBar);QMenu* menu = new QMenu("菜单");menu->setIcon(QIcon(":/open.png"));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);

如果给 QMenu 设置图标。因为当前 QMenu 是长在 QMenuBar 上的,此时文本就不显示,图标会覆盖文本。

而 QMenu 是子菜单,图标和文本都是可以显示的。


综合示例

在窗口上创建一个菜单栏,在菜单栏中添加一些菜单,在某一个菜单中添加一些菜单项。

(1)新建 Qt 项目

注意:此时新建项目时选择的基类 QMainwindow

(2)在 "mainwindow.cpp" 文件中创建菜单和中央控件

头文件中声明:

  • 创建一个菜单栏,一个菜单
  • 两个菜单项:保存,加载
  • 创建一个 QTextEdit 作为窗口的中央控件
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);// 设置标题this->setWindowTitle("我的记事本");// 创建菜单栏QMenuBar* menuBar = new QMenuBar(this);this->setMenuBar(menuBar);// 创建菜单QMenu* menu = new QMenu("文件");menuBar->addMenu(menu);// 创建菜单项QAction* action1 = new QAction("保存");QAction* action2 = new QAction("加载");menu->addAction(action1);menu->addAction(action2);// 创建中央控件edit = new QTextEdit(this);this->setCentralWidget(edit);edit->setPlaceholderText("此处编写⽂本内容...");
}

(3)给 action 添加一些动作

// 连接信号槽,点击 action 时触发一定的效果
connect(action1, &QAction::triggered, this, &MainWindow::save);
connect(action2, &QAction::triggered, this, &MainWindow::load);

实现这两个槽函数:

使用 QFileDialog 来实现选择文件的效果

  • getSaveFileName 用于保存文件的场景,此时的对话框可以输入文件名
  • getOpenFileName 用于打开文件的场景,此时的对话框可以获取到鼠标选择的文件名

搭配 C++ 标准库的⽂件操作实现文件读写

void MainWindow::save()
{// 弹出对话框,选择写入文件的路径QFileDialog* dialog = new QFileDialog(this);QString fileName = dialog->getSaveFileName(this, "保存⽂件", "C:/Users/1/");qDebug() << "fileName: " << fileName;// 写⼊⽂件std::ofstream file(fileName.toStdString().c_str());if (!file.is_open()) {qDebug() << "文件保存失败!";return;}const QString& text = edit->toPlainText();file << text.toStdString();file.close();
}void MainWindow::load()
{// 弹出对话框,选择打开的文件QFileDialog* dialog = new QFileDialog(this);QString fileName = dialog->getOpenFileName(this, "加载文件", "C:/Users/1/");qDebug() << "fileName: " << fileName;// 读取文件std::ifstream file(fileName.toStdString().c_str());if (!file.is_open()) {qDebug() << "文件加载失败!";return;}std::string content;std::string line;while (std::getline(file, line)) {content += line;content += "\n";}file.close();// 显示到界面上QString text = QString::fromStdString(content);edit->setPlainText(text);
}

执行程序,可以看到此时就可以通过程序来保存 / 加载文件了,并且对文件进行编辑。


http://www.ppmy.cn/devtools/150982.html

相关文章

Ubuntu 的内置字体中哪些字体支持中文

Ubuntu 的内置字体中&#xff0c;部分字体是支持中文的&#xff0c;但默认配置可能不完整或显示效果不佳。以下是 Ubuntu 内置支持中文的字体以及如何增强对中文的支持&#xff1a; Ubuntu 内置支持中文的字体 Noto Fonts&#xff08;推荐&#xff09; 字体名称&#xff1a;Not…

如何从本地计算机连接至远程服务器上的 Jupyter Notebook

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

js:正则表达式

目录 正则表达式的语法 定义 检测 检索 元字符 边界符 量词 字符类 表单判断案例 修饰符 过滤敏感词 正则表达式是一种用于匹配和操作文本的强大工具&#xff0c;它是由一系列字符和特殊字符组成的模式&#xff0c;用于描述要匹配的文本字符组合模式 正则表达式是一…

Hadoop3.x 万字解析,从入门到剖析源码

&#x1f496; 欢迎来到我的博客&#xff01; 非常高兴能在这里与您相遇。在这里&#xff0c;您不仅能获得有趣的技术分享&#xff0c;还能感受到轻松愉快的氛围。无论您是编程新手&#xff0c;还是资深开发者&#xff0c;都能在这里找到属于您的知识宝藏&#xff0c;学习和成长…

开发人员学习书籍推荐(C#、Python方向)

作为一名开发人员&#xff0c;持续学习和提升自己的技术水平是至关重要的。如今&#xff0c;技术不断更新换代&#xff0c;新的开发框架、语言和工具层出不穷。对于刚入行的开发者或希望深入某一领域的工程师来说&#xff0c;选对书籍是学习的捷径之一。本篇文章将推荐一些经典…

【Linux】--- 进程的等待与替换

进程的等待与替换 一、进程等待1、进程等待的必要性2、获取子进程status3、进程等待的方法&#xff08;1&#xff09;wait&#xff08;&#xff09;函数&#xff08;2&#xff09;waitpid函数 4、多进程创建以及等待的代码模型5、非阻塞接口 轮询 二、进程替换1、替换原理2、替…

Flutter插件制作、本地/远程依赖及缓存机制深入剖析(原创-附源码)

Flutter插件在开发Flutter项目的过程中扮演着重要的角色&#xff0c;我们从 ​​​​​​https://pub.dev 上下载添加到项目中的第三方库都是以包或者插件的形式引入到代码中的&#xff0c;这些第三方工具极大的提高了开发效率。 深入的了解插件的制作、发布、工作原理和缓存机…

CSS 元素的显示模式(块元素,行内元素,行内块元素)

一. 块元素&#xff08;block&#xff09; 又称&#xff1a;块级元素 特点&#xff1a; 1. 在页面中独占一行&#xff0c;不会与任何元素共用一行&#xff0c;是从上到下排列的。 2. 默认宽度&#xff1a;撑满父元素。 3. 默认高度&#xff1a;由内容撑开。 4. 可以通过 CSS 设…