【Qt】显示类控件 QLabel、QLCDNumer、QProgressBar、QCalendarWidget
显示类控件
- 一. 文本:QLabel
- 二. 数字:QLCDNumer
- 三. 进度条:QProgressBar
- 四. 日历:QCalendarWidget
一. 文本:QLabel
QLabel 可以用来显示文本和图片,核心属性如下:
代码:显示不同格式的文本
在界面上创建三个 QLabel,objectName 分别为 label、label_2、label_3,如下:
修改 widget.cpp,设置三个 label 的属性,运行效果如下:
- 使用
<b>
标签,在富文本中表示文本加粗,而在纯文本中没有进行任何渲染操作,只是单纯的文本。 - 使用
#
,在 markdown 中表示一级标题,而在纯文本中没有进行任何渲染操作,只是单纯的文本。
代码:显示图片
- 虽然 QPushButton 也可以通过设置图标的方式设置图片,但是并非是一个好的选择,更多的时候还是希望通过 QLabel 来作为一个更单纯的显示图片的方式。
在界面上创建一个 QLabel,objectName 为 label,如下:
创建 resource.qrc 文件,并把图片导⼊到 qrc 中,效果如下:
修改 widget.cpp,给 QLabel 设置图片,如下:
- 由于这个图片本身的尺寸是 200 * 200,而窗口和 QLabel 的大小是 400 * 400,并没有将其填充满。
修改代码,设置 scaledContents 属性,再次运行,就可以看到图片已经被拉伸,可以把窗口填满了,如下:
在上面的代码的构造函数中,进行 QLabel 的尺寸设置,是一次性的,一但程序运行起来之后,QLabel 的尺寸就固定下来了,当窗口手动放大时,QLabel 的大小是不会发生变化的,如下所示:
- Qt 中表示用户的操作,有两种概念:信号 和 事件。
- 当用户拖拽修改窗口大小的时候,就会触发 resize 事件 (resizeEvent),像 resize 这样的事件,是连续变化的,把窗口尺寸从 A 拖到 B 这个过程中,会触发出一系列的 resizeEvent,此时就可以借助 resizeEvent 来完成上述的功能。
- 可以让 Widget 类,重写父类 QWidget 的 resizeEvent 虚函数;在鼠标拖动 QWidget 窗口尺寸的过程中,这个函数会被反复调用执行,每次触发一个 resizeEvent 事件都会调用一次对应的虚函数。
- 由于此处进行了虚函数的重写,调用父类的虚函数就会实际调用到子类对应的虚函数,达到多态的效果。
- 注意:重写时需要在 widget.h 文件中,添加 resizeEvent 函数,如下:
执行程序,此时改变窗口大小,图片也会随之变化,于此同时,在控制台里也能够看到尺寸变化的过程。
代码:文本对齐,自动换行,缩进,边距
创建四个 label,objectName 分别是 label 到 label_4,并且在 QFrame 中设置 frameShape 为 Box (设置边框之后看起来会更清晰一些),如下:
QFrame 是 QLabel 的父类,其中 frameShape 属性用来设置边框性质,具体如下:
- QFrame::Box:矩形边框。
- QFrame::Panel:带有可点击区域的面板边框。
- QFrame::WinPanel:Windows 风格的边框。
- QFrame::HLine:水平线边框。
- QFrame::VLine:垂直线边框。
- QFrame::StyledPanel:带有可点击区域的面板边框,但样式取决于窗口主题。
编写 widget.cpp,给这四个 label 设置属性,如下:
运行程序,可以看到如下效果:
- 第一个 label 设置了 垂直水平居中。
- 第二个 label 设置了 wordWrap,能够自动换行。
- 第三个 label 设置了 Indent,能够自动缩进。
- 第四个 label 设置了 margin,四个方向均有间距 (图上仅体现出三个方向,下方看不出来)
代码:设置伙伴
创建两个 label 和 两个 radioButton,objectName 分别是 label,label_2,radioButton,radioButton_2,如下:
- 此处把 label 中的文本设置为 “快捷键 &A” 这样的形式,其中 & 后面跟着的字符,就是快捷键,可以通过 Alt + A 的方式来触发该快捷键。
- 但是注意,这里的快捷键和 QPushButton 的不同,需要搭配 Alt 和 单个字母的方式才能触发。
编写 widget.cpp,设置 buddy 属性,当然这里也可以使用 Qt Designer 直接设置,运行程序,可以看到,按下快捷键 Alt+a 或者 Alt+b,即可选中对应的选项,如下:
二. 数字:QLCDNumer
QLCDNumer 是一个专门用来显示数字的控件,类似于 “老式计算器” 的效果,如下:
核心属性如下:
代码:倒计时
在界面上创建一个 QLCDNumber,objectName 为 lcdNumber,如下:
修改 widget.cpp,在构造函数中初始化 QTimer,执行程序后,可以看到每隔一秒钟,显示的数字就减少 1,如下:
- C++ 标准库中,没有提供定时器的实现,Boost 里面提供了对应的功能,Qt 中也封装了对应的定时器 QTimer (结合了信号槽机制)
- QTimer 表示定时器,通过 start 方法启动定时器之后,就会每隔一定周期,触发一次 QTimer::timeout 信号。
- 使用 connect 把 QTimer::timeout 信号和 Widget::handle 连接起来,意味着每次触发 QTimer::timeout 都会执行 Widget::handle
- 通过 intValue 获取到 QLCDNumber 内部的数值,如果 value 的值归 0 了,就通过 stop 停止定时器,接下来 QTimer 也就不会触发 QTimer::timeout 信号了。
- 这里需要把 QTimer 对象,放在 Widget 成员中,如果放在构造函数中,则槽函数找不到构造函数中的 QTimer 对象。
- 但是这里我将
#include<QTimer>
头文件放在了 widget.cpp 中,而在 widget.h 中声明了 QTimer 了,为什么不会报错 (找不到 QTimer 的定义) - 上述的问题其实是通过 Qt 内部提供的一个特殊技巧来实现的,在 Qt 中,有一个专门的头文件包含了 Qt 中所有类的 “前置声明”,这个头文件一般不会直接接触到,但是包含在其他的 Qt 的头文件中。
- Widget 类的前面已经提供了 QTimer 类的声明的话,此时就可以在 Widget 中声明 QTimer 的指针/引用类型的成员,后续如果要真正使用 QTimer (包括创建实例,使用里面的成员),仍然需要包含 QTimer 的头文件 (包含了 QTimer 的详细的类的定义)
- Qt 引入了 C++ 中的特殊技巧,主要解决的是编译速度慢的问题 (与其他编程语言相比),编译速度慢主要和 #include 头文件,有直接的关系。
- 由于 #include 关系错综复杂,因此需要尽可能的减少 #include 头文件的个数,就可以有效的减短编译时间。
- 但是我们实际开发中,还是要该包含就包含,与其通过特殊技巧来缩短编译时间,不如说引入更好的硬件资源,来更高效的编译,一些互联网大厂,都有专门的 “编译集群”,进行分布式编译。
- 所以在 C++20 标准开始,就引入了 “模块” module 来替换 #include,从而提高编译速度。
- 但是这里我将
针对上述代码,存在两个问题:
- 上述代码如果直接在 Widget 构造函数中,通过一个循环 + sleep 的方式是否可以呢?代码如下:
最终的结果就是,运行代码 10 秒,窗口才显示出来,而上面的数字直接就是 0,因为 main 函数中,只有 Widget 的构造函数执行完后,w.show() 函数才会显示出窗口,达不到效果,如下:
- 上述代码如果是在 Widget 构造函数中,另起一个线程,在新线程中完成 循环+sleep 是否可以呢?代码如下:
这个代码同样是不行的,Qt 中规定,任何对于 GUI 上内容的操作,必须在主线程中完成像 Widget 构造函数,以及 connect 连接的 slot 函数,都是在主线程中调用的,而我们自己创建的线程则不是,当我们自己的线程中尝试对界面元素进行修改时,Qt 程序往往会直接崩溃。
- 因此 Qt 为了保证线程安全,直接要求所有的对界面的修改操作,必须在主线程中完成。
- 对于 Qt 的槽函数来说,默认情况下,槽函数都是由主线程调用的,在槽函数中修改界面是没有任何问题的。
- 主线程 main 函数中的 a.exec() 函数就会使主线程进入 “事件循环”,exec 就会一直循环下去,每执行一次循环,都会有一些固定的事情要操作。
三. 进度条:QProgressBar
使用 QProgressBar 表示一个进度条,如下:
核心属性如下:
代码:设置进度条按时间增长
在界面上创建进度条,objectName 为 progressBar,其中最小值设为 0,最大值设为 100,当前值设为 0,如下:
修改 widget.cpp,初始化 QTimer,此处设置 100ms 触发一次 QTimer::timeout 信号,也就是一秒钟触发 10 次,运行程序后,可以看到进度条中的进度在快速增长,如下:
代码:创建一个红色的进度条
不要忘了,QProgressBar 同样也是 QWidget 的子类,因此我们可以使用 styleSheet 通过样式来修改进度条的颜色,在界面上创建一个进度条,如下:
在 Qt Designer 中右击进度条,点击 “改变样式表”,添加样式,也可以在 Qt Designer 右侧的属性编辑器中,找到 QWidget 的 styleSheet 属性,其中的 chunk 是选中进度条中的每个 “块”,使用 QProgressBar::text 则可以选中文本,如下:
同时把 QProcessBar 的 alignment 属性设置为垂直水平居中,此处如果不设置 alignment,进度条中的数字会跑到左上角,这个怀疑是 Qt 本身的 bug,暂时只能先使用 alignment 来手动调整下,如下:
执行程序后,可以看到一个红色的进度条,如下:
四. 日历:QCalendarWidget
QCalendarWidget 表示一个 “日历”,如下:
核心属性如下:
重要信号如下:
代码:获取选中的日期
在界面上创建一个 QCalendarWidget 和一个 label,objectName 为 calendarWidget,label,如下:
给 QCalendarWidget 添加 slot 函数,执行程序后,可以看到当选择不同的日期时,label 中的内容就会随之改变,如下: