『QT』窗口 (一)

1 窗口介绍
在以往的博客中, 常常一QWidget类进行示例, 而通常情况下, 大部分的窗口都是由QMainWindow类进行的实现, 而QWidget通常以一个子控件(自定义控件)镶嵌在QMainWindow之中;
通常一个QMainWindow布局包含一个WindowTitle窗口标题(通常为系统默认), 一个菜单栏Menu Bar, 多个工具栏Tool Bars, 多个浮动窗口Dock Widgets(铆接部件, 可以认为是Tool Bar与 Central Widget的粘合剂), 一个状态栏Status Bar以及最中心的中心部件Central Widget;
如下图所示:

2 Menu Bar 菜单栏
通常很多软件都会有一个菜单栏, 来赋予一些程序应有的一些功能;

通常一个窗口只会有一个菜单栏Menu Bar, 菜单栏中可以添加菜单, 菜单可以为菜单添加菜单项, 菜单项内可以添加子菜单项;

通常情况下, 主窗口中最多只能有一个菜单栏, 数量为[0, 1], 即可以有也可以没有, 若是有菜单栏的话, 那只能拥有一个菜单栏;
菜单栏通常由QMainWindow类提供的menuBar()来实现;
2.1 创建菜单栏
创建菜单通常有两三种方式:
-
在堆中自动创建
可以手动采用
new的方式进行创建菜单栏;QMenuBar* menubar = new QMenuBar(this); // 创建MenuBar this->setMenuBar(menubar); // 设置MenuBar进当前窗口即 创建一个
QMenuBar对象, 并指名其的父节点为this控件以更好进行内存管理; -
使用函数创建
除了直接在堆上开辟空间创建
QMenuBar以外, 在QMainWindow中提供了一个专门创建QMenuBar的函数;QMenuBar *menuBar() const;使用方式为:
QMenuBar *menubar = this->menuBar(); // 当前窗口是否有menubar, 有则获取, 无则创建并设置进对象树 -
使用
QtDesigner创建菜单栏通常情况下, 当存在
UI文件时将默认存在QMenuBar菜单栏;
可以看到, 可以完全采用
QtDesigner来构建菜单, 菜单项, 甚至是子菜单项;可能使用
QtDesigner来构建菜单或许会有一些Bug, 如菜单项无法使用中文创建或是其他
通常情况下, 若是用代码来创建菜单栏时, 我们推荐使用第二种方式来创建Menubar, 本质原因是, 在上文中我们提到, 在一个窗口内, 最多只能拥有一个Menubar;
而在QtCreator中, 我们可以勾选是否建立UI文件;

当勾选上时, 对应的界面文件中, 将会自带一个QMenuBar;

而当使用setMenuBar()后, 由于原先的Menubar我们无法在替换后再次获取他的指针, 因此无法对其进行销毁释放内存(替换后, 原有的Menubar无法被管理), 从而导致内存泄漏;
若是该窗口是一个高频被打开后销毁的窗口, 将促成严重的内存泄漏问题;
而第二种方式直接调用QMainWindow提供的menuBar(), 当若是该窗口内存在菜单栏时将获取当前窗口内的菜单栏, 若是没有则创建一个菜单栏QMenuBar;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QMenuBar* menuBar = this->menuBar();
}
运行程序结果为:

2.2 创建菜单
可以看到实际上上文所展出的结果并没有菜单栏;
而通常情况, 菜单通常要伴随着菜单才可以显示;
在Qt中, 通常使用addMenu()来为菜单栏添加菜单;
该函数有两种调用方式(重载):
addMenu(QString)addMenu(QMenu*)
无论哪种方式都会将QMenu设置在自己的对象树中, 因此在创建QMenu时无需指名父对象;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 创建菜单栏 - 没有就创建并设置进窗口
QMenuBar* menuBar = this->menuBar();
// 创建菜单
QMenu* menu1 = new QMenu("文件");
QMenu* menu2 = new QMenu("编辑");
QMenu* menu3 = new QMenu("视图");
// 将菜单设置进菜单栏
menuBar->addMenu(menu1);
menuBar->addMenu(menu2);
menuBar->addMenu(menu3);
}
运行结果为:

