窗口概述
我们之前学过的代码都是基于QWidget控件,而QWidget更多情况下是作为别的窗口的一部分。
Qt 窗⼝ 是通过 QMainWindow类 来实现的。
QMainWindow 是⼀个为⽤⼾提供主窗⼝程序的类,继承⾃ QWidget 类,并且提供了⼀个预定义的布局。QMainWindow 包含 ⼀个菜单栏(menu bar)、多个⼯具栏(tool bars)、多个浮动窗⼝(铆接部件)(dock widgets)、⼀个状态栏(status bar) 和⼀个 中⼼部件(central widget),它是许多应⽤程序的基础,如⽂本编辑器,图⽚编辑器等。如下图为 QMainwindow 中 各组件所处的位置

像菜单栏,工具栏,状态栏这些跟窗口有关的,一般不把它们划分为控件。
菜单栏
一个主窗口最多只有一个菜单栏。

创建菜单栏
它的创建方式有两种:
菜单栏的创建可以借助于 QMainWindow类 提供的 menuBar() 函数来实现。menubar()函
数原型如下:
cpp
QMenuBar * menuBar() const

2.在堆上动态创建:
其中对于第二种创建方式:
如果我们创建项目的时候,勾选了自动生成ui文件,那么这种方式创建是没问题的。但是如果我们勾选了自动生成ui文件,那么这种方式创建就会引起内存泄漏。
因为自动生成ui文件的请款下,Qt其实已经帮我们生成了一个MenuBar了,在QtDesigner中可以看到:

在这个对象树中已经有一个menubar了。如果我们自己又创建了一个新的 menubar,然后将新的menubar设置到MainWindow的对象树中,那么旧的menubar就会脱离Qt的对象树,也就意味着后续无法对这个对象进行释放了。

不过这里造成的内存泄露对于客户端相比于服务器来说还好,因为现在的计算机内存都比较充裕,但是对于服务器来说就很致命了,因为服务器要处理很多请求,如果每个请求泄漏一点,那么积累下来就会泄漏很多,另外服务器一般都要求7 * 24小时运行。
关于 QMainWindow类 提供的 menuBar() 函数:

在菜单栏中添加菜单
上述代码直接运行后是什么都没有的。

我们需要创建菜单,并通过 QMenu 提供的 addMenu() 函数 来添加菜单。
同时需要用到Menu类

创建菜单项
在 Qt 中,并没有专⻔的菜单项类,可以通过 QAction 类,抽象出公共的动作。如在菜单中添加菜
单项.
QAction 可以给菜单栏使⽤, 也可以给⼯具栏使⽤

在菜单项之间添加分割线
当菜单栏的单项很多时,就可以通过分割线进行分组。
添加分割线是通过 QMenu 类 提供的addSeparator() 函数来实现

添加图标
添加图标,一样还是建议使用qrc文件管理的方式来添加。
给菜单添加:
我们发现给QMenu设置图标的话,那么它原本的文本就会被图标给覆盖。
我们给子菜单添加图标再看看

我们发现给子菜单添加图标就不会出现文本被覆盖的情况。
⼯具栏
QToolBar的基本使用
调⽤ QMainWindow类 的 addToolBar() 函数来创建⼯具栏,每增加⼀个⼯具栏都需要调⽤⼀次该函数。
一个窗口可以有多个工具栏,也可以没有。


典型的工具栏展示的一般是图标而不是文本。
我们可以设置图标

可以看到,如果QAction出现在工具栏上,也会产生图标覆盖文本的情况。
不过此时这个文本会议tooltip的方式存在

这个tooltip也可以手动设置。

工具栏和菜单栏往往是搭配使用的,工具栏中的QAction也可以出现在菜单栏中。
有这样一个问题:

设置停靠位置
⼯具栏停靠位置的设置有两种⽅式。⼀种是在创建⼯具栏的同时指定停靠的位置,另⼀种是通过
QToolBar类 提供的 setAllowedAreas()函数 来设置。
先创建多个工具栏,方便观察。
⽅式⼀:创建⼯具栏的同时指定其停靠的位置。
在创建⼯具栏的同时,也可以设置⼯具栏的位置,其默认位置是在窗⼝的最上⾯;如上述代码,默认在最上⾯显⽰。⼯具栏允许停靠的区域由 QToolBar类 提供的 allowAreas()函数 决定,其中可以设置的位置包括:
Qt::LeftToolBarArea 停靠在左侧
•
Qt::RightToolBarArea 停靠在右侧
•
Qt::TopToolBarArea 停靠在顶部
•
Qt::BottomToolBarArea 停靠在底部
•
Qt::AllToolBarAreas 以上四个位置都可停靠

