Qt作为跨平台GUI开发框架,提供了丰富的窗口组件封装,其中QMainWindow是最常用的主窗口类,其内置的菜单栏、工具栏、状态栏等组件,能快速搭建标准化应用界面。本文将从组件原理、创建步骤、核心API到综合实战,详细讲解Qt窗口组件的使用,适配Qt 5.14及以上版本,新手可直接复制代码实操。

本文核心内容:QMainWindow组件结构、菜单栏/工具栏/状态栏/浮动窗口的创建与配置、Qt内置对话框(消息框、颜色框、文件框等)实战,附带完整可运行代码及常见问题解决。

一、QMainWindow核心结构概述

QMainWindow继承自QWidget,是专门为主窗口程序设计的类,提供了预定义的布局结构,无需手动搭建基础框架,其核心组件包括5部分:

  • 菜单栏(Menu Bar):位于窗口顶部,最多1个,用于承载菜单和菜单项,实现功能分类(如文件、编辑、帮助)。

  • 工具栏(Tool Bars):可多个,支持移动、浮动,通常以图标/按钮形式呈现常用功能快捷键。

  • 状态栏(Status Bar):位于窗口底部,最多1个,用于显示实时消息、永久提示或进度信息。

  • 浮动窗口(Dock Widget):可多个,围绕中心部件停靠,支持拖拽浮动,适合放置辅助功能(如日志、属性面板)。

  • 中心部件(Central Widget):窗口核心区域,唯一且必填,可放置文本编辑、图表等核心功能组件。

组件布局示意图(对应QMainWindow默认结构):

Window Title → 菜单栏 → 工具栏区域 → 浮动窗口区域 → 中心部件 → 状态栏

二、菜单栏(QMenuBar)实战

2.1 核心原理

菜单栏通过QMenuBar类实现,一个QMainWindow只能有一个菜单栏。菜单(QMenu)是菜单栏的子项,菜单项(无专门类,用QAction抽象)是菜单的子项,QAction可复用(同时用于菜单栏和工具栏),支持快捷键、图标绑定。

2.2 创建方式(两种)

方式一:使用QMainWindow内置接口(推荐)

QMainWindow提供menuBar()函数,直接获取/创建菜单栏,无需手动分配父对象,简化代码:


#include <QMainWindow>

#include <QMenuBar>

#include <QMenu>

#include <QAction>



MainWindow::MainWindow(QWidget *parent)

    : QMainWindow(parent)

{

    // 1. 获取/创建菜单栏

    QMenuBar *menuBar = this->menuBar();

    // 2. 将菜单栏设置到窗口(内置接口可省略,建议显式设置,兼容低版本)

    this->setMenuBar(menuBar);



    // 3. 创建菜单(参数为菜单文本,可加快捷键提示,如"文件(&F)")

    QMenu *fileMenu = new QMenu("文件(&F)", this);

    QMenu *editMenu = new QMenu("编辑(&E)", this);

    QMenu *helpMenu = new QMenu("帮助(&H)", this);



    // 4. 将菜单添加到菜单栏

    menuBar->addMenu(fileMenu);

    menuBar->addMenu(editMenu);

    menuBar->addMenu(helpMenu);



    // 5. 创建菜单项(QAction)

    QAction *newAction = new QAction("新建(&N)", this);

    QAction *openAction = new QAction("打开(&O)", this);

    QAction *saveAction = new QAction("保存(&S)", this);

    QAction *exitAction = new QAction("退出(&X)", this);



    // 6. 给菜单项设置快捷键(两种方式)

    newAction->setShortcut(QKeySequence("Ctrl+N"));

    openAction->setShortcut(Qt::CTRL + Qt::Key_O);



    // 7. 添加菜单项到菜单,添加分割线区分功能组

    fileMenu->addAction(newAction);

    fileMenu->addAction(openAction);

    fileMenu->addAction(saveAction);

    fileMenu->addSeparator(); // 分割线

    fileMenu->addAction(exitAction);

}

方式二:堆上动态创建(灵活控制生命周期)