2.3 添加菜单项
在上文中, 提到, 我们可以对菜单设置对应的菜单项;
通常情况下, 我们采用addAction来为添加菜单项;
在以往中, 当控件存在子控件时, 对应的子控件命名方式往往采用xxxItem的命名方式, 但针对菜单项而言其所使用的是QAction类, 并且通过addAction()方法来添加菜单项;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
/*
* 创建菜单栏 - 没有就创建并设置进窗口
*/
QMenuBar* menuBar = this->menuBar();
/*
* 创建菜单
*/
QMenu* menu1 = new QMenu("文件");
QMenu* menu2 = new QMenu("编辑");
QMenu* menu3 = new QMenu("视图");
/*
* 将菜单设置进菜单栏
*/
menuBar->addMenu(menu1);
menuBar->addMenu(menu2);
menuBar->addMenu(menu3);
/*
* 创建菜单项
*/
// 写法1
QAction* action1 = new QAction("保存");
menu1->addAction(action1);
// 写法2
menu1->addAction("另存为");
menu1->addAction("打开");
}
运行结果为:

2.4 添加子菜单
在Qt中, 可以对一个菜单中添加子菜单, 即 将一个子菜单作为他的菜单项加入进去;
通常同样采用addMenu的方式进行添加;
同样的, 可以对这个子菜单来添加对应的QAction;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
/*
* 创建菜单栏 - 没有就创建并设置进窗口
*/
// ...
/*
* 创建菜单
*/
// ...
/*
* 将菜单设置进菜单栏
*/
// ...
/*
* 创建菜单项
*/
// ...
/*
* 添加子菜单
*/
QMenu* menu1_1 = new QMenu("最近打开");
menu1->addMenu(menu1_1);
/*
* 为子菜单添加菜单项
*/
menu1_1->addAction("./Hello.txt");
menu1_1->addAction("./World.rar");
}
运行结果为:

2.5 为菜单, 菜单项添加分隔线
添加分隔线通常主要通过addSeparator()进行;
可以为菜单, 菜单项来添加分隔线;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
/*
* 创建菜单栏 - 没有就创建并设置进窗口
*/
QMenuBar* menuBar = this->menuBar();
/*
* 创建菜单
*/
QMenu* menu1 = new QMenu("文件");
QMenu* menu2 = new QMenu("编辑");
QMenu* menu3 = new QMenu("视图");
/*
* 将菜单设置进菜单栏
*/
menuBar->addMenu(menu1);
menuBar->addSeparator(); // 添加分隔线
menuBar->addMenu(menu2);
menuBar->addSeparator(); // 添加分隔线
menuBar->addMenu(menu3);
/*
* 创建菜单项
*/
// 写法1
QAction* action1 = new QAction("保存");
menu1->addAction(action1);
// 写法2
menu1->addSeparator(); // 添加分隔线
menu1->addAction("另存为");
menu1->addSeparator(); // 添加分隔线
menu1->addAction("打开");
menu1->addSeparator(); // 添加分隔线
/*
* 添加子菜单
*/
QMenu* menu1_1 = new QMenu("最近打开");
menu1->addMenu(menu1_1);
/*
* 为子菜单添加菜单项
*/
menu1_1->addAction("./Hello.txt");
menu1_1->addSeparator(); // 添加分隔线
menu1_1->addAction("./World.rar");
}
运行结果为:

可以看到, 我们在菜单与菜单间中添加了Separator, 但并未显示, 本质是与系统内置的样式有关;
2.6 菜单项的信号
菜单项作为一个可点击控件, 同样有其对应的信号;
通常最常用的信号为triggered(bool checked=false);
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
// ...
/*
* 绑定槽函数
*/
connect(action1, &QAction::triggered, this, &MainWindow::triggeredHandler);
}
void MainWindow::triggeredHandler()
{
qDebug()<<"保存";
}
运行结果为:

2.7 为菜单, 菜单项添加快捷键
在之前的文章中, 我们采用过ShortCut设置对应的快捷键, 同样的, 我们也可以为菜单/菜单项设置快捷键, 当然可以用ShortCut进行绑定, 但针对菜单而言, 其有更加简便的方式进行操作;
通常只需要在菜单/菜单项添加文本的部分增加一个(&Key)即可;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
/*
* 创建菜单栏 - 没有就创建并设置进窗口
*/
QMenuBar* menuBar = this->menuBar();
/*
* 创建菜单
*/
QMenu* menu1 = new QMenu("文件 (&F)");
QMenu* menu2 = new QMenu("编辑 (&E)");
QMenu* menu3 = new QMenu("视图 (&V)");
/*
* 将菜单设置进菜单栏
*/
menuBar->addMenu(menu1);
menuBar->addSeparator(); // 添加分隔线
menuBar->addMenu(menu2);
menuBar->addSeparator(); // 添加分隔线
menuBar->addMenu(menu3);
/*
* 创建菜单项
*/
// 写法1
QAction* action1 = new QAction("保存 (&S)");
menu1->addAction(action1);
menu1->addSeparator(); // 添加分隔线
// 写法2
menu1->addAction("另存为 (&A)");
menu1->addSeparator(); // 添加分隔线
menu1->addAction("打开 (&O)");
menu1->addSeparator(); // 添加分隔线
/*
* 添加子菜单
*/
QMenu* menu1_1 = new QMenu("最近打开");
menu1->addMenu(menu1_1);
/*
* 为子菜单添加菜单项
*/
menu1_1->addAction("./Hello.txt");
menu1_1->addSeparator(); // 添加分隔线
menu1_1->addAction("./World.rar");
connect(action1, &QAction::triggered, this, &MainWindow::triggeredHandler);
}
void MainWindow::triggeredHandler()
{
qDebug()<<"保存";
}
运行结果为:

当快捷键设置后, 可以通过Alt+对应的快捷键进行使用;
2.7 为菜单, 菜单项设置图标
同样的, 可以为菜单, 菜单项通过setIcon方法对其设置对应的图标, 以增加可用性与增加美观;
可以提前去阿里巴巴矢量图标库中下载对应的Icon并设置QRC资源文件;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
// ...
/*
* 添加Icon
*/
menu1->setIcon(QIcon(":/file.png"));
action1->setIcon(QIcon(":/save.png"));
}
运行结果:
![]()
可以看到, 在设置Icon后, 菜单中的文字标题将会消失不见, 本质上将会被Icon给顶替, 而这种顶替不一定代表一定消失, 在某些系统下, 这些被Icon代替的标题文字将会以ToolTip存在;
也可以手动为对应的菜单或是菜单项设置ToolTip, 此次不做演示;
3 Tool Bar 工具栏
工具栏通常为菜单栏的简化版, 在许多的应用中, 总是会将常用或者主要的菜单功能放置在工具栏中以方便使用;
这里以轻量级编辑器Notepad--为例:

其中红色部分即为工具栏(QToolBar);
工具栏中所存在的各个Icon即为快捷项QAction;
3.1 创建工具栏
通常情况下, 工具栏在QMainWindow中是没有的, 若是需要工具栏需要手动去创建;

创建工具栏时, 采用new的方式创建并通过addToolBar函数将工具栏设置进QMainWindow中, 或者可以直接调用QMainWindow所给的addToolBar(QString)进行创建;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
/*创建工具栏*/
QToolBar* toolbar1 = new QToolBar();
QToolBar* toolbar2 = new QToolBar();
/*设置工具栏*/
this->addToolBar(toolbar1);
this->addToolBar(toolbar2);
}
这里直接采用new的方式并调用addToolBar设置对应的工具栏;
运行结果为:

从运行结果来看, 这段代码并没有报错, 可以成功编译并运行;
本质上在QMainWindow中, 可以存在0~N个QToolBar;
3.2 添加快捷项
运行结果中的工具栏显示的并不明显, 本质上与QMenuBar相同, 其没有对应的QAction进行填充, 因此显得比较不明显;
现在分别为两个QToolBar填充对应的QAction;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
/*创建工具栏*/
QToolBar* toolbar1 = new QToolBar();
QToolBar* toolbar2 = new QToolBar();
/*设置工具栏*/
this->addToolBar(toolbar1);
this->addToolBar(toolbar2);
/*创建QAction*/
QAction* action1 = new QAction("Action1");
QAction* action2 = new QAction("Action2");
QAction* action3 = new QAction("Action3");
QAction* action4 = new QAction("Action4");
/*设置快捷项*/
toolbar1->addAction(action1);
toolbar1->addAction(action2);
toolbar2->addAction(action3);
toolbar2->addAction(action4);
}
运行结果为:

3.3 工具栏的浮动与停靠
可以看到, 实际上在工具栏的侧边, 有一个可拖动标识, 表示可以对其进行拖动;

默认情况下, 工具栏支持浮动与停靠;
-
停靠
停靠即为停靠在窗口的边界, 边界通常分为上下左右四个边界;

默认情况下,
ToolBar停靠在MainWindow的顶部, 但是可以通过属性设置其可以停靠的位置; -
浮动
当工具栏未停靠在任何一个部分时, 称之为浮动状态;

可以为对应的工具栏设置以下属性:
-
setMoveable- 是否可拖动无论是浮动还是拖动停靠四周, 都建立在可拖动的基础上, 当该属性被禁用时, 工具栏将无法拖动;
通常使用
QToolBar::setMoveable(bool)来设置改属性;MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); /*创建工具栏*/ QToolBar* toolbar1 = new QToolBar(); QToolBar* toolbar2 = new QToolBar(); /*设置工具栏*/ this->addToolBar(toolbar1); this->addToolBar(toolbar2); /*创建QAction*/ QAction* action1 = new QAction("Action1"); QAction* action2 = new QAction("Action2"); QAction* action3 = new QAction("Action3"); QAction* action4 = new QAction("Action4"); /*设置快捷项*/ toolbar1->addAction(action1); toolbar1->addAction(action2); toolbar2->addAction(action3); toolbar2->addAction(action4); /*设置不可拖动*/ toolbar1->setMovable(false); toolbar2->setMovable(false); }运行结果为:

从结果来看, 当该属性设置为
false时, 可拖动标识消失, 为不可拖动; -
setFloatable- 是否浮动可以使用
setFloatable(bool)来设置工具栏是否可浮动;为
true时表示可浮动, 默认为可浮动状态,false表示无法浮动;MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); /*创建工具栏*/ QToolBar* toolbar1 = new QToolBar(); QToolBar* toolbar2 = new QToolBar(); /*设置工具栏*/ this->addToolBar(toolbar1); this->addToolBar(toolbar2); /*创建QAction*/ QAction* action1 = new QAction("Action1"); QAction* action2 = new QAction("Action2"); QAction* action3 = new QAction("Action3"); QAction* action4 = new QAction("Action4"); /*设置快捷项*/ toolbar1->addAction(action1); toolbar1->addAction(action2); toolbar2->addAction(action3); toolbar2->addAction(action4); /*设置不可浮动*/ toolbar1->setFloatable(false); toolbar2->setFloatable(false); }运行结果为:

-
停靠位置
停靠位置的设置通常有两种方式进行设置, 一种是在通过
addToolBar时进行传参, 另一种方式为通过QToolBar提供的setAllowerAreas进行设置;停靠的位置分别为上下左右;
枚举值 说明 Qt::LeftToolBarArea停靠在左侧 Qt::RightToolBarArea停靠在右侧 Qt::TopToolBarArea停靠在顶部 Qt::BottomToolBarArea停靠在底部 Qt::AllToolBarAreas上下左右均可停靠(设置默认停靠时不能传这个参数) 这些枚举值以二进制的顺序进行枚举, 以方便在设置停靠位置时可以通过位运算进行设置(单参多用);
enum ToolBarArea { LeftToolBarArea = 0x1, RightToolBarArea = 0x2, TopToolBarArea = 0x4, BottomToolBarArea = 0x8, ToolBarArea_Mask = 0xf, AllToolBarAreas = ToolBarArea_Mask, NoToolBarArea = 0 };当停靠位置为多个时采用按位或
|的方式进行设置;addToolBar传参(默认停靠位置)
传参的方式为:
addToolBar(Qt::ToolBarArea, QToolBar*)第一个参数为位置, 第二个参数为工具栏;
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); /*创建工具栏*/ QToolBar* toolbar1 = new QToolBar(); QToolBar* toolbar2 = new QToolBar(); /*设置工具栏*/ this->addToolBar(Qt::LeftToolBarArea, toolbar1); this->addToolBar(Qt::RightToolBarArea, toolbar2); /*创建QAction*/ QAction* action1 = new QAction("Action1"); QAction* action2 = new QAction("Action2"); QAction* action3 = new QAction("Action3"); QAction* action4 = new QAction("Action4"); /*设置快捷项*/ toolbar1->addAction(action1); toolbar1->addAction(action2); toolbar2->addAction(action3); toolbar2->addAction(action4); }运行结果为:

setToolBarArea(允许停靠位置)
该函数用来设置工具栏的允许停靠位置, 传参为上述的枚举值, 当存在多参情况下采用按位或
|的形式进行;MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); /*创建工具栏*/ QToolBar* toolbar1 = new QToolBar(); QToolBar* toolbar2 = new QToolBar(); /*设置工具栏*/ this->addToolBar(toolbar1); this->addToolBar(toolbar2); /*创建QAction*/ QAction* action1 = new QAction("Action1"); QAction* action2 = new QAction("Action2"); QAction* action3 = new QAction("Action3"); QAction* action4 = new QAction("Action4"); /*设置快捷项*/ toolbar1->addAction(action1); toolbar1->addAction(action2); toolbar2->addAction(action3); toolbar2->addAction(action4); /*设置允许停靠位置*/ toolbar1->setAllowedAreas(Qt::RightToolBarArea|Qt::LeftToolBarArea); toolbar2->setAllowedAreas(Qt::RightToolBarArea|Qt::LeftToolBarArea); // 只允许停靠在左侧或是右侧 }运行结果为:

3.4 设置图标
工具栏的快捷项同样可以设置图标, 其设置图标的方式与上文中提到的菜单/菜单项所设置图标的方式如出一辙;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
/*设置工具栏*/
QToolBar *toolbar = new QToolBar();
this->addToolBar(toolbar);
/*添加快捷项*/
QAction *action1 = new QAction("打开");
QAction *action2 = new QAction("保存");
QAction *action3 = new QAction("另存为");
toolbar->addActions({action1, action2, action3}); // 采用QList的传参方式
/*设置图标*/
action1->setIcon(QIcon(":/open.png"));
action2->setIcon(QIcon(":/save.png"));
action3->setIcon(QIcon(":/saveas.png"));
}
运行结果为:

从运行结果可以看到, 在工具栏中对快捷项设置图标, 对应的原文本同样会被Icon所覆盖, 但其对应的文本标题将以ToolTip的形式存在;
4 Status Bar 状态栏
状态栏通常在程序的最下方, 用于显示对应的状态;
以Notepad--为例:

状态栏与菜单栏QMenuBar相同, 一个程序中的状态栏至多只能有一个, 且通常情况下, 当勾选UI文件生成后, 对应的将自动生成一个QStatusBar状态栏;

4.1 状态栏的创建
主流的状态栏的创建方式同样分为两种:
-
QMainWindow提供的statusBar()使用该方式创建时, 若是不存在状态栏则创建并设置, 存在则获取;
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); /*设置状态栏 一*/ QStatusBar* statusbar = this->statusBar(); } -
new一个QStatusBar对象通过
new在堆空间中创建一个QStatusBar对象, 并采用setStatusBar()设置进QMainWindow中;MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); /*设置状态栏 二*/ QStatusBar* statusbar = new QStatusBar(); this->setStatusBar(statusbar); }
运行结果为:

从结果可以看出, 与QMenuBar行为相同, 当对应的QStatusBar中没有内容时, 将不显示;
4.2 状态栏添加内容
状态栏可以添加任意内容, 包括但不限于, 控件, 文本, 空白占位;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
/*设置状态栏 二*/
QStatusBar* statusbar = new QStatusBar();
this->setStatusBar(statusbar);
/*添加内容*/
QPushButton *button = new QPushButton("click me", this);
statusbar->addWidget(button); // 按钮
QLabel *label = new QLabel("这是StatusBar中的QLabel", this);
statusbar->addWidget(label); // 标签
QProgressBar *progress = new QProgressBar(this);
progress->setValue(60);
statusbar->addWidget(progress); // 进度条
}
运行结果为:

在QStatusBar中设置控件时可以为其设置对应的拉伸系数;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
/*设置状态栏 二*/
QStatusBar* statusbar = new QStatusBar();
this->setStatusBar(statusbar);
/*添加内容*/
QPushButton *button = new QPushButton("click me", this);
statusbar->addWidget(button,1/*拉伸系数*/); // 按钮
QLabel *label = new QLabel("这是StatusBar中的QLabel", this);
statusbar->addWidget(label,2); // 标签
QProgressBar *progress = new QProgressBar(this);
progress->setValue(60);
statusbar->addWidget(progress,2); // 进度条
}
运行结果为:

4.2.1 从右往左放置
上文中提到的放置方式, 即addWidget为从左往右的放置方式, 除此之外还可以通过由右向左的放置方式进行放置;
通常使用addPermanentWidget进行放置;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
/*设置状态栏 二*/
QStatusBar* statusbar = new QStatusBar();
this->setStatusBar(statusbar);
/*添加内容(从右往左)*/
QPushButton *button = new QPushButton("click me", this);
statusbar->addPermanentWidget(button); // 按钮 (从右往左)
QLabel *label = new QLabel("这是StatusBar中的QLabel", this);
statusbar->addWidget(label); // 标签 (从左往右)
QProgressBar *progress = new QProgressBar(this);
progress->setValue(60);
statusbar->addWidget(progress); // 进度条 (从左往右)
}
运行结果为:

4.2.2 显示状态信息
除了添加控件以外, QStatusBar可以添加状态信息的显示;
通常采用QStatusBar::showMessage(QString)进行显示;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
/*设置状态栏 二*/
QStatusBar* statusbar = new QStatusBar();
this->setStatusBar(statusbar);
/*显示状态栏信息*/
statusbar->showMessage("这是状态栏"); // 状态栏信息
/*添加内容(从右往左)*/
QPushButton *button = new QPushButton("click me", this);
statusbar->addPermanentWidget(button); // 按钮
QLabel *label = new QLabel("这是StatusBar中的QLabel", this);
statusbar->addPermanentWidget(label); // 标签
QProgressBar *progress = new QProgressBar(this);
progress->setValue(60);
statusbar->addPermanentWidget(progress); // 进度条
}
运行结果为:

除此之外, 可以为这个状态栏信息进行定时, 即显示多久, 单位为ms;
/*显示状态栏信息*/
statusbar->showMessage("这是状态栏", 3000/*设置timeout*/); // 状态栏信息
运行结果为:

(这里不是循环显示, 循环的是gif不是程序 - orz)
可以看到在一定时间后, Tips提示将会消失;
其次是当一个程序的StatusBar中存在控件内容和状态信息时, 需要注意他们的位置信息与前后顺序, 否则将会出现显示错误, 由于这段代码显示状态信息时对应的控件是由右向左进行插入, 而若是从左往右插入, 将会与状态信息发生冲突;
-
情况一
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); /*获取状态栏*/ QStatusBar* statusbar = this->statusBar(); /*定义控件*/ QLabel *label = new QLabel("这是一个QLabel"); QPushButton *button = new QPushButton("这是一个Button"); /*情况 一*/ statusbar->showMessage("这是showMessage显示信息"); statusbar->addWidget(button); statusbar->addWidget(label); }运行结果为:

控件由左向右插入时, 状态信息先于控件显示, 控件被覆盖;
-
情况二
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); /*获取状态栏*/ QStatusBar* statusbar = this->statusBar(); /*定义控件*/ QLabel *label = new QLabel("这是一个QLabel"); QPushButton *button = new QPushButton("这是一个Button"); /*情况 二*/ statusbar->addWidget(button); statusbar->addWidget(label); statusbar->showMessage("这是showMessage显示信息"); }运行结果为:

控件由左向右插入时, 控件先于状态信息插入,
UI显示错乱; -
情况三
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); /*获取状态栏*/ QStatusBar* statusbar = this->statusBar(); /*定义控件*/ QLabel *label = new QLabel("这是一个QLabel"); QPushButton *button = new QPushButton("这是一个Button"); /*情况 三*/ statusbar->showMessage("这是showMessage显示信息"); statusbar->addPermanentWidget(button); statusbar->addPermanentWidget(label); }运行结果为:

控件由右向左插入时, 状态信息先于控件显示, 无影响;
且当
showMessage调用时, 控件由右向左插入, 无论其先后顺序, 均无影响;
由此得知, 当需要调用showMessage与控件并存时, 控件需要由右向左插入;
5 Dock Widget 浮动窗口
浮动窗口可以看成是窗口中的子窗口, 在上文中也提到, 实际上Dock Widget是一种铆接部件, 是Tool Bar与 Central Widget的粘合剂;
这个浮动窗口与ToolBar相似, 都可以进行浮动与停靠;
5.1 创建浮动窗口
通常通过new来创建一个QDockWidget对象;
并通过QMainWindow类提供的addDockWidget()来添加对应的浮动窗口;
addDockWidget(Qt::DockWidgetArea area, QDockWidget *dockwidget);
可以看到, 这里实际上需要传入两个参数, 其中第一个参数为浮动窗口默认的位置, 第二个参数才是浮动窗口的对象指针;
其中位置参数的信息为如下:
enum DockWidgetArea {
LeftDockWidgetArea = 0x1,
RightDockWidgetArea = 0x2,
TopDockWidgetArea = 0x4,
BottomDockWidgetArea = 0x8,
DockWidgetArea_Mask = 0xf,
AllDockWidgetAreas = DockWidgetArea_Mask,
NoDockWidgetArea = 0
};
同样的采用位的方式进行设置, 以方便设置浮动窗口的允许停靠位置(采用按位或|进行设置, 实现单参数多选项);
而在初始位置时, 只设置单选项;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
QDockWidget* dockw1 = new QDockWidget("浮动窗口"); // 传入 windowTitle 标题
this->addDockWidget(Qt::LeftDockWidgetArea, dockw1);
}
运行结果为:

5.2 为浮动窗口添加控件
浮动窗口同样可以添加其他控件, 但是在添加其它控件之前, 需要先为浮动窗口添加一个单独的Widget;
否则浮动窗口无法直接添加控件;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
/*创建浮动窗口*/
QDockWidget* dockw1 = new QDockWidget("浮动窗口");
this->addDockWidget(Qt::LeftDockWidgetArea, dockw1);
/*为浮动窗口添加Widget*/
QWidget* widget1 = new QWidget();
dockw1->setWidget(widget1); // 这里是setxxx 意味着只能存在
/*为widget设置布局管理器*/
QVBoxLayout* vlayout = new QVBoxLayout();
widget1->setLayout(vlayout);
/*添加控件(按钮)*/
QPushButton* button1 = new QPushButton("button1",widget1);
QPushButton* button2 = new QPushButton("button2",widget1);
/*将按钮控件设置进布局管理器中*/
vlayout->addWidget(button1); // add表示能存在多个
vlayout->addWidget(button2);
}
运行结果为:

5.3 设置允许停靠位置
通常通过setAllowedAreas()方法来设置可停靠位置;
具体的可停靠位置具体通过 enum DockWidgetArea {...};内的值, 通过按位或|的方式设置;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// ...
/*设置浮动窗口允许停靠位置(左右)*/
dockw1->setAllowedAreas(Qt::LeftDockWidgetArea|Qt::RightDockWidgetArea);
}
运行结果为:
