当前位置: 首页 > article >正文

Qt常用控件之显示类控件

目录

QLabel

文本格式

设置图片

文本对齐/自动换行/边距/缩进

设置伙伴

QLCDNumber

倒计时功能

QProgressBar

进度条

QCalendarWidget


QLabel

QLabel 同样是 QWidget 的子类,所以前面博客中 QWidget 中的属性方法也是适用的

QLabel可以用来显示文本和图片
核心属性如下:

           属性                                                          说明
           textQLabel中的文本
      textFormat文本的格式
Qt::PlainText 纯文本 (使用最多)
Qt::RichText 富文本(支持 html 标签)
Ot::MarkdownText markdown 格式
Qt::AutoText 根据文本内容自动决定文本格式
         pixmapQLabel 内部包含的图片
  scaledContents设为 true 表示内容自动拉伸填充 QLabel
设为 false 则不会自动拉伸
       alignment对齐方式,可以设置水平和垂直方向如何对齐
       wordWrap设为 true 内部的文本会自动换行
设为 false 则内部文本不会自动换行 (QLabel不提供滚动条,QTestEdit会提供)
          indent设置文本缩进,水平和垂直方向都生效
          margin内部文本和边框之间的边距
不同于于 indent,但是是上下左右四个方向都同时有效
而 indent 最多只是两个方向有效(具体哪两个方向有效取决于 alignment)
openExternalLinks是否允许打开一个外部的链接
(当 OLabel文本内容包含 url 的时候涉及到)
          buddy给 OLabel关联一个 "伙伴",这样点击 OLabel时就能激活对应的伙伴
例如伙伴如果是一个 QCheckBox,那么该 QCheckBox 就会被选中

文本格式

下面演示 QLabel 的 textFormat 属性,先创建三个 Label 标签:

再将这三个文本分别设置为纯文本、富文本、markdown文本:

可以看到,给这三个不同 textFormat 属性的文本的 Test,分别加入 html 标签、markdown格式,运行程序,结果如下:

所以得出结论,纯文本不会识别 html 标签或是 markdown格式,只会将他们当做文本打印出来


设置图片

想要设置图片,当然要使用 qrc机制,这里就不重复步骤了:

接着图形化界面的方式,拖动一个 Label,并编写构造函数:

此时运行程序:

我们发现图片并没有按照我们代码所编写的那样,让整个 Label 都是这个图片,是因为我们在 qrc 中传入的图片,可能原本的尺寸就是比较小的,像上述所插入的 dog.png 原本尺寸就是 200 * 200 的,而 Widget 窗口是 800* 600 的,所以不能够显示整个屏幕

     

而我们想要让整个 Widget 窗口都显示图片,就需要将 scaledContents 属性设置为 true,自动拉伸图片:

此时运行程序,dog.png 就能够填满整个屏幕了:

在上面代码中是在构造函数里,进行的这样的尺寸设置这个设置相当于是一次性的
一旦程序运行起来之后,QLabel 的尺寸就固定下来了,如果窗口发生改变,QLabel 是不会变化的

如果想要 QLabel 随着窗口大小实时发送改变,就需要了解 事件

在前面的学习中,我们了解了用户的操作,会对应一些信号
在 Qt 中,表示用户的操作,有两类概念,一个是信号,另一个是事件

当用户拖拽修改窗口大小的时候,就会触发 resize 事件(resizeEvent)
像 resize 这样的事件,是连续变化的,把窗口尺寸从 A 拖到 B 这个过程中,会触发出一系列的 resizeEvent

此时就可以借助 resizeEvent 来完成上述的功能
可以让 Widget 窗囗类,重写父类(QWidget)的 resizeEvent 虚函数,在鼠标拖动窗口尺寸的过程中,这个函数就会被反复调用执行,每次触发一个 resizeEvent 事件,都会调用一次对应的虚函数

由于此处进行了函数重写,调用父类的虚函数就会实际调用到子类的对应的函数(多态)

下面先在 widget.h 中,声明需要重写的 resizeEvent 函数:
这里的形参 event 是非常有用的,这里就包含了触发这个 resize 事件这一时刻,窗口的尺寸的数值

再在 widget.cpp 中编写 resizeEvent 函数,观察拖动窗口时发送的情况:

运行程序:

此时拖动窗口,发现 Qt 会自动调用 resizeEvent 函数,所以我们这里重写虚函数,是指定了一个回调函数的逻辑:

在实际编程中,指定回调函数其实有很多种写法:

  • 设置函数指针
  • 设置仿函数(函数对象)
  • 设置 lambda
  • 通过重写父类虚函数(框架中拿着父类的指针调用这个函数,如果你创建了子类重写了这个函数此时在多态机制下,实际执行的就是子类的函数了)
  • Qt 的信号槽

上面只是单纯的打印出尺寸,下面完善代码,使得能够通过实时窗口大小的结果,来实时修改 QLabel 的尺寸:

运行程序,随意拖动窗口的大小,图片也会实时改变,满足了我们的需求:


文本对齐/自动换行/边距/缩进

文本对齐

我们创建一个 Label,并在右侧找到 QFrame,设置 Label 的边框,这样能够更加清楚的观察文本对齐的方式

我们将 第一个属性 frameShape 改为 box,此时就有边框了:

下面给第一个 Label 设置属性,将其设置为 水平居中(AlignHCenter)和垂直居中(AlignVCenter)

之所以中间使用 按位或 连接,因为这里的 AlignHCenter 和 AlignVCenter 都是枚举类型:
类似于位图一样的效果,想要某个效果,就将某个比特位置为1即可

此时运行程序:

如果水平和垂直方向不居中了,想让它靠右上角对齐,将 AlignHCenter 改为 AlignRight,AlignVCenter 改为 AlignTop 即可:


自动换行

给第二个 Label 设置一段很长的文本:

运行程序观察:

发现这段文本无法完全显示出来,所以给它添加上自动换行的属性:


缩进

缩进使用的属性是 indent:

此处设置的缩进即使文本换行了,后续的行也会产生缩进不仅仅是首行缩进:


边距

边距是会影响上下左右四个方向的,用到了 margin 属性:

可以看到设置完边距50,这段长文本有一部分被覆盖掉了,显示不太清晰,超出部分也不再显示了,这就是设置边距的效果


设置伙伴

可以将 QLabel 和 单选框/复选框 绑定一个伙伴关系,此时就能够通过 QLabel 触发 单选框/复选框 的选择操作

下面先创建两个 RadioButton,分别在这两个 RadioButton 后面跟上一个 Label:

此时在构造函数中,将 Label 与对应的 RadioButton 建立伙伴关系:

运行程序,不需要鼠标点击,使用 alt + a / alt + b 就能选中对应的 单选按钮/复选按钮:

Qt 中,QLabel 中写的文本,是可以指定快捷键的,此处快捷键的规则功能上要比 QPushButton 弱很多
是在文本中使用 & 跟上一个字符来表示快捷键
比如 &A => 通过键盘上的 alt +a来触发这个快捷键
        &B =>通过键盘上的 alt +b 来触发
绑定了伙伴关系之后,通过快捷键就可以选中对应的 单选按钮/复选按钮


QLCDNumber

QLCDNumer 是一个专门用来显示数字的控件,类似于"老式计算器"的效果

核心属性:

           属性                                                          说明
        intValueQLCDNumber 显示的数字值(int)
         valueQLCDNumber 显示的数字值(double) 和 intValue 是联动的
例如给 value 设为 1.5,intValue 的值就是 2
另外,设置 value和 intValue 的方法名字为 display,而不是 setValue 或者 setIntValue 
     digitCount显示几位数字
         mode数字显示形式
QLCDNumber::Dec:十进制模式,显示常规的十进制数字
QLCDNumber::Hex:十六进制模式,以十六进制格式显示数字
QLCDNumber::Bin:二进制模式,以二进制格式显示数字
QLCDNumber::0ct:八进制模式,以八进制格式显示数字
只有十进制的时候才能显示小数点后的内容
    segmentStyle设置显示风格
QLCDNumber::Flat:平面的显示风格,数字呈现在一个平坦的表面上QLCDNumber::0utline:轮廓显示风格,数字具有清晰的轮和阴影效果
5QLCDNumber::Filled:填充显示风格,数字被填充颜色并与背景区分开
smallDecimalPoint设置比较小的小数点

倒计时功能

使用 QLCDNumber 显示一个初始的数值,比如 10
每隔一秒钟,数字就 -1,一直到 0,就停止了

先使用 图形化界面 的方式拖动一个 LCDNumber:

此处关键要点是要实现"每秒钟 -1"这个效果
周期性的执行某个逻辑,也就是"定时器”
C++标准库中,没有提供定时器的实现,Boost 里面提供了对应的功能

Qt 中也封装了对应的定时器(结合了信号槽机制的)
Qt 中是使用 QTimer类,通过这个类创建出来的对象,就会产生一个 timeout 这样的信号
可以通过 start 方法来开启定时器,并且参数中设定触发 timeout 信号的周期
再结合 connect,把这个 timeout 信号绑定到需要的槽函数中,就可以执行逻辑,修改 LCDNumber 中的数字了