手动new QMenuBar,指定父对象为QMainWindow,适合需要自定义菜单栏生命周期的场景:


// 堆上创建菜单栏,指定父对象为当前窗口

QMenuBar *menuBar = new QMenuBar(this);

this->setMenuBar(menuBar);

// 后续创建菜单、菜单项步骤与方式一一致

2.3 菜单项点击事件(信号槽绑定)

QAction的triggered()信号触发菜单项点击事件,通过connect绑定槽函数,实现具体功能:


// 绑定退出菜单项的点击事件

connect(exitAction, &QAction::triggered, this, &MainWindow::close);



// 自定义槽函数(需在mainwindow.h中声明)

void MainWindow::on_openAction_triggered()

{

    // 打开文件的逻辑,后续结合文件对话框讲解

}

2.4 常见问题

  • 菜单栏不显示:未调用setMenuBar()将菜单栏设置到窗口,或菜单/菜单项未正确添加。

  • 快捷键无效:快捷键设置冲突,或未给QAction绑定父对象(需指定父对象为当前窗口)。

三、工具栏(QToolBar)实战

3.1 核心特点

工具栏通过QToolBar类实现,支持多个工具栏并存,可设置停靠位置、浮动属性、移动属性,组件元素可是QAction或其他控件(如按钮、输入框),适合放置高频使用的功能。

3.2 基础创建与配置


#include <QToolBar>

#include <QPushButton>



MainWindow::MainWindow(QWidget *parent)

    : QMainWindow(parent)

{

    // 1. 创建工具栏,指定父对象

    QToolBar *toolBar1 = new QToolBar(this);

    QToolBar *toolBar2 = new QToolBar(this);



    // 2. 将工具栏添加到窗口(addToolBar()可指定默认停靠位置)

    // 方式一:添加时指定默认停靠位置(顶部、底部、左侧、右侧)

    this->addToolBar(Qt::TopToolBarArea, toolBar1); // 默认顶部

    this->addToolBar(Qt::LeftToolBarArea, toolBar2); // 默认左侧



    // 3. 设置工具栏允许停靠的位置(可多个位置,用|连接)

    toolBar1->setAllowedAreas(Qt::TopToolBarArea | Qt::BottomToolBarArea); // 仅允许上下停靠

    toolBar2->setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea); // 仅允许左右停靠



    // 4. 设置浮动属性(默认允许浮动)

    toolBar1->setFloatable(false); // 禁止浮动

    toolBar2->setFloatable(true); // 允许浮动



    // 5. 设置移动属性(总开关,禁止移动则停靠设置无效)

    toolBar1->setMovable(false); // 禁止移动

    toolBar2->setMovable(true); // 允许移动



    // 6. 给工具栏添加QAction(复用菜单栏的QAction)

    QAction *newAction = new QAction("新建", this);

    QAction *openAction = new QAction("打开", this);

    toolBar1->addAction(newAction);

    toolBar1->addSeparator(); // 分割线

    toolBar1->addAction(openAction);



    // 7. 给工具栏添加自定义控件(如按钮)

    QPushButton *saveBtn = new QPushButton("保存", this);

    toolBar2->addWidget(saveBtn);

}

3.3 关键API说明

  • addToolBar(Qt::ToolBarArea area, QToolBar *toolbar):指定默认停靠位置添加工具栏,Qt::ToolBarArea包含Top、Bottom、Left、Right、All(所有位置)。

  • setAllowedAreas():设置工具栏可停靠的位置,仅当setMovable(true)时生效。

  • setFloatable():设置是否允许工具栏脱离窗口浮动(浮动时可拖拽到任意位置)。

  • addWidget():添加自定义控件到工具栏,突破QAction的限制。

四、状态栏(QStatusBar)实战

4.1 核心功能

状态栏通过QStatusBar类实现,一个QMainWindow只能有一个状态栏,用于显示三类信息:实时消息(如操作提示,自动消失)、永久消息(如版本号,固定显示)、进度信息(如文件加载进度)。

基础创建与信息显示


#include <QStatusBar>

#include <QLabel>



MainWindow::MainWindow(QWidget *parent)

    : QMainWindow(parent)

{

    // 1. 创建状态栏(QMainWindow内置statusBar()函数,无需手动new)

    QStatusBar *statusBar = this->statusBar();

    // 2. 设置状态栏到窗口(内置接口可省略,显式设置更稳妥)

    this->setStatusBar(statusBar);



    // 3. 显示实时消息(参数2:显示时长,单位ms,0表示永久显示)

    statusBar->showMessage("欢迎使用Qt窗口程序", 3000); // 显示3秒后消失



    // 4. 显示永久消息(通过QLabel添加,默认左侧)

    QLabel *leftLabel = new QLabel("当前状态:正常", this);

    statusBar->addWidget(leftLabel);



    // 5. 显示右侧永久消息(addPermanentWidget()专门用于右侧)

    QLabel *rightLabel = new QLabel("版本:v1.0.0", this);

    statusBar->addPermanentWidget(rightLabel);

}

4.2 进度信息显示(结合QProgressBar)

通过添加QProgressBar到状态栏,实现进度提示(如文件上传、数据加载):


#include <QProgressBar>



// 添加进度条到状态栏

QProgressBar *progressBar = new QProgressBar(this);

progressBar->setRange(0, 100); // 设置进度范围

progressBar->setValue(50); // 当前进度50%

statusBar->addWidget(progressBar);



// 动态更新进度(示例:模拟加载)

QTimer *timer = new QTimer(this);

connect(timer, &QTimer::timeout, [=](){

    static int progress = 0;

    progress++;

    progressBar->setValue(progress);

    if (progress == 100) {

        timer->stop();

        statusBar->showMessage("加载完成", 2000);

    }

});

timer->start(100); // 每100ms更新一次进度

五、浮动窗口(QDockWidget)实战

5.1 核心作用

浮动窗口(铆接部件)通过QDockWidget类实现,可多个并存,围绕中心部件停靠,支持拖拽浮动,适合放置辅助功能(如日志面板、属性设置面板),不占用中心部件的核心空间。

基础创建与配置


#include <QDockWidget>

#include <QTextEdit>



MainWindow::MainWindow(QWidget *parent)

    : QMainWindow(parent)

{

    // 1. 创建浮动窗口(参数1:窗口标题,参数2:父对象)

    QDockWidget *dockWidget = new QDockWidget("日志面板", this);

    // 2. 设置浮动窗口的中心部件(必须设置,否则窗口为空)

    QTextEdit *logEdit = new QTextEdit(this);

    logEdit->setPlaceholderText("日志信息将显示在这里...");

    dockWidget->setWidget(logEdit);



    // 3. 添加浮动窗口到窗口,指定默认停靠位置

    this->addDockWidget(Qt::BottomDockWidgetArea, dockWidget);



    // 4. 设置允许停靠的位置(多个位置用|连接)

    dockWidget->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);



    // 5. 设置是否可关闭(默认可关闭)

    dockWidget->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable);

}

5.2 关键API说明

  • setWidget():给浮动窗口设置核心部件,必须调用,否则浮动窗口为空。

  • setFeatures():设置浮动窗口的功能,如是否可关闭、可移动、可浮动。

  • addDockWidget():添加浮动窗口,Qt::DockWidgetArea与工具栏的停靠位置一致。

六、Qt内置对话框(QDialog)实战

对话框是独立于主窗口的顶层窗口,用于短期交互(如提示、选择、输入),Qt提供多种内置对话框,无需手动绘制,直接调用即可,所有内置对话框均继承自QDialog类。

对话框分为三类:模态对话框(阻塞父窗口,必须处理后才能返回)、非模态对话框(不阻塞父窗口,可同时操作)、混合属性对话框(兼具两者特性)。

6.1 模态对话框(常用)

通过QDialog::exec()调用,阻塞父窗口,适合必须用户确认的场景(如消息提示、确认退出):


#include <QDialog>

#include <QAction>