⽅式⼆:使⽤ QToolBar类 提供的 setAllowedAreas()函数 设置停靠位置。

设置浮动属性
⼯具栏的浮动属性可以通过 QToolBar类 提供的 setFloatable()函数 来设置。setFloatable()函数原
型为:
cpp
void setFloatable (bool floatable)


程序运行后,鼠标长按那一排点点即可拖动窗口。
设置移动属性
设置⼯具栏的移动属性可以通过 QToolBar类 提供的 setMovable()函数 来设置。setMovable()函数
原型为:
cpp
void setMovable(bool movable)


设置了不能移动后,那些点点都不见了,说明都不能拖动了。
说明: 若设置⼯具栏为不移动状态,则设置其停靠位置的操作就不会⽣效,所以设置⼯具栏
的移动属性类似于总开关的效果。
状态栏
状态栏是应⽤程序中输出简要信息的区域。⼀般位于主窗⼝的最底部,⼀个窗⼝中最多只能有⼀个状态栏。在 Qt 中,状态栏是通过 QStatusBar类 来实现的。 在状态栏中可以显⽰的消息类型有:
实时消息:如当前程序状态
•
永久消息:如程序版本号,机构名称
•
进度消息:如进度条提⽰,百分百提⽰
状态栏的创建
状态栏的创建是通过 QMainWindow 类 提供的 statusBar() 函数来创建
在状态栏中显⽰实时消息

showMessage如果timeout = 0的话,就会一直显示。
timeout的单位是ms。
在状态栏中添加控件
在状态栏中可以显⽰永久消息,此处的永久消息是通过 标签 来显⽰的


这里看到消息是显示在左侧的,我们也可以设置显示在右侧


当然我们也可以添加按钮,进度条这些。

注意
对于Qt的内置类,我们通过setXXX,addXXX这样的接口把这些内置类对象设置或者添加到比如对象A中,那么它们的生命周期也将由对象A来管理。
浮动窗⼝
在 Qt 中,浮动窗⼝也称之为铆接部件。浮动窗⼝是通过 QDockWidget类 来实现浮动的功能。浮动窗⼝⼀般是位于核⼼部件的周围,可以有多个。
浮动窗⼝的创建
浮动窗⼝的创建是通过 QDockWidget类 提供的构造⽅法 QDockWidget()函数 动态创建的

我们可以通过鼠标拖动这个浮动窗口的位置。也可以通过这个x号关闭
我们也可以把这个窗口嵌套设置进其它窗口中

设置停靠的位置
浮动窗⼝是位于中⼼部件的周围。可以通过 QDockWidget类 中提供 setAllowedAreas() 函数设置其允许停靠的位置。其中可以设置允许停靠的位置有:
Qt::LeftDockWidgetArea 停靠在左侧
•
Qt::RightDockWidgetArea 停靠在右侧
•
Qt::TopDockWidgetArea 停靠在顶部
•
Qt::BottomDockWidgetArea 停靠在底部
•
Qt::AllDockWidgetAreas 以上四个位置都可停靠

不过它依然可以自由停靠。
对话框
对话框介绍
对话框是 GUI 程序中不可或缺的组成部分。⼀些不适合在主窗⼝实现的功能组件可以设置在对话框中。对话框通常是⼀个顶层窗⼝,出现在程序最上层,⽤于实现短期任务或者简洁的⽤⼾交互。Qt常⽤的内置对话框有:QFiledialog(⽂件对话框)、QColorDialog(颜⾊对话框)、QFontDialog(字体对话框)、QInputDialog (输⼊对话框)和 QMessageBox(消息框) 。
我们在创建项目的时候,可以选择Bass Class:
通过这样的方式创建出来的程序窗口和QWidget非常相似。
在实际开发中,更多的情况并不是在这里继承自QDialog,而是继承其它的类,然后在代码中创建额外的类,让这个类继承QDialog。
所以这里演示的时候我们还是以QWidget为例