先在 widget.h 中添加成员 timer 和 槽函数 handle:

再在 widget.cpp 中编写代码:

此时运行程序,完成了倒计时功能:


上面实现的 倒计时功能 是利用的 QTimer类, 那么如果不使用这个类,直接写一个循环,每个一秒减一,能够实现倒计时的功能吗,看下面的示例

我们直接在 ui界面 中,在右侧修改初始值:

之前学习 C++ 时使用 sleep函数 是 Windows 的 API,需要在 VS 中包含 Windows.h 的头文件才能使用,而 Qt 是无法直接使用 Windows.h 这个头文件的
所以下面采用 thread库 中的 sleep_for 来完成休眠一秒的操作

具体代码如下:

 

此时运行程序,发现10秒内并没有显示窗口,而是10秒后,才会显示下面的界面:

这是因为我们是在构造函数中编写的上述代码,而 main.cc 在执行的时候,构造函数执行完,才会执行 show函数,所以运行程序后,无法看到窗口,直到在构造函数中10秒执行完,才显示0秒的界面


下面我们就可以思考一下,另一个情况能够实现吗
假设在构造函数中,另外创建一个线程,在新的线程中,执行上述循环+更新操作,此时并不影响主线程的构造函数的执行
所以将代码改为:

此时运行程序,发现控制台上日志显示,程序终止,出现异常:

而之所以出现异常,原因是:
Qt 里,界面有一个专门的线程去负责维护更新的(主线程,也就是 main 函数所在的线程)
对于 GUI 来说,内部包含了很多的隐藏状态,Qt 为了保证修改界面的过程中,线程安全是不会受到影响的,所以 Qt 禁止了其他线程直接修改界面

而我们上面创建一个线程,在最后一行的 ui->lcdNumber->display(value); 就是在修改界面,所以会出现异常

因此 Qt 为了确保线程安全,直接要求所有的对界面的修改操作,必须在主线程中完成
对于 Qt 的槽函数来说,默认情况下,槽函数都是由主线程调用的,所以在槽函数中修改界面是没有任何问题的


QProgressBar

使用 QProgressBar 表示一个进度条

核心属性:

                属性                                  说明
            minimum进度条最小值
            maximum进度条最大值
               value进度条当前值
           alignment文本在进度条中的对齐方式
Qt::AlignLeft:左对齐
Qt::AlignRight:右对齐
Qt::Aligncenter:居中对齐
Qt::AlignJustify:两端对齐
          textVisible进度条的数字是否可见
          orientation进度条的方向是水平还是垂直
     invertAppearance是否是朝反方向增长进度
         textDirection文本的朝向
              format展示的数字格式
%p:表示进度的百分比 (0-100)
%v:表示进度的数值 (0-100)
%m:表示剩余时间 (以毫秒为单位)
%t:表示总时间 (以毫秒为单位)

进度条

创建一个进度条,让这个进度条的进度跟随时间增长
(可以假设每隔 100ms,让进度条数值+1)

先拖拽一个 进度条:


通过右边的属性栏,将最小值/最大值设置为0/100,将当前值设置为0


下面就需要上面设计倒计时功能时,所用到的 QTimer类

同样在 widget.h 中新增成员 timer,新增槽函数 handle:
之所以需要定义一个成员 timer,而不是在构造函数中定义局部变量,是因为下面的槽函数 handle 还需要使用 timer

widget.cpp:

运行程序,进度条以 100ms 的速度每次 +1


这里有一个细节问题,我们所使用的 QTimer类,是需要包含头文件的,我们之前在写 C++代码 时一般是包含在 .h文件 中的,而在 Qt 中,既可以在 .h 中包含,也可以在 .cpp 中包含

之所以可以不在 .h 中包含,却能够在 .h 中声明 QTimer类,是因为:
在 Qt 中,有一个专门的头文件,这个头文件中包含了 Qt 中所有类的"前置声明",这个头文件一般不会直接接触到,但是包含其他的 Qt 的头文件,例如 #include<QWidget> 都会间接的包含到这个头文件

Widget 类的前面已经提供了 QTimer 类的声名的话,此时就可以在 Widget.h 中声明 QTimer 的指针/引用类型的成员
后续如果要真正使用 QTimer(包括创建实例,使用里面的成员),仍然需要包含 QTimer 的头文件(包含了 QTimer 的详细的类的定义)

Qt 使用上述的技巧,主要解决的是编译速度的问题