// 绑定菜单项点击事件,弹出模态对话框

connect(exitAction, &QAction::triggered, [=](){

    QDialog dlg(this);

    dlg.setWindowTitle("确认退出");

    dlg.resize(200, 100);

    // 模态显示,阻塞父窗口

    dlg.exec();

});

6.2 非模态对话框

通过QDialog::show()调用,不阻塞父窗口,需在堆上创建(栈上创建会一闪而过),并设置Qt::WA_DeleteOnClose属性,避免内存泄漏:


// 弹出非模态对话框

connect(newAction, &QAction::triggered, [=](){

    // 堆上创建,指定父对象

    QDialog *dlg = new QDialog(this);

    dlg->setWindowTitle("新建文档");

    dlg->resize(300, 200);

    // 设置关闭时释放对象,避免内存泄漏

    dlg->setAttribute(Qt::WA_DeleteOnClose);

    // 非模态显示,不阻塞父窗口

    dlg->show();

});

6.3 常用内置对话框实战

6.3.1 消息对话框(QMessageBox)

最常用的对话框,用于提示消息、询问用户、警告、报错,提供静态成员函数,无需手动创建对象,支持自定义图标、按钮。


#include <QMessageBox>



// 1. 询问对话框(Question)

connect(openAction, &QAction::triggered, [=](){

 // 静态函数getQuestion,返回用户点击的按钮

    QMessageBox::StandardButton btn = QMessageBox::question(

        this,

        "询问",

        "确定要打开文件吗?",

        QMessageBox::Ok | QMessageBox::Cancel // 显示的按钮

    );

    // 判断用户点击的按钮

    if (btn == QMessageBox::Ok) {

        statusBar()->showMessage("正在打开文件...", 2000);

    }

});



// 2. 警告对话框(Warning)

QMessageBox::warning(this, "警告", "文件格式错误,请重新选择!", QMessageBox::Ok);



// 3. 错误对话框(Critical)

QMessageBox::critical(this, "错误", "文件打开失败,权限不足!", QMessageBox::Ok);



// 4. 信息对话框(Information)

QMessageBox::information(this, "信息", "文件保存成功!", QMessageBox::Ok);

6.3.2 文件对话框(QFileDialog)

用于打开文件、保存文件,支持单文件、多文件选择,可设置文件过滤器(如仅显示.jpg、.txt文件),结合文件操作实现读写功能。


#include <QFileDialog>

#include <fstream>

#include <QTextEdit>



// 全局/类成员变量,用于存储中心文本编辑组件

QTextEdit *centralEdit;



MainWindow::MainWindow(QWidget *parent)

    : QMainWindow(parent)

{

    // 设置中心部件为文本编辑框(用于显示文件内容)

    centralEdit = new QTextEdit(this);

    this->setCentralWidget(centralEdit);

}



// 1. 打开文件(单文件)

void MainWindow::openFile()

{

    // 静态函数getOpenFileName,返回选中的文件路径

    QString filePath = QFileDialog::getOpenFileName(

        this,

        "打开文件",

        "C:/Users", // 默认打开路径

        "文本文件 (*.txt);;图片文件 (*.jpg *.png);;所有文件 (*.*)" // 文件过滤器

    );

    if (filePath.isEmpty()) {

        return; // 用户取消选择

    }



    // 读取文件内容(使用C++标准库)

    std::ifstream file(filePath.toStdString().c_str());

    if (!file.is_open()) {

        QMessageBox::critical(this, "错误", "文件打开失败!");

        return;

    }

    std::string content;

    std::string line;

    while (std::getline(file, line)) {

        content += line + "\n";

    }

    file.close();

    // 显示到文本编辑框

 centralEdit->setPlainText(QString::fromStdString(content));

}



// 2. 保存文件

void MainWindow::saveFile()