对话框的内存泄漏问题
关于这个代码

虽然我们new了一个对话框,并且将它放到了对象树中,但是这里我们需要注意:
我们只是把它挂到了Widget这个窗口中,那么只有当Widget销毁时,这个对话框才会销毁。
我们每次点击按钮就会生成一个对话框,虽然点击窗口上的❌就可以这个对话框关闭,此时这里它的资源并没有释放,因此就会导致内存泄漏了。
在上述代码中
Qt显然也考虑到了这个问题,因此给我们提供了一种很方便的解决方案:


自定义对话框
自定义对话框的方式有两种。
比如刚刚的代码,就是其中一种:用代码的方式自定义对话框,比如添加一个布局管理器

第二种方式:通过图形化界面的方式
在界面文件右键新建:


这样我们就可以通过图形化界面的方式来自定义对话框了。


在界面文件这里也多了相应的文件。
我们用两个按钮来进行区分

实现对应的槽函数
不要忘记包含头文件



对话框的分类
对话框分为模态对话框和非模态对话框。
模态对话框:弹出对话框的时候,此时用户无法操作父窗口,必须先完成对话框中的操作。
一般用在特别关键的场合,此时需要用户做出决策的场景。
非模态对话框: 弹出对话框的时候,用户可以操作父窗口。
一般用在不是特别关键的场景。
我们之前演示的对话框默认就是非模态对话框。
使用模态对话框,其实只要将show换成exec即可。


此时就是模态对话框了。
模态对话框最好不要频繁使用,不然会影响用户的体验。
使⽤ QDialog::setModal() 函数 可以创建混合特性的对话框。通常,创建对话框时需要指定对话框的⽗组件。

false就是非模态,反之就是模态。
Qt内置对话框
Qt 提供了多种可复⽤的对话框类型,即 Qt 标准对话框。Qt 标准对话框全部继承于 QDialog类。
常用的标准对话框:

消息对话框 QMessageBox
消息对话框是应⽤程序中最常⽤的界⾯元素。消息对话框主要⽤于为⽤⼾提⽰重要信息,强制⽤⼾进⾏选择操作。
QMessageBox类 中定义了静态成员函数,可以直接调⽤创建不同⻛格的消息对话框,其中包括:


问题提示对话框

这里的按钮有很多种:
还有前面的Icon

颜⾊对话框 QColorDialog
颜⾊对话框的功能是允许⽤⼾选择颜⾊。继承⾃ QDialog 类。

获取用户选择颜色/设置初始的颜色


演示:
同时,getColor还可以设置用户打开对话框时的初始颜色。

我们还可以使用QSS来通过用户选择的颜色来设置窗口的颜色。
cpp
void MainWindow::on_pushButton_clicked()
{
QColorDialog* dialog = new QColorDialog(this);
dialog->setAttribute(Qt::WA_DeleteOnClose);
//dialog->show();
QColor color = dialog->getColor(QColor(237,28,36)); // 这是一个静态方法,设置初始颜色为红色
qDebug() << color;
QString colors = "background-color: rgb(" + QString::number(color.red()) + ","
+ QString::number(color.green()) + "," + QString::number(color.blue()) + ");";
this->setStyleSheet(colors);
}

⽂件对话框 QFileDialog
⽂件对话框⽤于应⽤程序中需要打开⼀个外部⽂件或需要将当前内容存储到指定的外部⽂件
打开⽂件


其中getOpenFileName是一个静态方法,它可以自动帮我们创建一个对话框,并且它的返回值是一个QString,也就是我们目标文件的路径。
getOpenFileName的参数

从左至右分别是 父指针 文件对话框的标题 对话框的初始路径 只保留什么格式的文件
保存文件
这里的对话框和打开是略有不同的。

不过我们这里并没有实现其它逻辑,所以点击了保存也不会有什么反应。
字体对话框 QFontDialog
Qt 中提供了预定义的字体对话框类 QFontDialog,⽤于提供选择字体的对话框部件。


输⼊对话框 QInputDialog
Qt 中提供了预定义的输⼊对话框类:QInputDialog,⽤于进⾏临时数据输⼊的场合。
数据的类型可以是整数,浮点数,字符串等等
同样也提供了静态函数
比如:


