📑 目录
- [📌 引言](#📌 引言)
- [🗂️ 1. 菜单栏](#🗂️ 1. 菜单栏)
- [1.1 创建菜单栏](#1.1 创建菜单栏)
- [1.2 在菜单栏中添加菜单](#1.2 在菜单栏中添加菜单)
- [1.3 创建菜单项](#1.3 创建菜单项)
- [1.4 在菜单项之间添加分割线](#1.4 在菜单项之间添加分割线)
- [1.5 综合示例](#1.5 综合示例)
- [🛠️ 2. 工具栏](#🛠️ 2. 工具栏)
- [2.1 创建工具栏](#2.1 创建工具栏)
- [2.2 设置停靠位置](#2.2 设置停靠位置)
- [2.3 设置浮动属性](#2.3 设置浮动属性)
- [2.4 设置移动属性](#2.4 设置移动属性)
- [2.5 综合示例](#2.5 综合示例)
- [📊 3. 状态栏](#📊 3. 状态栏)
- [3.1 状态栏的创建](#3.1 状态栏的创建)
- [3.2 在状态栏中显示实时消息](#3.2 在状态栏中显示实时消息)
- [3.3 在状态栏中显示永久消息](#3.3 在状态栏中显示永久消息)
- [🪟 4. 浮动窗口](#🪟 4. 浮动窗口)
- [4.1 浮动窗口的创建](#4.1 浮动窗口的创建)
- [4.2 设置停靠的位置](#4.2 设置停靠的位置)
- [💬 5. 对话框](#💬 5. 对话框)
- [5.1 对话框介绍](#5.1 对话框介绍)
- [5.2 对话框的分类](#5.2 对话框的分类)
- [5.3 Qt 内置对话框](#5.3 Qt 内置对话框)
- [🎯 6. 小总结](#🎯 6. 小总结)
- [📝 7. 经典面试题](#📝 7. 经典面试题)
📌 引言
Qt 窗口是通过 QMainWindow 类来实现的。QMainWindow 是一个为用户提供主窗口程序的类,继承自 QWidget 类,并且提供了一个预定义的布局。
QMainWindow 包含一个菜单栏(menu bar)、多个工具栏(tool bars)、多个浮动窗口(铆接部件)(dock widgets)、一个状态栏(status bar)和一个中心部件(central widget),它是许多应用程序的基础,如文本编辑器、图片编辑器等。

💡 核心理解 :
QMainWindow是 Qt 中主窗口的基石,它把常用的窗口组件(菜单栏、工具栏、状态栏等)都整合在一起,方便开发者快速搭建完整的应用界面。
🗂️ 1. 菜单栏
Qt 中的菜单栏是通过 QMenuBar 这个类来实现的。一个主窗口最多只有一个菜单栏,位于主窗口顶部、主窗口标题栏下面。
菜单栏中包含菜单,菜单中包含菜单项。
📌 工具栏与菜单栏的关系 :工具栏本质上就是把菜单栏中一些比较常用的选项,直接放到工具栏里面,直接点工具栏中的选项能快速生效。
1.1 创建菜单栏
方式一 :菜单栏的创建可以借助于 QMainWindow 类提供的 menuBar() 函数来实现。menuBar() 函数原型如下:
cpp
QMenuBar * menuBar() const
方式二 :在堆上动态创建,使用 setMenuBar 把菜单栏放到窗口中。
⚠️ 内存泄露问题 :如果我们创建的项目没有勾选自动生成 ui 文件,此时的代码是 OK 的;但是如果勾选了自动生成 ui 文件,上述代码会引起内存泄露问题。因为此时 Qt 已经给你生成一个
QMenuBar了,之前程序自己已经创建好了一个QMenuBar,当设置新的QMenuBar时,就会导致旧的QMenuBar脱离 Qt 的对象树了,意味着后续就无法对这个对象进行释放了。上述程序如果窗口关闭,对象树释放,此时进程也就结束了,进程结束,自然所有内存都回收系统了,上述内存泄露不会造成太多影响。但是如果这样的程序出现在一个多窗口的程序中,如果涉及到多个窗口的跳转切换(窗口的频繁创建和销毁),上述内存泄露可能就会更加严重一些。
创建菜单栏的规范写法:
cpp
QMenuBar* menuBar = this->menuBar();
this->setMenuBar(menuBar);
💡 说明 :如果
QMenuBar已经存在,直接获取并返回;如果QMenuBar不存在,就先创建一个,再返回。即使如此,还是应该规范写法。
1.2 在菜单栏中添加菜单
创建菜单,并通过 QMenu 提供的 addMenu() 函数来添加菜单。
示例:
cpp
// 创建菜单并通过 addMenu() 添加
//1.创建菜单栏
QMenuBar* menubar = menuBar();
//将菜单栏放入窗口中
this->setMenuBar(menubar);
//创建菜单
QMenu* menu1 = new QMenu("文件");
QMenu* menu2 = new QMenu("编辑");
QMenu* menu3 = new QMenu("构建");
//添加菜单到菜单栏中
menubar->addMenu(menu1);
menubar->addMenu(menu2);
menubar->addMenu(menu3);
1.3 创建菜单项
在 Qt 中,并没有专门的菜单项类,可以通过 QAction 类,抽象出公共的动作。如在菜单中添加菜单项。
💡 提示 :
QAction可以给菜单栏使用,也可以给工具栏使用。
示例:
cpp
// 代码位置:创建菜单项(添加子菜单、添加快捷键、添加主窗口、添加分割线、添加图标)
//创建菜单项
QAction* act1 = new QAction("open");
QAction* act2 = new QAction("close");
QAction* act3 = new QAction("create");
//将菜单项添加到菜单上
menu1->addAction(act1);
menu1->addAction(act2);
menu1->addAction(act3);
1.4 在菜单项之间添加分割线
在菜单项之间可以添加分割线。分割线如下图所示,添加分割线是通过 QMenu 类提供的 addSeparator() 函数来实现。

示例:
cpp
// 添加分割线
//将菜单项添加到菜单上
menu1->addAction(act1);
menu1->addSeparator();//在open和close中间添加分割线
menu1->addAction(act2);
menu1->addSeparator();//在close和create中间添加分割线
menu1->addAction(act3);
1.5 综合示例
在窗口上创建一个菜单栏,在菜单栏中添加一些菜单,在某一个菜单中添加一些菜单项。
1、新建 Qt 项目
📌 注意 :此时新建项目时选择的基类是
QMainWindow。2、在 "mainwindow.cpp" 文件中创建菜单和中央控件
- 创建一个菜单栏,一个菜单。
- 两个菜单项:保存、加载。
- 创建一个
QTextEdit作为窗口的中央控件。
cpp
// 代码位置:MainWindow 构造函数中创建菜单栏、菜单、菜单项和中央控件
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QMenu>
#include<QMenuBar>
#include<QAction>
#include<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);
QMenu* menu1 = new QMenu("视图");
menubar->addMenu(menu1);
QMenu* menu2 = new QMenu("工具");
menubar->addMenu(menu2);
//创建菜单项
QAction* action1 = new QAction("保存");
QAction* action2 = new QAction("加载");
QAction* action3 = new QAction("创建");
//将三个菜单项加入到菜单menu中
menu->addAction(action1);
menu->addAction(action2);
menu->addAction(action3);
//创建中央控件
QTextEdit* edit = new QTextEdit(this);
this->setCentralWidget(edit);
edit->setPlaceholderText("此处编写文本内容");
}
MainWindow::~MainWindow()
{
delete ui;
}
3、给 action 添加一些动作
cpp
// 连接信号槽,点击 action 时触发一定的效果
connect(action1, &QAction::triggered, this, &MainWindow::save);
connect(action2, &QAction::triggered, this, &MainWindow::load);
实现这两个槽函数:
- 使用
QFileDialog来实现选择文件的效果。getSaveFileName用于保存文件的场景,此时的对话框可以输入文件名。getOpenFileName用于打开文件的场景,此时的对话框可以获取到鼠标选择的文件名。
- 搭配 C++ 标准库的文件操作实现文件读写。
cpp
void MainWindow::save()
{
//弹出对话框,选择写入文件的路径
QFileDialog* dialog = new QFileDialog(this);
QString filename = dialog->getSaveFileName(this,"保存文件","D:/Qt/tmp/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,"加载文件","D:/Qt/tmp/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);
}
✅ 执行效果:执行程序,可以看到此时就可以通过程序来保存/加载文件了,并且对文件进行编辑。
🛠️ 2. 工具栏
工具栏是应用程序中集成各种功能实现快捷键使用的一个区域。可以有多个,也可以没有,它并不是应用程序中必须存在的组件。它是一个可移动的组件,它的元素可以是各种窗口组件,它的元素通常以图标按钮的方式存在。

📌 说明 :工具栏往往是和菜单栏搭配使用的,菜单栏中的
QAction也可以出现在工具栏中。
2.1 创建工具栏
调用 QMainWindow 类的 addToolBar() 函数来创建工具栏,每增加一个工具栏都需要调用一次该函数。
如添加两个工具栏:
cpp
// 添加两个工具栏
QToolBar* toolbar1 = new QToolbar(this);
QToolBar* toolbar2 = new QToolbar(this);
this->addToolBar(toolbar1);
this->addToolBar(toolbar2);
2.2 设置停靠位置
工具栏停靠位置的设置有两种方式。一种是在创建工具栏的同时指定停靠的位置,另一种是通过 QToolBar 类提供的 setAllowedAreas() 函数来设置。
方式一:创建工具栏的同时指定其停靠的位置。
在创建工具栏的同时,也可以设置工具栏的位置,其默认位置是在窗口的最上面。工具栏允许停靠的区域由 QToolBar 类提供的 allowAreas() 函数决定,其中可以设置的位置包括:
Qt::LeftToolBarArea:停靠在左侧Qt::RightToolBarArea:停靠在右侧Qt::TopToolBarArea:停靠在顶部Qt::BottomToolBarArea:停靠在底部Qt::AllToolBarAreas:以上四个位置都可停靠
示例:
cpp
// 创建工具栏的同时指定停靠位置
QToolBar* toolBar1 = new QToolBar(this);
QToolBar* toolBar2 new QToolBar(this);
//创建工具栏的同时,指定工具栏在左侧显示
this->addToolBar(Qt::LeftToolBarArea,toolBar1);
//创建工具栏的同时,指定工具栏在左侧显示
this->addToolBar(Qt::RightToolBarArea,toolBar1);
方式二 :使用 QToolBar 类提供的 setAllowedAreas() 函数设置停靠位置。
示例:
cpp
// 使用 setAllowedAreas() 设置停靠位置
QToolBar* toolbar1 = new QToolBar(this);
QToolBar* toolbar2 = new QToolBar(this);
this->addToolBar(toolbar1);
this0>addToolBar(toolbar2);
//工具栏在左侧
toolbar1->setAllowedAreas(Qt::LeftToolBarArea);
//工具栏在右侧
toolbar1->setAllowedAreas(Qt::RightToolBarArea);
🚅 说明 :在创建工具栏的同时指定其停靠的位置,指的是程序运行时工具栏默认所在的位置;而使用
setAllowedAreas()函数设置停靠位置,指的是工具栏允许其所能停靠的位置。📌 补充 :菜单栏使用
set创建是因为一个界面菜单栏只有一个,但是其他的使用add是因为可以设置多个。
2.3 设置浮动属性
工具栏的浮动属性可以通过 QToolBar 类提供的 setFloatable() 函数来设置。setFloatable() 函数原型为:
cpp
void setFloatable(bool floatable)
参数:
true:浮动false:不浮动
示例:
cpp
// 设置浮动属性
QToolBar* toolbar1 = new QToolBar(this);
QToolBar* toolbar2 = new QToolBar(this);
this->addToolBar(Qt::LeftToolBarArea,toolbar1);
this->addToolBar(Qt::RightToolBarArea,toolbar2);
toolbar1->setFloatable(true);//允许工具栏浮动
toolbar2->setFloatable(false);//不允许菜单栏浮动
2.4 设置移动属性
设置工具栏的移动属性可以通过 QToolBar 类提供的 setMovable() 函数来设置。setMovable() 函数原型为:
cpp
void setMovable(bool movable)
参数:
true:移动false:不移动
📌 说明:若设置工具栏为不移动状态,则设置其停靠位置的操作就不会生效,所以设置工具栏的移动属性类似于总开关的效果。
示例:
cpp
// 代码位置:设置移动属性
QToolBar* toolbar1 = new QToolBar(this);
QToolBar* toolbar2 = new QToolBar(this);
this->addToolBar(Qt::LeftToolBarArea,toolbar1);
this->addToolBar(Qt::RightToolBarArea,toolbar2);
toolbar1->setMovable(true);//允许工具栏移动
toolbar2->setMovable(false);//不允许工具栏移动
2.5 综合示例
cpp
//工具栏
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QAction>
#include<QToolBar>
#include<QPushButton>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//设置窗口大小
resize(800,600);
QToolBar* toolbar = new QToolBar(this);
//设置工具栏的位置:默认是在窗口的上方,此处设置在左侧
this->addToolBar(Qt::LeftToolBarArea,toolbar);
//设置工具栏的停靠位置 设置工具栏只允许在窗口的左右停靠
toolbar->setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea);
//设置工具栏的浮动特性
toolbar->setFloatable(true);
//设置工具栏的移动(总开关)
toolbar->setMovable(true);
//设置工具栏的内容
QAction* open = new QAction("open",this);
QAction* create = new QAction("create",this);
toolbar->addAction(open);
//在open和create之间添加分割线
toolbar->addSeparator();
toolbar->addAction(create);
//工具栏也可以添加控件
QPushButton* btn = new QPushButton("保存",this);
toolbar->addWidget(btn);
}
MainWindow::~MainWindow()
{
delete ui;
}

📊 3. 状态栏
状态栏是应用程序中输出简要信息的区域。一般位于主窗口的最底部,一个窗口中最多只能有一个状态栏。在 Qt 中,状态栏是通过 QStatusBar 类来实现的。
在状态栏中可以显示的消息类型有:
- 实时消息:如当前程序状态
- 永久消息:如程序版本号、机构名称
- 进度消息:如进度条提示、百分比提示
3.1 状态栏的创建
状态栏的创建是通过 QMainWindow 类提供的 statusBar() 函数来创建。
示例:
cpp
//创建状态栏
QStatusBar* stbar = statusBar();
//将状态栏置于窗口中
setStatusBar(stbar);
3.2 在状态栏中显示实时消息
在状态栏中显示实时消息是通过 showMessage() 函数来实现。
示例:
cpp
//显示实时消息
//状态栏中显示大约2秒的"have a good day!"
stbar->showMessage("have a good day",2000);//参数2的单位是毫秒
3.3 在状态栏中显示永久消息
在状态栏中可以显示永久消息,此处的永久消息是通过标签来显示的。
示例:
cpp
// 代码位置:显示永久消息(使用标签)
//创建状态栏
QStatusBar* stbar = statusBar();
//将状态栏置于窗口中
setStatusBar(stbar);
//显示永久消息
QLabel* label = new QLabel("提示消息",this);
//将标签放入状态栏中
stbar->addWidget(label);

📌 补充:可以调整显示消息的位置。
cpp
//将创建的标签放入到状态栏的右侧
QLabel* label = new QLabel("右侧提示消息",this);
stbar->addPermanentWidget(label);

🪟 4. 浮动窗口
在 Qt 中,浮动窗口也称之为铆接部件 。浮动窗口是通过 QDockWidget 类来实现浮动的功能。浮动窗口一般是位于核心部件的周围,可以有多个。
4.1 浮动窗口的创建
浮动窗口的创建是通过 QDockWidget 类提供的构造方法 QDockWidget() 函数动态创建的。
示例:
cpp
//创建浮动窗口
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QDockWidget>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//浮动窗口
QDockWidget* dockwidget = new QDockWidget("浮动窗口",this);
//将浮动窗口设置到当前窗口中
addDockWidget(Qt::BottomDockWidgetArea,dockwidget);
}
MainWindow::~MainWindow()
{
delete ui;
}

4.2 设置停靠的位置
浮动窗口是位于中心部件的周围。可以通过 QDockWidget 类中提供 setAllowedAreas() 函数设置其允许停靠的位置。其中可以设置允许停靠的位置有:
Qt::LeftDockWidgetArea:停靠在左侧Qt::RightDockWidgetArea:停靠在右侧Qt::TopDockWidgetArea:停靠在顶部Qt::BottomDockWidgetArea:停靠在底部Qt::AllDockWidgetAreas:以上四个位置都可停靠
示例:设置浮动窗口只允许上下停靠
cpp
// 代码位置:设置浮动窗口停靠位置
//设置浮动窗口的停靠区域,只允许上下停靠
dockwidget->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
💬 5. 对话框
5.1 对话框介绍
对话框是 GUI 程序中不可或缺的组成部分。一些不适合在主窗口实现的功能组件可以设置在对话框中。对话框通常是一个顶层窗口,出现在程序最上层,用于实现短期任务或者简洁的用户交互。
Qt 常用的内置对话框有:QFileDialog(文件对话框)、QColorDialog(颜色对话框)、QFontDialog(字体对话框)、QInputDialog(输入对话框)和 QMessageBox(消息框)。
💡 理解 :对话框往往是用户和用户之间进行"短平快"的操作。总体来说,基于
QDialog作为父类创建出来的程序窗口和之前通过QWidget创建出来的非常相似。📌 补充 :实际开发过程中,更多的情况下,往往不是直接在创建项目的时候继承自
Dialog,而是在代码中,创建额外的类,让额外的类继承自QDialog。主窗口一般不会作为一个对话框,主窗口可以产生一些其他的对话框。
5.2 对话框的分类
对话框分为模态对话框 和非模态对话框。
💡 核心理解:模态(modal)就是一个 bool 值。
- 模态:弹出对话框的时候,此时用户无法操作父窗口,必须得完成对话框内部的操作,关闭对话框后,才能操作。用于特别关键的场合,用户必须做出决策。
- 非模态:弹出对话框时,用户可以操作父窗口。用于不是特别关键的场景。
📌 注意 :前面写的代码都是非模态对话框。使用
dialog->exec()就是将对话框设置为模态对话框。
5.2.1 模态对话框
模态对话框指的是:显示后无法与父窗口进行交互,是一种阻塞式 的对话框。使用 QDialog::exec() 函数调用。
模态对话框适用于必须依赖用户选择的场合,比如消息显示、文件选择、打印设置等。
示例 :
1、新建 Qt 项⽬,在 ui ⽂件中的菜单栏中设置两个菜单:"⽂件" 和 "编辑",在 菜单 "⽂件" 下新建菜单项:"创建" 并将菜单项 "新建" 置于⼯具栏中 ; 如下图⽰:

2、在 mainwindow.cpp ⽂件中实现:当点击 "新建" 时,弹出⼀个模态对话框;
cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QMenu>
#include<QMenuBar>
#include<QToolBar>
#include<QAction>
#include<QDialog>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//创建菜单栏
QMenuBar* menubar = new QMenuBar(this);
//创建来两个菜单
QMenu* menu1 = new QMenu("文件");
QMenu* menu2 = new QMenu("编辑");
//将两个菜单添加到菜单栏中
menubar->addMenu(menu1);
menubar->addMenu(menu2);
//创建一个菜单项
QAction* create = new QAction("create",this);
//将菜单项添加到菜单栏中
menu1->addAction(create);
this->setMenuBar(menubar);
//当点击"create"时,弹出一个模态对话框,在菜单项中,当点击之后就会触发triggered信号
connect(create,&QAction::triggered,[=](){
QDialog dlg(this);
dlg.resize(200,100);
dlg.setWindowTitle("模态对话框");
dlg.exec();
});
}
MainWindow::~MainWindow()
{
delete ui;
}

📌 说明 :在菜单项中,点击菜单项时就会触发
triggered()信号。
5.2.2 非模态对话框
非模态对话框显示后独立存在,可以同时与父窗口进行交互,是一种非阻塞式 对话框,使用 QDialog::show() 函数调用。
非模态对话框一般在堆上 创建,这是因为如果创建在栈上时,弹出的非模态对话框就会一闪而过。同时还需要设置 Qt::WA_DeleteOnClose 属性,目的是:当创建多个非模态对话框时(如打开了多个非模态窗口),为了避免内存泄漏要设置此属性。
非模态对话框适用于特殊功能设置的场合,比如查找操作、属性设置等。
示例:
cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QMenu>
#include<QMenuBar>
#include<QToolBar>
#include<QAction>
#include<QDialog>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//创建菜单栏
QMenuBar* menubar = new QMenuBar(this);
//创建来两个菜单
QMenu* menu1 = new QMenu("文件");
QMenu* menu2 = new QMenu("编辑");
//将两个菜单添加到菜单栏中
menubar->addMenu(menu1);
menubar->addMenu(menu2);
//创建一个菜单项
QAction* create = new QAction("create",this);
//将菜单项添加到菜单栏中
menu1->addAction(create);
this->setMenuBar(menubar);
// //模态对话框 - 阻塞式对话框
// //当点击"create"时,弹出一个模态对话框,在菜单项中,当点击之后就会触发triggered信号
// connect(create,&QAction::triggered,[=](){
// QDialog dlg(this);
// dlg.resize(300,100);
// dlg.setWindowTitle("模态对话框");
// dlg.exec();
// });
//非模态对话框 - 非阻塞式对话框
connect(create,&QAction::triggered,[=](){
//非模态对话框 - 为了防止对话框一闪而过,创建在堆区
QDialog* dlg = new QDialog(this);
dlg->resize(300,100);//调整非模态对话框尺寸
//当dlg2无限创建时(即一直不断的打开关闭窗口)
//设置下面的这个属性就可以在关闭非模态对话框时释放这个对象
dlg->setAttribute(Qt::WA_DeleteOnClose);
dlg->setWindowTitle("非模态对话框");
dlg->show();
});
}
MainWindow::~MainWindow()
{
delete ui;
}

5.2.3 混合属性对话框
混合属性对话框同时具有模态对话框和非模态对话框的属性,对话框的生成和销毁具有非模态对话框属性,功能上具有模态对话框的属性。
使用 QDialog::setModal() 函数可以创建混合特性的对话框。通常,创建对话框时需要指定对话框的父组件。
示例:
cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QMenu>
#include<QMenuBar>
#include<QToolBar>
#include<QAction>
#include<QDialog>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//创建菜单栏
QMenuBar* menubar = new QMenuBar(this);
//创建来两个菜单
QMenu* menu1 = new QMenu("文件");
QMenu* menu2 = new QMenu("编辑");
//将两个菜单添加到菜单栏中
menubar->addMenu(menu1);
menubar->addMenu(menu2);
//创建一个菜单项
QAction* create = new QAction("create",this);
//将菜单项添加到菜单栏中
menu1->addAction(create);
this->setMenuBar(menubar);
connect(create,&QAction::triggered,[=](){
QDialog* dialog = new QDialog(this);
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->setModal(true);
dialog->resize(400,100);
dialog->setWindowTitle("混合模态对话框");
dialog->show();
});
}
MainWindow::~MainWindow()
{
delete ui;
}

5.3 Qt 内置对话框
Qt 提供了多种可复用的对话框类型,即 Qt 标准对话框。Qt 标准对话框全部继承于 QDialog 类。常用标准对话框如下:

5.3.1 消息对话框 QMessageBox
消息对话框是应用程序中最常用的界面元素。消息对话框主要用于为用户提示重要信息,强制用户进行选择操作。
QMessageBox 类中定义了静态成员函数,可以直接调用创建不同风格的消息对话框,其中包括:
Question:用于正常操作过程中的提问Information:用于报告正常运行信息Warning:用于报告非关键错误Critical:用于报告严重错误
对应的函数原型:

示例 1:问题提示消息对话框
cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QPushButton>
#include<QMessageBox>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//设置窗口大小
resize(800,600);
//创建一个按钮
QPushButton* btn = new QPushButton("消息对话框",this);
//创建一个消息对话框
QMessageBox* msg = new QMessageBox(this);
//设置消息对话框的标题
msg->setWindowTitle("Warning Message");
//设置消息对话框的内容
msg->setText("Error Message!");
//设置消息对话框的类型
msg->setIcon(QMessageBox::Question);
//在此对话框上设置按钮
msg->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
connect(btn,&QPushButton::clicked,[=](){
msg->show();
});
}
MainWindow::~MainWindow()
{
delete ui;
}
实现效果如下:

其中可以设置的按钮的类型如下:
| 常量 | 值 | 描述 |
|---|---|---|
QMessageBox::Ok |
0x00000400 |
一个 "OK" 按钮,定义为 AcceptRole |
QMessageBox::Open |
0x00002000 |
一个 "Open" 按钮,定义为 AcceptRole |
QMessageBox::Save |
0x00000800 |
一个 "Save" 按钮,定义为 AcceptRole |
QMessageBox::Cancel |
0x00400000 |
一个 "Cancel" 按钮,定义为 RejectRole |
QMessageBox::Close |
0x00200000 |
一个 "Close" 按钮,定义为 RejectRole |
QMessageBox::Discard |
0x00800000 |
一个 "Discard" 或 "Don't Save" 按钮(取决于平台),定义为 DestructiveRole |
QMessageBox::Apply |
0x02000000 |
一个 "Apply" 按钮,定义为 ApplyRole |
QMessageBox::Reset |
0x04000000 |
一个 "Reset" 按钮,定义为 ResetRole |
QMessageBox::RestoreDefaults |
0x08000000 |
一个 "Restore Defaults" 按钮,定义为 ResetRole |
QMessageBox::Help |
0x01000000 |
一个 "Help" 按钮,定义为 HelpRole |
QMessageBox::SaveAll |
0x00001000 |
一个 "Save All" 按钮,定义为 AcceptRole |
QMessageBox::Yes |
0x00004000 |
一个 "Yes" 按钮,定义为 YesRole |
QMessageBox::YesToAll |
0x00008000 |
一个 "Yes to All" 按钮,定义为 YesRole |
QMessageBox::No |
0x00010000 |
一个 "No" 按钮,定义为 NoRole |
QMessageBox::NoToAll |
0x00020000 |
一个 "No to All" 按钮,定义为 NoRole |
QMessageBox::Abort |
0x00040000 |
一个 "Abort" 按钮,定义为 RejectRole |
QMessageBox::Retry |
0x00080000 |
一个 "Retry" 按钮,定义为 AcceptRole |
QMessageBox::Ignore |
0x00100000 |
一个 "Ignore" 按钮,定义为 AcceptRole |
QMessageBox::NoButton |
0x00000000 |
一个无效的按钮 |
📌 补充:其中可以设置的按钮的类型如上表所示,可以更改消息对话框中的按钮类型,可以更改消息对话框中的按钮类型。
cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QPushButton>
#include<QMessageBox>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//设置窗口大小
resize(800,600);
//创建一个按钮
QPushButton* btn = new QPushButton("消息对话框",this);
//创建一个消息对话框
QMessageBox* msg = new QMessageBox(this);
//设置消息对话框的标题
msg->setWindowTitle("Warning Message");
//设置消息对话框的内容
msg->setText("Error Message!");
//设置消息对话框的类型
msg->setIcon(QMessageBox::Question);
//在此对话框上设置按钮
//msg->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
msg->setStandardButtons(QMessageBox::Open | QMessageBox::Close);
connect(btn,&QPushButton::clicked,[=](){
msg->show();
});
}
MainWindow::~MainWindow()
{
delete ui;
}

示例 2:信息提示消息对话框
cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QPushButton>
#include<QMessageBox>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//设置窗口大小
resize(800,600);
//创建一个按钮
QPushButton* btn = new QPushButton("消息对话框",this);
//创建一个消息对话框
QMessageBox* msg = new QMessageBox(this);
//设置消息对话框的标题
msg->setWindowTitle("Warning Message");
//设置消息对话框的内容
msg->setText("Error Message!");
//设置消息对话框的类型
msg->setIcon(QMessageBox::Information);
//在此对话框上设置按钮
msg->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
//msg->setStandardButtons(QMessageBox::Open | QMessageBox::Close);
connect(btn,&QPushButton::clicked,[=](){
msg->show();
});
}
MainWindow::~MainWindow()
{
delete ui;
}

示例 3:警告信息消息对话框
cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QPushButton>
#include<QMessageBox>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//设置窗口大小
resize(800,600);
//创建一个按钮
QPushButton* btn = new QPushButton("消息对话框",this);
//创建一个消息对话框
QMessageBox* msg = new QMessageBox(this);
//设置消息对话框的标题
msg->setWindowTitle("Warning Message");
//设置消息对话框的内容
msg->setText("Error Message!");
//设置消息对话框的类型
msg->setIcon(QMessageBox::Warning);
//在此对话框上设置按钮
msg->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
//msg->setStandardButtons(QMessageBox::Open | QMessageBox::Close);
connect(btn,&QPushButton::clicked,[=](){
msg->show();
});
}
MainWindow::~MainWindow()
{
delete ui;
}

示例 4:错误提示消息对话框
cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QPushButton>
#include<QMessageBox>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//设置窗口大小
resize(800,600);
//创建一个按钮
QPushButton* btn = new QPushButton("消息对话框",this);
//创建一个消息对话框
QMessageBox* msg = new QMessageBox(this);
//设置消息对话框的标题
msg->setWindowTitle("Warning Message");
//设置消息对话框的内容
msg->setText("Error Message!");
//设置消息对话框的类型
msg->setIcon(QMessageBox::Critical);
//在此对话框上设置按钮
msg->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
//msg->setStandardButtons(QMessageBox::Open | QMessageBox::Close);
connect(btn,&QPushButton::clicked,[=](){
msg->show();
});
}
MainWindow::~MainWindow()
{
delete ui;
}

5.3.2 颜色对话框 QColorDialog
颜色对话框的功能是允许用户选择颜色。继承自 QDialog 类。
💡 说明 :Qt 中
QColorDialog内置了颜色调色板。

常用方法介绍:
QColorDialog(QWidget *parent = nullptr):创建对象的同时设置父对象QColorDialog(const QColor &initial, QWidget *parent = nullptr):创建对象的同时通过QColor对象设置默认颜色和父对象void setCurrentColor(const QColor &color):设置当前颜色对话框QColor currentColor() const:获取当前颜色对话框QColor getColor(const QColor &initial = Qt::white, QWidget *parent = nullptr, const QString &title = QString(), QColorDialog::ColorDialogOptions options = ColorDialogOptions()):打开颜色选择对话框,并返回一个QColor对象
参数说明:
initial:设置默认颜色parent:设置父对象title:设置对话框标题options:设置选项
void open(QObject *receiver, const char *member):打开颜色对话框
💡 理解 :
getColor()这个函数就能够弹出一个模态对话框,用户选择颜色后,点击确定,对话框关闭,getColor返回的值就是用户返回的颜色值。该函数是一个静态函数,不用创建对话框对象就能直接调用。📌 补充 :
QColor(ARGB 1, 0, 1, 0),alpha - A(不透明度),使用 0-1 这样的小数表示 RGB 的值了。
示例 1:
cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QPushButton>
#include<QColorDialog>
#include<QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//设置窗口大小
resize(800,600);
QPushButton* btn = new QPushButton("颜色对话框",this);
//创建颜色对话框
QColorDialog* cdlg = new QColorDialog(this);
connect(btn,&QPushButton::clicked,[=](){
//打开颜色对话框
QColor color = cdlg->getColor(QColor(0,255,0));
qDebug()<<"r= "<<color.red();
qDebug()<<"g= "<<color.green();
qDebug()<<"b= "<<color.blue();
});
}
MainWindow::~MainWindow()
{
delete ui;
}

示例 2:
cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QPushButton>
#include<QColorDialog>
#include<QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//设置窗口大小
resize(800,600);
QPushButton* btn = new QPushButton("颜色对话框",this);
//创建颜色对话框
QColorDialog* cdlg = new QColorDialog(this);
connect(btn,&QPushButton::clicked,[=](){
//打开颜色对话框
QColor color = cdlg->getColor(QColor(200,100,150));
qDebug()<<"r= "<<color.red();
qDebug()<<"g= "<<color.green();
qDebug()<<"b= "<<color.blue();
});
}
MainWindow::~MainWindow()
{
delete ui;
}

5.3.3 文件对话框 QFileDialog
文件对话框用于应用程序中需要打开一个外部文件或需要将当前内容存储到指定的外部文件。
常用方法介绍:
- 打开文件(一次只能打开一个文件)
cpp
QString getOpenFileName(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = Options())
- 打开多个文件(一次可以打开多个文件)
cpp
QStringList getOpenFileNames(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = Options())
- 保存文件
cpp
QString getSaveFileName(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = Options())
参数说明:
- 参数 1:
parent:父亲 - 参数 2:
caption:对话框标题 - 参数 3:
dir:默认打开的路径 - 参数 4:
filter:文件过滤器
示例 1:打开文件
cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QPushButton>
#include<QFileDialog>
#include<QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//设置主窗口大小
resize(800,600);
//创建一个按钮
QPushButton* btn = new QPushButton("文件",this);
//创建一个文件窗口
QFileDialog* fdlg = new QFileDialog(this);
connect(btn,&QPushButton::clicked,[=](){
QString str = fdlg->getOpenFileName(this,//父亲
"文件",//对话框标题
"D:\\Qt\\tmp",//打开的文件路径
"*.txt"//文件过滤器
);
});
}
MainWindow::~MainWindow()
{
delete ui;
}

示例 2:保存文件
cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QPushButton>
#include<QFileDialog>
#include<QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//设置主窗口大小
resize(800,600);
//创建一个按钮
QPushButton* btn = new QPushButton("文件",this);
//创建一个文件窗口
QFileDialog* fdlg = new QFileDialog(this);
connect(btn,&QPushButton::clicked,[=](){
QString str = fdlg->getSaveFileName(this,//父亲
"文件",//对话框标题
"D:\\Qt\\tmp",//打开的文件路径
"*.txt"//文件过滤器
);
});
}
MainWindow::~MainWindow()
{
delete ui;
}
5.3.4 字体对话框 QFontDialog
Qt 中提供了预定义的字体对话框类 QFontDialog,用于提供选择字体的对话框部件。
示例:
cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QPushButton>
#include<QFontDialog>
#include<QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//设置主窗口大小
resize(800,600);
QPushButton* btn = new QPushButton("选择字体",this);
connect(btn,&QPushButton::clicked,[=](){
//使用QFontDialog类的静态方法getFont打开字体对话框并设置默认格式
bool flag;//由于getFont方法的第一个参数为bool类型,所以有此定义
QFont font = QFontDialog::getFont(&flag,QFont("华文楷体",36));
//将【char*】转化为【QString】的方法 - .toUtf8().data()
qDebug()<<"字体: "<< font.family().toUtf8().data();
//pointSize() -> 获取字号
qDebug()<<"字号: "<< font.pointSize();
//bold() -> 判断字体是否加粗
qDebug()<<"是否加粗: "<<font.bold();
//italic() -> 判断字体是否是倾斜
qDebug()<<"是否倾斜: "<< font.italic();
});
}
MainWindow::~MainWindow()
{
delete ui;
}


💡 理解:字体对话框允许用户选择字体、字号、粗体、斜体等属性,常用于文本编辑器等需要设置文字样式的场景。
5.3.5 输入对话框 QInputDialog
Qt 中提供了预定义的输入对话框类:QInputDialog,用于进行临时数据输入的场合。
💡 理解:让用户输入一个具体的数据,该数据可以是整数,可以是浮点数,还可以是字符串(类似于下拉框)。
常用方法介绍:
- 双精度浮点型输入数据对话框
cpp
double getDouble(QWidget *parent, const QString &title, const QString &label, double value = 0, double min = -2147483647, double max = 2147483647, int decimals = 1, bool *ok = nullptr, Qt::WindowFlags flags = Qt::WindowFlags());
- 整型输入数据对话框
cpp
int getInt(QWidget *parent, const QString &title, const QString &label, int value = 0, int min = -2147483647, int max = 2147483647, int step = 1, bool *ok = nullptr, Qt::WindowFlags flags = Qt::WindowFlags());
- 选择条目型输入数据框
cpp
QString getItem(QWidget *parent, const QString &title, const QString &label, const QStringList &items, int current = 0, bool editable = true, bool *ok = nullptr, Qt::WindowFlags flags = Qt::WindowFlags(), Qt::InputMethodHints inputMethodHints = Qt::ImhNone);
参数说明:
parent:父亲title:对话框标题label:对话框标签items:可供选择的条目
示例 1:浮点型数据输入对话框
cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QPushButton>
#include<QInputDialog>
#include<QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//设置主窗口大小
resize(600,400);
//创建一个按钮
QPushButton* btn = new QPushButton("输入框",this);
QInputDialog* ldlg = new QInputDialog(this);
connect(btn,&QPushButton::clicked,[=](){
double d = ldlg->getDouble(this,"输入框","浮点数");
qDebug()<<"d = "<<d;
});
}
MainWindow::~MainWindow()
{
delete ui;
}

示例 2:整型数据输入对话框
cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QPushButton>
#include<QInputDialog>
#include<QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//设置主窗口大小
resize(600,400);
//创建一个按钮
QPushButton* btn = new QPushButton("输入框",this);
QInputDialog* ldlg = new QInputDialog(this);
connect(btn,&QPushButton::clicked,[=](){
//double d = ldlg->getDouble(this,"输入框","浮点数");
int i = ldlg->getInt(this,"输入框","Int");
qDebug()<<"i = "<< i;
});
}
MainWindow::~MainWindow()
{
delete ui;
}

示例 3:打开选择条目对话框
cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QPushButton>
#include<QInputDialog>
#include<QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
//设置主窗口大小
resize(600,400);
//创建一个按钮
QPushButton* btn = new QPushButton("输入框",this);
QInputDialog* ldlg = new QInputDialog(this);
// connect(btn,&QPushButton::clicked,[=](){
// //double d = ldlg->getDouble(this,"输入框","浮点数");
// int i = ldlg->getInt(this,"输入框","Int");
// qDebug()<<"i = "<< i;
// });
connect(btn,&QPushButton::clicked,[=](){
QStringList items;
items<<tr("Spring")<<tr("Summer")<<tr("Fall")<<tr("Winder");
QString item = ldlg->getItem(this,"输入框","Item",items);
qDebug()<<"item: "<<item.toUtf8().data();
});
}
MainWindow::~MainWindow()
{
delete ui;
}
🎯 6. 小总结
通过本章的学习,我们系统地掌握了 Qt 窗口系统的核心组件:
- 菜单栏 (
QMenuBar):主窗口顶部的菜单容器,一个窗口最多一个,通过menuBar()或setMenuBar()创建。 - 工具栏 (
QToolBar):可移动、可浮动的快捷操作区域,可以有多个,通过addToolBar()创建。 - 状态栏 (
QStatusBar):窗口底部的信息输出区域,一个窗口最多一个,通过statusBar()创建。 - 浮动窗口 (
QDockWidget):中心部件周围的铆接部件,可以有多个,通过QDockWidget()动态创建。 - 对话框 (
QDialog):用于短期任务或用户交互的顶层窗口,分为模态、非模态和混合属性三种。
💡 核心要点:
- 菜单栏用
set创建(唯一),其他组件用add创建(可多个)。- 模态对话框用
exec()调用(阻塞式),非模态对话框用show()调用(非阻塞式)。- 非模态对话框要在堆上创建并设置
Qt::WA_DeleteOnClose属性避免内存泄漏。QAction是抽象动作,可同时用于菜单栏和工具栏。
📝 7. 经典面试题
面试题 1:QMainWindow 和 QWidget 有什么区别?
解答 :QMainWindow 继承自 QWidget,是专门为主窗口设计的类。它提供了一个预定义的布局,包含菜单栏、工具栏、状态栏、浮动窗口和中心部件等标准组件。而 QWidget 是一个通用的窗口基类,没有这些预定义布局。如果需要一个包含完整窗口框架的应用,应该使用 QMainWindow;如果只是一个简单的控件或子窗口,使用 QWidget 即可。
面试题 2:模态对话框和非模态对话框有什么区别?分别如何使用?
解答 :模态对话框显示后无法与父窗口交互,是一种阻塞式对话框,使用 QDialog::exec() 函数调用,适用于必须依赖用户选择的场合(如消息显示、文件选择)。非模态对话框显示后可以同时与父窗口交互,是非阻塞式对话框,使用 QDialog::show() 函数调用,适用于特殊功能设置的场合(如查找操作、属性设置)。非模态对话框需要在堆上创建,并设置 Qt::WA_DeleteOnClose 属性避免内存泄漏。
面试题 3:为什么创建菜单栏时推荐使用 menuBar() 而不是 new QMenuBar?
解答 :因为 menuBar() 函数会先检查当前窗口是否已经存在 QMenuBar,如果存在则直接返回已有的对象,不存在才创建新的。如果使用 new QMenuBar 手动创建,在勾选了自动生成 ui 文件的项目中,Qt 已经自动生成了一个 QMenuBar,此时再设置新的 QMenuBar 会导致旧的 QMenuBar 脱离 Qt 的对象树,无法被正确释放,造成内存泄漏。
面试题 4:QAction 在 Qt 中的作用是什么?
解答 :QAction 是 Qt 中抽象公共动作的类,它封装了一个用户可触发的动作(如保存、加载、新建等)。QAction 可以同时添加到菜单栏和工具栏中,实现"一处定义,多处使用"的效果。当用户点击菜单项或工具栏按钮时,都会触发 QAction 的 triggered() 信号,开发者只需连接一次信号槽即可同时处理两种触发方式。
面试题 5:如何设置工具栏的停靠位置?创建时指定和 setAllowedAreas() 有什么区别?
解答 :设置工具栏停靠位置有两种方式:一种是在创建工具栏的同时通过 addToolBar() 的第二个参数指定默认停靠位置;另一种是通过 setAllowedAreas() 函数设置允许停靠的区域。两者的区别在于:创建时指定的是程序运行时工具栏默认所在的位置 ,而 setAllowedAreas() 设置的是工具栏允许停靠的所有位置 (用户可以在这些位置之间拖动工具栏)。另外,如果设置了工具栏为不可移动状态(setMovable(false)),则停靠位置的设置不会生效。