{

    QString filePath = QFileDialog::getSaveFileName(

        this,

        "保存文件",

        "C:/Users",

        "文本文件 (*.txt)"

    );

    if (filePath.isEmpty()) {

        return;

    }



    // 写入文件内容

    std::ofstream file(filePath.toStdString().c_str());

    if (!file.is_open()) {

        QMessageBox::critical(this, "错误", "文件保存失败!");

 return;

    }

    QString text = centralEdit->toPlainText();

    file << text.toStdString();

    file.close();

    QMessageBox::information(this, "信息", "文件保存成功!");

}

6.3.3 颜色对话框(QColorDialog)

用于选择颜色,返回QColor对象,可用于设置文本颜色、背景颜色等:


#include <QColorDialog>



// 选择颜色并设置文本颜色

connect(colorAction, &QAction::triggered, [=](){

 // 静态函数getColor,默认颜色为红色,返回选中的颜色

    QColor color = QColorDialog::getColor(QColor(255, 0, 0), this, "选择颜色");

    if (color.isValid()) { // 判断用户是否选择了有效颜色(未取消)

        // 设置文本编辑框的文本颜色

        QPalette palette = centralEdit->palette();

        palette.setColor(QPalette::Text, color);

        centralEdit->setPalette(palette);

    }

});

6.3.4 字体对话框(QFontDialog)

用于选择字体、字号、加粗/倾斜等样式,返回QFont对象:


#include <QFontDialog>



// 选择字体并设置文本字体

connect(fontAction, &QAction::triggered, [=](){

    bool ok; // 用于判断用户是否确认选择

    // 静态函数getFont,默认字体为华文行楷、36号,返回选中的字体

    QFont font = QFontDialog::getFont(&ok, QFont("华文行楷", 36), this, "选择字体");

    if (ok) { // 用户确认选择

        centralEdit->setFont(font);

    }

});

6.3.5 输入对话框(QInputDialog)

用于临时输入数据,支持整型、浮点型、字符串、下拉选择等类型:


#include <QInputDialog>



// 1. 整型输入

int num = QInputDialog::getInt(this, "输入整数", "请输入年龄:", 18, 0, 100, 1, &ok);

if (ok) {

    qDebug() << "输入的年龄:" << num;

}



// 2. 下拉选择输入

QStringList items = {"Spring", "Summer", "Fall", "Winter"};

QString item = QInputDialog::getItem(this, "选择季节", "请选择季节:", items, 0, true, &ok);

if (ok) {

    qDebug() << "选择的季节:" << item;

}

七、综合实战:完整记事本程序

整合上述所有组件,实现一个简易记事本,支持新建、打开、保存文件,设置字体、颜色,显示日志和状态栏提示,完整代码如下:

7.1 mainwindow.h


#ifndef MAINWINDOW_H

#define MAINWINDOW_H



#include <QMainWindow>

#include <QTextEdit>

#include <QStatusBar>



QT_BEGIN_NAMESPACE

namespace Ui { class MainWindow; }

QT_END_NAMESPACE



class MainWindow : public QMainWindow

{

    Q_OBJECT



public:

    MainWindow(QWidget *parent = nullptr);

    ~MainWindow();



private slots:

    void openFile(); // 打开文件

    void saveFile(); // 保存文件

    void setTextFont(); // 设置字体

    void setTextColor(); // 设置颜色



private:

    Ui::MainWindow *ui;

    QTextEdit *centralEdit; // 中心文本编辑框

    QStatusBar *statusBar; // 状态栏

};



#endif // MAINWINDOW_H

7.2 mainwindow.cpp


#include "mainwindow.h"

#include "ui_mainwindow.h"

#include <QMenuBar>

#include <QMenu>

#include <QAction>

#include <QToolBar>

#include <QStatusBar>

#include <QLabel>

#include <QDockWidget>

#include <QTextEdit>

#include <QMessageBox>

#include <QFileDialog>

#include <QFontDialog>

#include <QColorDialog>

#include <fstream>



MainWindow::MainWindow(QWidget *parent)

    : QMainWindow(parent)

    , ui(new Ui::MainWindow)

