目录
[1. Label](#1. Label)
[1.1 textFormat 属性](#1.1 textFormat 属性)
[1.2 pixmap 属性](#1.2 pixmap 属性)
[1.3 scaledContents属性](#1.3 scaledContents属性)
[1.4 文本对齐:alignment](#1.4 文本对齐:alignment)
[1.5 自动换行:wordWrap](#1.5 自动换行:wordWrap)
[1.6 缩进:indent](#1.6 缩进:indent)
[1.7 边距:margin](#1.7 边距:margin)
[1.8 QLabel 的伙伴:buddy](#1.8 QLabel 的伙伴:buddy)
[1.9 小结](#1.9 小结)
[2. LCD Number](#2. LCD Number)
[3. ProgressBar](#3. ProgressBar)
[4. Calender Widget](#4. Calender Widget)
1. Label
QLabel 可以⽤来显示⽂本和图片,QLabel 也是可以使用 QWidget 中的属性和方法的。
核心属性如下:
|-------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 属性 | 说明 |
| text | QLabel 中的⽂本 |
| textFormat | ⽂本的格式. * Qt::PlainText 纯⽂本 【用的最多的格式,最普通的文本】 * Qt::RichText 富⽂本(支持 html 标签)【内容更丰富的文本,支持html,word工具,编辑的文件,就可以认为是一种富文本】 * Qt::MarkdownText markdown 格式【提供了各种特殊符号,表示不同的样式 / 格式】 * Qt::AutoText 根据文本内容⾃动决定文本格式 |
| pixmap | QLabel 内部包含的图片 |
| scaledContents | 设为 true 表⽰内容⾃动拉伸填充 QLabel 设为 false 则不会⾃动拉伸 |
| alignment | 对⻬⽅式. 可以设置⽔平和垂直⽅向如何对⻬. |
| wordWrap | 设为 true 内部的⽂本会⾃动换行. 设为 false 则内部⽂本不会⾃动换行. |
| indent | 设置⽂本缩进. ⽔平和垂直⽅向都⽣效 |
| margin | 内部⽂本和边框之间的边距. 不同于于 indent, 但是是上下左右四个⽅向都同时有效. ⽽ indent 最多只是两个⽅向有效(具体哪两个⽅向有效取决于 alignment ) |
| openExternalLinks | 是否允许打开⼀个外部的链接. (当 QLabel ⽂本内容包含 url 的时候涉及到) |
| buddy | 给 QLabel 关联⼀个 "伙伴" , 这样点击 QLabel 时就能激活对应的伙伴. 例如伙伴如果是⼀个 QCheckBox, 那么该 QCheckBox 就会被选中. |
QLabel 不会自动提供滚动条的,有的控件,QTextEdit,就会带有滚动条
1.1 textFormat 属性
eg:显示不同格式的⽂本

好像并没有什么区别:

体现出差异:

<b> 标签加到纯文本中,只是被当成了单纯的文本,没有进行任何的渲染操作的。
纯文本中,# 只是被单纯的当成了 "文本",而 # 在markdown 中,则是一级标题
1.2 pixmap 属性
QLabel 显示图片:
添加图片:

选中窗口,显示出属性:


窗口是 800 * 600,窗口也是 800* 600,但是图片对应的尺寸就不一定了

1.3 scaledContents属性
添加以下代码:


但是,在上面的代码中是在构造函数里,进行的这样的尺寸设置,这个设置相当于是"一次性的",图片不能随着拖动窗口的变化而变化,一旦程序运行起来后,QLabel的尺寸就被固定下来了,窗口发生变化,此时,QLabel 是不会变化的。
要想实现图片的大小随着窗口大小变化,得涉及到事件,用户的操作不仅仅涉及到信号也涉及到一些事件。
当前用户拖动窗口大小的时候,就会触发 resize 事件(resizeEvent)
像 resize 这样的事件,是连续变化的,把窗口尺寸从 A 拖到 B这个过程中,会触发一系列的 resizeEvent。
此时就可以借助 resizeEvent 来完成上述的功能,可以让 Widget 窗口类,重写父类(QWidget)的 resizeEvent 虚函数,在鼠标拖动窗口尺寸的过程中,这个函数就会被返回调用执行,每次触发一个 resizeEvent 事件都会调用一次对应的虚函数,由于此处进行了函数重写,调用父类的虚函数实际就会调用到子类的对应的函数(多态)

在拖动窗口的过程中,触发了一些列的打印,Qt自己调用的resizeEvent:

在实际编程中,指定回调函数其实有很多种写法:
- 设置函数指针
- 设置仿函数
- 设置 lambda
- 通过重写父类虚函数(框架中拿着父类的指针调用这个函数,如果你创建了子类并重写了这个函数,此时在多台机制下,实际执行的就是子类的函数了)
- Qt 的信号槽





1.4 文本对齐:alignment
选择样式:


在 Qt Creator 右侧属性的编辑区中,能够看到类之间的继承关系
QLabel 继承自 QFrame,QFrame 继承自 QWidget


垂直水平居中:


水平靠右,垂直居中:


垂直方向靠右上:


1.5 自动换行:wordWrap

设置自动换行:

1.6 缩进:indent


换为一长串的内容:


加上自动换行:


此处设置的缩进即使文本换行了,后续的行也会产生缩进,不仅仅是首行的缩进
1.7 边距:margin
上下左右都是有距离的:




1.8 QLabel 的伙伴:buddy


只能点击选项12来进行选择,点击后面的快捷键AB文字却不行

但是使用快捷键:ALT+A 就可以进行选择:

Qt 中,Qlabel 中写的文本,是可以指定 "快捷键",此处的快捷键的规则功能上要比 QPushButton 弱很多,是在文本中使用 & 跟上一个字符来标识快捷键,比如,&B => 通过键盘上的 ALT + b 来触发这个快捷键。
绑定了伙伴关系之后,通过快捷键就可以选中对应的单选按钮 / 复选按钮。
1.9 小结
QLabel 功能比较丰富的控件,只是显示文本,不进行编辑的话,也是一个很好的选择。
如果需要显示文本的同时也要进行编辑的话,就得选择 QLineEdit,QTextEdit,QPlainEdit 这几个控件来完成
2. LCD Number
QLCDNumer 是一个专门用来显示数字的控件。类似于 "老式计算器" 的效果
|-------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 属性 | 说明 |
| intValue | QLCDNumber 显示的数字值(int). |
| value | QLCDNumber 显⽰的数字值(double). 和 intValue 是联动的. 例如给 value 设为 1.5, intValue 的值就是 2. 另外, 设置 value 和 intValue 的⽅法名字为 display , ⽽不是 setValue 或者 setIntValue . |
| digitCount | 显示几位数字 |
| mode | 数字显⽰形式. 1. QLCDNumber::Dec :十进制模式,显示常规的十进制数字。 2. QLCDNumber::Hex :十六进制模式,以十六进制格式显示数字。 3. QLCDNumber::Bin :⼆进制模式,以⼆进制格式显示数字。 4. QLCDNumber::Oct :八进制模式,以八进制格式显示数字。 只有十进制的时候才能显示小数点后的内容 |
| segmentStyle | 设置显示风格. 1. QLCDNumber::Flat :平⾯的显示风格,数字呈现在⼀个平坦的表面上。 2. QLCDNumber::Outline :轮廓显示风格,数字具有清晰的轮廓和阴影效果。 3. QLCDNumber::Filled :填充显示风格,数字被填充颜⾊并与背景区分开。 |
| smallDecimalPoint | 设置⽐较小的 小数点 |
eg:倒计时
使用 QLCDNumber 显示一个初始的数值,比如10
每隔一秒,数字就 -1,一直到0,就停止了



此处的关键要点是要实现 "每秒钟 -1" 这个效果:周期性的执行某个逻辑,往往是封装成单独的一个组件,这样的组件叫做 "定时器"。
C++ 中并没有提供定时器的实现,Boost 里面提供了对应的功能,Qt 中也封装了对应的定时器(结合了信号槽机制)。通过 QTimer 这个类创建出来的对象,就会产生一个 timeout 这样的信号,可以通过 start 方法来开启定时器,并且参数中设定触发 timeout 信号的周期。
结合 connect ,把这个 timeout 信号绑定到需要的槽函数中,就可以执行逻辑,修改 LCDNumber 中的数字了。


说明定时器在工作了,触发的信号也正确是被槽函数执行到了

运行:



如果在上述的代码中我们不要QTimer的能达到上面的效果吗??比如用一个循环之类的。
方案一:sleep_for


Sleep 是Windows中的 api,需要包含 "Windows.h" 头文件才能使用的,只能在 vs 中才能使用。
C++ 11 标准库中引入了 sleep 操作。sleep_for:

过了很久才弹出来的界面:

Widget 的构造函数,需要把 Widget 构造完毕,然后才能执行后续的显示操作~~~
构造函数:

w.show() 才是进行显示。
以上编写的代码都是在构造中产生的,这一段逻辑需要消耗的时间就是10秒,构造完之后才进行的显示,显示的就是0.
那么方案二:在构造函数中,另外创建一个线程,在新的线程中,执行上述的 循环 + 更新操作。

控制台出现的信息:出现异常,终止

Qt 里,界面有一个专门的线程去负责维护更新的 (主线程:main 函数所在的线程),对于 GUI 来说,内部包含了很多的隐藏状态,Qt 为了保证修改界面的过程中,,线程安全是不会受到影响的,Qt 禁止了其它线程直接修改界面。
ui->lcdNumber->display(value); 例如这样的操作就是在修改界面,所以一执行就会导致异常,导致整个进程异常结束。因此,Qt 为了确保线程安全,直接要求所有的对界面的修改操作,必须在主线程中完成!!!对于 Qt 的槽函数来说,默认的情况下,槽函数都是有主线程调用的,在槽函数中修改界面是没有任何问题的!!!

a.exec() 就会使主线程进入 "事件循环",exec 就会一直循环下去,每执行一次循环,都会有一些固定的事情要操作。
所以 上面的两种方案是不能实现倒计时的效果的!!!!
3. ProgressBar
使用 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 :表示总时间(以毫秒为单位) |
eg:创建一个进度条,让这个进度条的进度跟随时间的增长(假设:每隔100ms,让进度条数值 + 1)




运行:



可以发现:

上个 QLCDNumber 的例子中,头文件的包含是放到了 .cpp 中的。
将头文件加到cpp文件中:

此时,点击运行也是可以正常运行的:

.h 的文件中:

明明已经用到了QTimer,但是却没在.h 文件中包含 <QTimer> 头文件中,为什么这个代码编译不会出错??为什么此处的 QTimer 就不会提示 "找不到定义" 之类的报错???
其实在 Qt 中,有一个专门的头文件,这个头文件 包含了 Qt 中多有类的 "前置声明",前置声明就是:class QTimer; class QPushButton;class QWidget; 这样的声明都专门在一个头文件中,这个头文件,一般不会直接接触到,但是包含其他的 Qt 的头文件,都会间接的包含到这个头文件。
所以在以下的代码中就会有一些前置的声明:
lass QTimer;
class QPushButton;
class QWidget;

Widget 类的前面已经提供了 QTimer 类的声明的话,此时就可以在 Widget 中声明 QTimer 的指针/引用类型的成员。这个是 C++ 中的特殊技巧,在 Qt 中被使用到了。
后续如果要真正使用 QTimer(包括创建示例,使用里面的成员......)仍然需要包含 QTimer 的头文件(包含了QTimer 的详细的类的定义)。
Qt 使用上述的技巧是为了主要解决编译速度的问题。C++ 编译速度慢,和 #include 头文件,有直接关系的。所以 尽可能减少 include 头文件的个数,就可以有效的减少编译的时间,Qt 就使用 class 前置声明的方式 来尽量减少头文件的包含。
但是在实际开发中,还是要该包含就包含!!!
eg:创建一个其它颜色的进度条

chunk就是以下的这部分:

点击 ok,但是24% 却跑到了左上角:

我们修改一下:

此时便修改好了:

进度条的进度是一般是根据实际的任务类型来灵活设置的,例如,要读取一个很大的文件,就可以先获取到文件的总大小,每读取一部分的数据,就计算出读了多少数据,更新一次进度条的数值,同时在进度条的设置中,往往是要搭配 定时器 的
4. Calender Widget
QCalendarWidget 表⽰⼀个 "⽇历" , 形如
核心属性
|------------------------|------------------------|
| 属性 | 说明 |
| selectDate | 当前选中的⽇期 |
| minimumDate | 最小日期 |
| maximumDate | 最大日期 |
| firstDayOfWeek | 每周的第⼀天(也就是⽇历的第⼀列) 是周⼏. |
| gridVisible | 是否显⽰表格的边框 |
| selectionMode | 是否允许选择⽇期 |
| navigationBarVisible | ⽇历上方标题是否显示 |
| horizontalHeaderFormat | ⽇历上方标题显⽰的⽇期格式 |
| verticalHeaderFormat | ⽇历第⼀列显⽰的内容格式 |
| dateEditEnabled | 是否允许⽇期被编辑 |
重要信号
|---------------------------------|--------------------------------------------|
| 信号 | 说明 |
| selectionChanged(const QDate&) | 当选中的⽇期发⽣改变时发出 |
| activated(const QDate&) | 当双击⼀个有效的⽇期或者按下回⻋键时发出,形参是⼀个QDate类型,保存了选中的⽇期 |
| currentPageChanged(int, int) | 当年份⽉份改变时发出,形参表示改变后的新年份和⽉份 |
eg:

右键,日历:





