上一章节我们已经掌握了 Qt 工程项目的创建与基础界面元素(菜单栏、工具条)的搭建,这些组件为应用程序提供了核心操作入口。本节课将在此基础上,进一步完善界面布局 ------ 导航工具条能让用户快速切换功能模块,状态栏则用于展示关键状态信息,二者结合将大幅提升应用的实用性和用户体验。下面我们通过实战案例,详细讲解这两个组件的搭建流程。
核心类介绍
本章节中介绍的导航条依然采用工具条进行构建,本节新学的核心类如下:
1. QLabel 类
QLabel是 Qt 最基础的 "内容显示类",支持文本、图片、HTML 内容展示,在状态栏中主要用于承载静态文本(如版本号)和动态更新的内容(如当前时间)。
2. QStatusBar 类
QStatusBar是主窗口底部的 "状态信息管理类",专门用于展示临时提示、永久信息或动态状态,是应用程序与用户的 "信息反馈窗口"。
3.QDateTime类
QDateTime是 Qt 提供的 "日期时间处理类",用于获取系统当前日期时间、对日期时间进行计算(如增减时间)和格式化输出,是实现状态栏 "动态时间显示" 功能的核心依赖。
工具条实战
实战内容
本节课的实战内容是在上一节课的基础上,再创建一个导航工具条,以及创建一个状态栏,要求如下:
1、导航工具条上放置两个按钮,分别是"建模"、"拓扑",代表两个不同的功能模块;
2、导航工具条上的功能按钮有两个状态,选中、未选中时要有区分;
3、工具条上的按钮以图标的形式显示,并且在图标下放显示出操作的名称;
4、工具条默认显示在窗口左侧位置,工具条禁止移动到其他的区域;
5、状态栏中左侧显示临时信息,右侧展示当前时间;

实战步骤
头文件引入
根据本节课需要用到的Qt类,我们需要引入以下头文件
cpp
#include <QLabel>
#include <QStatusBar>
#include <QDateTime>
同样,我们分别定义两个单独的函数来实现导航工具条和状态栏的逻辑,函数分别定义为:
cpp
void createNaviToolBar();// 导航工具条
void createStatusBar(); // 状态栏
createNaviToolBar()的实现
通过该函数实现工具条的创建、按钮的添加以及状态的切换。根据上节课学习的搭建工具条的方式创建一个导航的工具条,样式同样设置为图标在上、文字在下的样式。但是要注意的我们将工具栏的位置设置在窗口左侧,同时禁止工具条移动,可以通过setMovable设置工具条是不可移动的。设置了该属性值为false,则工具条不允许拖拽移动。
cpp
QToolBar* naviToolBar = addToolBar(QStringLiteral("导航条"));
addToolBar(Qt::LeftToolBarArea, naviToolBar);
naviToolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
naviToolBar->setMovable(false);
我们再给工具条定义一个标题,这里我们要用到QLabel类,QLabel 是 Qt 框架中用于显示文本或图像的基础控件,继承自 QFrame。它通常用于显示静态文本、图片、链接或简单的富文本内容,是界面设计中最常用的组件之一。我们在整个开发中经常会用到该类,也会用到该类的不同用法,此处只是用来显示工具条的标题文本。
我们先创建一个QLabel对象,然后通过QToolBar的addWidget方法将其添加到工具栏上。QToolBar::addWidget(QWidget *widget) 方法的作用是将一个任意的 Qt 控件添加到工具栏中。这个方法会将传入的控件作为工具栏的一部分显示,并按照添加顺序排列在工具栏上。
cpp
QLabel* titleLabel = new QLabel("导航", naviToolBar);
naviToolBar->addWidget(titleLabel);
依次添加"建模"、"拓扑"个菜单项,按照前面课程学到的QAction的定义方法进行定义和添加,但要注意因为我们需要用到菜单项状态的切换,所以每个按钮找两个不同颜色的图片以区分状态。先把图标放到我们前面定义的image目录下,在添加到资源qrc中(按照前面课程的内容自行添加,)。

前面的课程中定义快捷工具条我们学到的是先创建一个QAction对象,然后通过setIcon函数为其设置图片,这节课我们使用QAction的另外一个构造函数:
++QAction(const QIcon &icon , const QString &text , QObject *parent = nullptr)++
通过这个构造函数可以直接创建一个带图标的按钮,让后加入到导航菜单中。 这里关键的一点是,第一个参数的QIcon图标需要有两个状态,我们会用到QIcon的一个方法:
++addPixmap(const QPixmap &pixmap, QIcon::Mode mode = Normal, QIcon::State state = Off)。++
- 第一个参数 pixmap:表示当前要添加的图片资源(QPixmap 对象),即这个图片会在特定的 mode 和 state 下显示。例如,选中状态的图标图片、未选中状态的图标图片等。
- 第二个参数 mode:表示图标所处的「模式」,由 QIcon::Mode 枚举定义,常用取值:
QIcon::Normal:正常模式(默认值),控件处于启用且未被选中 /hover 的状态。
QIcon::Disabled:禁用模式,控件被禁用(setEnabled(false))时显示。
QIcon::Active:激活模式,鼠标 hover 或聚焦到控件时显示。
QIcon::Selected:选中模式,某些控件(如菜单项)被选中时显示(较少用,通常用 State 区分选中)。
- 第三个参数 state:表示图标所处的「激活状态」,由 QIcon::State 枚举定义,取值:
QIcon::Off:未激活(默认值,如按钮未选中)。
QIcon::On:激活(如按钮选中)。
第二个参数我们保持QIcon::Normal即可,如果将来需要处理禁用、hover 等状态,再指定对应模式,我们分别定义激活、未激活状态。按照上面的逻辑我们先定义两个QIcon对象。然后创建QAction,将QAction对象添加的导航栏,并设置其为可点击。
cpp
// 添加菜单项
QIcon modelIcon, topologyIcon;
modelIcon.addPixmap(QPixmap(":/SubCfgTool/image/model.png"), QIcon::Normal, QIcon::Off);
modelIcon.addPixmap(QPixmap(":/SubCfgTool/image/model_sel.png"), QIcon::Normal, QIcon::On);
topologyIcon.addPixmap(QPixmap(":/SubCfgTool/image/topology.png"), QIcon::Normal, QIcon::Off);
topologyIcon.addPixmap(QPixmap(":/SubCfgTool/image/topology_sel.png"), QIcon::Normal, QIcon::On);
QAction* modelAct = new QAction(modelIcon, QStringLiteral("建模"), this);
QAction* topologyAct = new QAction(topologyIcon, QStringLiteral("拓扑"), this);
naviToolBar->addAction(modelAct);
naviToolBar->addAction(topologyAct);
// 设置菜单具备可点击状态
modelAct->setCheckable(true);
topologyAct->setCheckable(true);
将createNaviToolBar()函数放入到构造函数中调用,然后编译运行测试一下效果。

从测试效果来看,按钮可以点击并切换状态,但是两个按钮没有互斥,即同一时间两个按钮都可以被选中,后面我们学到信号与槽的机制时再优化这部分内容。还有个问题是整个页面的布局比较紧凑,需要调整一下布局的样式,这里引入一个新的成员函数setStyleSheet,这个函数是QToolBar继承自QWidget的函数。setStyleSheet 是 Qt 框架中用于设置控件外观的核心函数,可以参考Qt Style Sheets官方文档。

每个界面组件都可以用上面的模型来表示。
CONTENT属性:是显示内容矩形区域,如QLabel用于显示文字的区域。min-width、max-width、min-height和max-height属性定义最大/最小宽度或高度,就是定义这个矩形区。
PADDING属性:是包围content的矩形区域,通过padding属性可以定义padding的宽度,padding-top、padding-bottom、padding-left、padding-right分别定义padding的上下左右。
BORDER属性:是包围padding的边框,通过border属性(border-width、border-style、border-color)可以定义边框的线宽、、线型和颜色,也可以分别定义border的上、下、左、右的线宽和颜色。
MARGIN属性:是border之外的父组件之间的空白边距,可以分别定义上、下、左、右的边距大小。
对于导航工具条的布局我们做两个调整,首先是将"建模"、"拓扑"这两个菜单项的Padding加大,让菜单项四周有一些留白,同时我们加大菜单项之间的间距,用到了spacing属性,这属于布局的范围,后面讲到布局会详细讲解,这里只需要按代码实现即可。
cpp
naviToolBar->setStyleSheet("padding:2px;spacing:16px;");
createStatusBar()的实现
因为QMainWindow创建的时候已经为我们创建了状态栏,所以我们只需要定义一个QStatusBar对象,通过QMainWindow的statusBar()方法返回 QStatusBar的对象。
cpp
QStatusBar* statusBar = this->statusBar();
这里会涉及两个重要的方法:
- **
addWidget():**添加左侧控件,受临时信息影响,适合非永久内容。 - **
addPermanentWidget():**添加右侧永久控件,不受临时信息影响,适合固定内容。

下面我们在状态栏的左侧添加一个状态信息展示标签、在状态栏的右侧加一个时间显示。
定义一个全局的QLabel,命名为QLabel* StatusInfoLbl,用于显示状态信息。
cpp
StatusInfoLbl = new QLabel(QStringLiteral("已就绪"));
statusBar->addWidget(StatusInfoLbl);
定义一个QLabel,用于显示时间,并通过addPermanentWidget函数添加至状态栏,默认显示在右侧。 因为还没有学到信号和槽,我们先不做时间的更新,只显示个当前的时间即可。
cpp
// 创建时间标签
QLabel* timeLabel = new QLabel(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"));
// 直接添加到状态栏右侧(无需伸缩控件)
statusBar->addPermanentWidget(timeLabel);
将createStatusBar()函数放入构造函数中调用,并测试运行,效果如下:

本章小结
本节课的内容是 Qt 界面开发的重要延伸,导航工具条解决了多功能模块的快速切换问题,状态栏实现了用户操作反馈与关键信息展示,二者结合大幅提升了应用的实用性与用户体验。这类布局在各类桌面应用(如编辑器、设计软件、管理工具)中广泛应用,掌握后可快速搭建结构清晰、交互友好的基础界面框架。同时,通过本节课的学习,进一步熟悉了 Qt 控件的属性配置、资源管理与样式调整方法,为后续信号与槽、动态交互等进阶内容打下了坚实基础。
附录
SubCfgTool.h代码:
cpp
#pragma once
#include <QtWidgets/QMainWindow>
//#include "ui_SubCfgTool.h"
#include <QMenuBar>
#include <QMenu>
#include <QAction>
#include <QToolBar>
#include <QLabel>
#include <QStatusBar>
#include <QDateTime>
class SubCfgTool : public QMainWindow
{
Q_OBJECT
public:
SubCfgTool(QWidget *parent = nullptr);
~SubCfgTool();
void createMenuBar();
void createToolBar();
void createNaviToolBar();
void createStatusBar();
private:
QAction* createProjAct;
QAction* openProjAct;
QAction* quitAct;
QLabel* StatusInfoLbl;
};
SubCfgTool.cpp代码:
cpp
#include "SubCfgTool.h"
SubCfgTool::SubCfgTool(QWidget *parent)
: QMainWindow(parent)
{
// ui.setupUi(this);
createMenuBar();
createToolBar();
createNaviToolBar();
createStatusBar();
}
SubCfgTool::~SubCfgTool()
{}
void SubCfgTool::createMenuBar()
{
// 菜单栏
QMenuBar* menuBar = this->menuBar();
// 菜单
QMenu* fileMenu = menuBar->addMenu("文件");
QMenu* helpMenu = menuBar->addMenu("帮助");
// 定义文件菜单中的菜单项
createProjAct = new QAction("新建项目");
openProjAct = new QAction("打开项目");
quitAct = new QAction("退出");
// 将菜单项加入到文件菜单
fileMenu->addAction(createProjAct);
fileMenu->addAction(openProjAct);
fileMenu->addSeparator();
fileMenu->addAction(quitAct);
// 定义帮助菜单中的菜单项
QAction* aboutAct = new QAction("关于");
// 将菜单加入到帮助菜单项
helpMenu->addAction(aboutAct);
// 添加快捷键
createProjAct->setShortcut(QKeySequence::New);
openProjAct->setShortcuts(QKeySequence::Open);
createProjAct->setAutoRepeat(false);
// 临时测试代码
connect(createProjAct, &QAction::triggered, []() {qDebug() << "Create New Project"; });
// 设置图标
createProjAct->setIcon(QIcon(":/SubCfgTool/image/menu_new.png"));
openProjAct->setIcon(QIcon(":/SubCfgTool/image/menu_open.png"));
}
void SubCfgTool::createToolBar()
{
QToolBar* mainToolBar = new QToolBar(QStringLiteral("工具条"));
mainToolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
addToolBar(Qt::TopToolBarArea, mainToolBar);
mainToolBar->addAction(createProjAct);
mainToolBar->addAction(openProjAct);
mainToolBar->setAllowedAreas(Qt::TopToolBarArea | Qt::BottomToolBarArea);
}
void SubCfgTool::createNaviToolBar()
{
// 创建导航条
QToolBar* naviToolBar = addToolBar(QStringLiteral("导航条"));
addToolBar(Qt::LeftToolBarArea, naviToolBar);
naviToolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
naviToolBar->setMovable(false);
// 添加标题
QLabel* titleLabel = new QLabel("导航", naviToolBar);
naviToolBar->addWidget(titleLabel);
// 添加菜单项
QIcon modelIcon, topologyIcon;
modelIcon.addPixmap(QPixmap(":/SubCfgTool/image/model.png"), QIcon::Normal, QIcon::Off);
modelIcon.addPixmap(QPixmap(":/SubCfgTool/image/model_sel.png"), QIcon::Normal, QIcon::On);
topologyIcon.addPixmap(QPixmap(":/SubCfgTool/image/topology.png"), QIcon::Normal, QIcon::Off);
topologyIcon.addPixmap(QPixmap(":/SubCfgTool/image/topology_sel.png"), QIcon::Normal, QIcon::On);
QAction* modelAct = new QAction(modelIcon, QStringLiteral("建模"), this);
QAction* topologyAct = new QAction(topologyIcon, QStringLiteral("拓扑"), this);
naviToolBar->addAction(modelAct);
naviToolBar->addAction(topologyAct);
// 设置菜单具备可点击状态
modelAct->setCheckable(true);
topologyAct->setCheckable(true);
naviToolBar->setStyleSheet("padding:2px;spacing:16px;");
}
void SubCfgTool::createStatusBar()
{
QStatusBar* statusBar = this->statusBar();
// 左侧状态信息
StatusInfoLbl = new QLabel(QStringLiteral("已就绪"));
statusBar->addWidget(StatusInfoLbl);
// 右侧时间区域
// 创建时间标签
QLabel* timeLabel = new QLabel(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"));
// 直接添加到状态栏右侧(无需伸缩控件)
statusBar->addPermanentWidget(timeLabel);
}