{

    ui->setupUi(this);

    this->setWindowTitle("Qt简易记事本");

    this->resize(800, 600);



    // 1. 中心部件(文本编辑框)

    centralEdit = new QTextEdit(this);

    centralEdit->setPlaceholderText("请输入文本内容...");

    this->setCentralWidget(centralEdit);



    // 2. 菜单栏

    QMenuBar *menuBar = this->menuBar();

    this->setMenuBar(menuBar);

    QMenu *fileMenu = new QMenu("文件(&F)", this);

    QMenu *editMenu = new QMenu("编辑(&E)", this);

    QMenu *helpMenu = new QMenu("帮助(&H)", this);

    menuBar->addMenu(fileMenu);

    menuBar->addMenu(editMenu);

    menuBar->addMenu(helpMenu);



    // 菜单栏动作

    QAction *openAction = new QAction("打开(&O)", this);

    QAction *saveAction = new QAction("保存(&S)", this);

    QAction *exitAction = new QAction("退出(&X)", this);

    QAction *fontAction = new QAction("设置字体", this);

    QAction *colorAction = new QAction("设置颜色", this);

    QAction *aboutAction = new QAction("关于", this);



    // 设置快捷键

    openAction->setShortcut(Qt::CTRL + Qt::Key_O);

    saveAction->setShortcut(Qt::CTRL + Qt::Key_S);

    exitAction->setShortcut(Qt::CTRL + Qt::Key_Q);



    // 添加动作到菜单

    fileMenu->addAction(openAction);

    fileMenu->addAction(saveAction);

    fileMenu->addSeparator();

    fileMenu->addAction(exitAction);

    editMenu->addAction(fontAction);

    editMenu->addAction(colorAction);

    helpMenu->addAction(aboutAction);



    // 3. 工具栏

    QToolBar *toolBar = new QToolBar(this);

 this->addToolBar(Qt::TopToolBarArea, toolBar);

    toolBar->addAction(openAction);

 toolBar->addAction(saveAction);

    toolBar->addSeparator();

    toolBar->addAction(fontAction);

    toolBar->addAction(colorAction);



    // 4. 状态栏

    statusBar = this->statusBar();

    this->setStatusBar(statusBar);

    QLabel *statusLabel = new QLabel("状态:就绪", this);

    statusBar->addWidget(statusLabel);

 statusBar->showMessage("欢迎使用简易记事本", 3000);



    // 5. 浮动窗口(日志面板)

    QDockWidget *dockWidget = new QDockWidget("日志面板", this);

    QTextEdit *logEdit = new QTextEdit(this);

7.3 运行效果

  1. 窗口包含菜单栏、工具栏、中心文本编辑区、状态栏、底部浮动日志面板;

  2. 支持打开/保存txt文件,设置文本字体和颜色;

  3. 工具栏可移动,浮动窗口可停靠/浮动,状态栏显示操作提示。

八、常见问题汇总

  1. 中心部件不显示:未调用setCentralWidget(),或中心部件未设置父对象。

  2. 对话框一闪而过:非模态对话框在栈上创建,需改为堆上创建并设置Qt::WA_DeleteOnClose属性。

  3. 文件读写失败:路径包含中文(可改用Qt的QFile类替代C++标准库,避免编码问题)。

  4. 工具栏无法移动:未设置setMovable(true),或设置了setFloatable(false)不影响移动。

  5. 状态栏消息不消失:showMessage()的第二个参数设为0,需手动调用clearMessage()清除。

九、总结

本文详细讲解了Qt QMainWindow的核心组件及内置对话框的使用,从基础创建、API解析到综合实战,覆盖了Qt窗口开发的常用场景。Qt的组件封装完善,无需重复造轮子,通过组合菜单栏、工具栏、状态栏等组件,可快速搭建标准化GUI应用。

后续可拓展功能:添加文本查找替换、快捷键自定义、日志记录、皮肤切换等,进一步提升应用的实用性。如果遇到问题,可结合Qt官方文档(Qt 5.14 Documentation)查询API细节,或在评论区留言交流。

代码已测试可运行,适配Qt 5.14~Qt 6.x版本,新手可直接复制到项目中修改使用。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