C++编译速度慢,和 #include 头文件有直接关系的
由于 include 关系错综复杂,因此尽可能减少 include 头文件的个数,就可以有效的减少编译时间
Qt 中就使用 class 前置声明的方式,来尽量减少头文件的包含,通过前置声明的方式,Qt 中的每个头文件包含的其他头文件数量都能得到一定的降低

但是咱们实际开发中,还是要该包含就包含,与其通过特殊技巧来缩短编译时间,不如说引入更好的硬件资源,来更高效的编译
例如:一些互联网大厂,都有专门的"编译集群”(分布式编译)

正是因为 #include 编译速度慢的原因,所以在 C++ 20 标准开始,就引入了"模块" module来替代 #include


因为 QProgressBar 也是 QWidget 的子类,所以 QWidget 的 styleSheet 属性也就可以使用,所以我们可以将 进度条 的颜色改为红色:
先拖动一个进度条:

右键,点击改变样式表:

输入以下内容:

此时进度条颜色就变为红色了,但是我们发现 24% 原来是在右边,现在却在左上角了:

这种情况有可能是 Qt 的 bug,并不知道原因是什么,但是也没关系,我们也可以设置样式:

此时就变为 垂直/水平方向 都 居中对齐了:

进度条具体的进度如何设置,一般都是根据实际的任务类型来灵活设置的
例如:要读取一个很大的文件,就可以先获取到文件的总大小,每读取一部分数据(可以计算出读了多少数据的),更新一次进度条的数值
设置进度条的过程中,往往是要搭配 定时器 的


QCalendarWidget

QCalendarwidget 表示一个"日历",形如

核心属性:

属性说明
selectDate当前选中的日期
minimumDate最小日期
maximumDate最大日期
firstDayOfWeek每周的第一天(也就是日历的第一列) 是周几
gridVisible是否显示表格的边框
selectionMode是否允许选择日期
navigationBarVisible日历上方标题是否显示
horizontalHeaderFormat日历上方标题显示的日期格式
verticalHeaderFormat日历第一列显示的内容格式
dateEditEnabled是否允许日期被编辑

重要信号

                      信号                                                说明
selectionChanged(const QDate&)当选中的日期发生改变时发出
activated(const QDate&)当双击⼀个有效的日期或者按下回车键时发出,形参是⼀个QDate类型,保存了选中的日期
currentPageChanged(int, int)当年份月份改变时发出,形参表示改变后的新年份和月份

首先使用 图形化界面 的方式,拖动一个 QCalendarWidget 和一个 Label,用于显示我们选中的日期:

接着右键日历,选择 转到槽 的 selectionChanged:

下面编写 槽函数 :

运行程序,可以看到控制台会打印我们所点击的日期,上面的 Label 中也会显示所点击的日期:


Qt常用控件之显示类控件到此结束啦


http://www.kler.cn/a/414858.html

相关文章:

  • Scala身份证上的秘密以及Map的遍历
  • flink中barrier不对齐的原因和影响
  • web安全之信息收集
  • CAN详解
  • 以达梦为数据库底座时部署的微服务页面报乱码,调整兼容模式
  • Asp.net core Autofac 案例 注入、AOP 启用接口代理拦截 启用 类代理拦截=== 只会拦截虚方法
  • go语言去除字符串末尾的特定字符
  • Java项目实战II基于SPringBoot的玩具销售商城管理系统(开发文档+数据库+源码)
  • Ajax入门程序
  • Python基础学习-12匿名函数lambda和map、filter
  • 【数据分析】一、pandas数据处理指南:100个基于pandas数据预处理方法
  • Leetcode494. 目标和(HOT100)
  • 【已解决】git push需要输入用户名和密码问题
  • MySQL:常用数据类型
  • 【数据结构】ArrayList与顺序表
  • # 18_ Python基础到实战一飞冲天(二)-python基础(十八)--元组
  • 尚硅谷学习笔记——Java设计模式(一)设计模式七大原则
  • mac 如何查看 export NVM_NODEJS_ORG_MIRROR=https://npm.taobao.org/mirrors/node 是否正确
  • Modern Effective C++ item 15:尽可能的使用constexpr
  • 【GIT】TortoiseGit的拉取(Pull) 和 获取(Fetch)
  • 机器学习在教育方面的应用文献综述
  • windows server 2019 启动 nginx 报错
  • 如何在AWS中部署HOOPS Communicator?Docker容器化策略!
  • 深度学习-46-大语言模型LLM之仅需一个文件llamafile部署本地大模型
  • 【C++】入门【三】
  • 无人机油气领域应用详解!