目录
[3.2.1 PushButton](#3.2.1 PushButton)
[3.2.2 RadioButtion](#3.2.2 RadioButtion)
[3.2.4 Label控件](#3.2.4 Label控件)
[3.2.5 LCDNumber](#3.2.5 LCDNumber)
[3.2.7Calendar Widget](#3.2.7Calendar Widget)
[3.2.8Line Edit](#3.2.8Line Edit)
那么核心信号是什么呢?就是你右击控件,有个转到槽,就是那个里面的槽函数编辑
3.2按钮类控件
3.2.1 PushButton
那么咱们先来看:QAbstractButton 中,和 QPushButton 相关性较⼤的属性
属性 说明
text 按钮中的⽂本
icon 按钮中的图标
iconSize 按钮中图标的尺⼨
shortCut 按钮对应的快捷键
autoRepeat 按钮是否会重复触发.当⿏标左键按住不放时,
如果设为true,则会持续产⽣⿏标点击事件;
如果设为false,则必须释放⿏标,再次按下⿏标时才能产⽣点击事件. (相当于游戏⼿柄上的"连发"效果)
autoRepeatDelay 重复触发的延时时间.按住按钮多久之后,开始重复触发.(就是按下按钮之后多久后才开始触发)
autoRepeatInterval 重复触发的周期
Qt的api设计⻛格是⾮常清晰的.此处列出的属性都是可以获取和设置的,例如,使用text()获取按钮文本,使用setText()设置文本
咱们先来设置一下按钮的图标吧
先来看代码
cpp
widget.cpp
// 创建图标对象
QIcon icon(":/image.png");
// 设置图标
ui->pushButton->setIcon(icon);
// 设置图标的尺寸
ui->pushButton->setIconSize(QSize(50, 50));
那么咱们的setIconSize这个函数,
你必须得先传一个QSize函数才可以,然后QSize里面才可以写入设置的图标的尺寸大小


然后咱们来讲关于快捷键的问题
使⽤ setShortcut 给按钮设置快捷键.参数是⼀个QKeySequence对象.表⽰⼀个按键序列.⽀ 持组合键(ctrl+c这种)
cpp
//ui->pushButton->setShortcut(QKeySequence("w"));//这种情况就是设置了快捷键w,按下w也可以实现点击
//按钮的操作
ui->pushButton->setShortcut(QKeySequence(Qt::Key_W));//也可以使用这种方式来设置快捷键
ui->pushButton->setShortcut(QKeySequence(Qt::CTRL+Qt::Key_W));//这种方式是组合键
那么其实Qt::Key_W,其实是

Qt是给它封装好了一个枚举的类型,这样的话就可以直接使用Qt中的快捷键就可以了

也可以采用这个方法来实现鼠标按下就可以实现连发
3.2.2 RadioButtion
QRadioButton 是单选按钮.可以让我们在多个选项中选择⼀个.
QAbstractButton 中和 QRadioButton 关系较⼤的属性

那么这里咱们需要知道,QRadioButton本身就是具有排他性的
来看一个例子
cpp
widget.cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//在这里添加一个默认的选项
ui->radioButton_male->setChecked(true);//这个是是否已经被选中,true,代表已经被选中了
ui->label->setText("你选择的性别为: 男");
//这里我想禁用掉最后一个选项
//ui->radioButton_other->setCheckable(false);//这个代表能被选中嘛?不能!并且可以看出来
//checkable是checked的前提
ui->radioButton_other->setEnabled(false);//直接这样禁用掉也是可以的
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_radioButton_male_clicked()
{
ui->label->setText("你选择的性别为: 男");
}
void Widget::on_radioButton_female_clicked()
{
ui->label->setText("你选择的性别为: 女");
}
void Widget::on_radioButton_other_clicked()
{
ui->label->setText("你选择的性别为: 其他");
}

那么此时的状态就是这么个状态,主要看的是QRadioButton本身就是具有排他性的
那么咱们再来看一个例子:

clicked(bool)就是看看这个按钮是否被选中,如果被选中,这个checked就为true,否则为false
pressed()是这个按钮按下之后,就会触发这个槽函数
released()是这个按钮按下,得是松开的那一瞬间,就是会触发这个槽函数
toggled(bool)是这个按钮切换之后,才会触发,点击按钮时,是true,那么切换按钮之后,就是false了。(checked 状态发生改变, 就会触发这个信号.)
cpp
widget.cpp
oid Widget::on_radioButton_clicked(bool checked)
{
qDebug()<<"clicked"<< checked;//其实这个地方,就是看看这个按钮是否被选中了,被选中了就是true,
//没被选中就是false
}
void Widget::on_radioButton_2_pressed()
{
qDebug() << "pressed";
}
void Widget::on_radioButton_3_released()
{
qDebug() << "released";
}
void Widget::on_radioButton_4_toggled(bool checked)
{
// checked 状态发生改变, 就会触发这个信号.
qDebug() << "toggled: " << checked;
}

按完第四个按钮后,我是直接又按的1这个按钮
咱们现在再来写一个例子

写一个选择小食的,但是,这里有个问题

cpp
// 使用 QButtonGroup 对单选按钮进行分组
QButtonGroup* group1 = new QButtonGroup(this);
QButtonGroup* group2 = new QButtonGroup(this);
QButtonGroup* group3 = new QButtonGroup(this);
// 把上述单选按钮, 放到不同的组里.
group1->addButton(ui->radioButton);
group1->addButton(ui->radioButton_2);
group1->addButton(ui->radioButton_3);
group2->addButton(ui->radioButton_4);
group2->addButton(ui->radioButton_5);
group2->addButton(ui->radioButton_6);
group3->addButton(ui->radioButton_7);
group3->addButton(ui->radioButton_8);
但是咱们只需要分组一下,就完全没问题了,

3.2.3CheckBox
QCheckBox 表⽰复选按钮.可以允许选中多个.(小孩子才做选择,我全都要)
就是一个可以多选的按钮,不具有排他性
来看代码

给提交按钮装上槽函数
cpp
void Widget::on_pushButton_clicked()
{
QString result = "今天你的安排是: ";
if (ui->checkBox_study->isChecked()) {
result += ui->checkBox_study->text() + " ";
}
if (ui->checkBox_game->isChecked()) {
result += ui->checkBox_game->text() + " ";
}
if (ui->checkBox_work->isChecked()) {
result += ui->checkBox_work->text();
}
ui->label->setText(result);
}
其实说,这个ischecked要是true,说明这个按钮就被选中了,也就说明可以进入这个if了。因为checked本身就是判断这个按钮是否被选中。

那么运行结果就是如图所示
3.2.4 Label控件
QLabel 就是⽤来显⽰⽂本和图⽚的控件
属性 说明
text QLabel 中的⽂本
textFormat 文本的格式
-
Qt::PlainText纯文本最普通的文本-
Qt::RichText富文本 (支持 html 标签)内容更丰富的文本,支持 htmlword 工具,编辑的文件,就可以认为是一种富文本.-
Qt::MarkdownTextmarkdown 格式作为程序猿,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设置文本格式:
cpp
widget.cpp
// 把第一个 label 设置成显示纯文本.那么不管你在这里面设置markdown的格式还是html的格式,全都无效
ui->label->setTextFormat(Qt::PlainText);
ui->label->setText("# 这是一段纯文本");
// 把第二个 label 设置成显示富文本,可设置html的格式
ui->label_2->setTextFormat(Qt::RichText);
ui->label_2->setText("<b>这是一段富文本</b>");
// 把第三个 label 设置成显示 markdown > " *等都是markdown格式
ui->label_3->setTextFormat(Qt::MarkdownText);
ui->label_3->setText("# 这是 markdown 文本");
结果就是:

差别还是挺明显的
QLabel设置图片
来看代码
cpp
widget.cpp
ui->setupUi(this);
QRect windowRect = this->geometry();//先获取到这个窗口的尺寸大小
//先把 QLabel 设置成和窗口一样大, 并且把这个 QLabel 左上角设置到窗口的左上角这里.
// 让整个 QLabel 铺满整个窗口
ui->label->setGeometry(0,0,windowRect.width(),windowRect.height());//然后根据窗口的尺寸大小
//设置一下你的label的窗口大小
QPixmap pixmap = QPixmap(":/image.png");
ui->label->setPixmap(pixmap);
// 启动自动拉伸. 此时图片就能够填充满整个窗口了.
ui->label->setScaledContents(true);

咱们可以看到,确实image充满了整个label,而label又充满了整个窗口,但是现在有一个问题,什么问题呢,就是这个图标不会根据你的拖动改变大小,
例如这样,那么此时就需要用到事件机制
Qt 中,表示用户的操作,有两类概念,一个是信号,另一个是事件
当用户拖拽修改窗口大小的时候,就会触发 resize 事件 (resizeEvent)
像 resize 这样的事件,是连续变化的。把窗口尺寸从 A 拖到 B 这个过程中,会触发出一系列的 resizeEvent.
此时就可以借助 resizeEvent 来完成上述的功能.
可以让 Widget 窗口类,重写父类 (QWidget) 的 resizeEvent 虚函数(在鼠标拖动窗口尺寸的过程中 这个函数就会被反复调用执行,每次触发一个 resizeEvent 事件都会调用一次对应的虚函数)
由于此处进行了函数重写,调用父类的虚函数就会实际调用到子类的对应的函数 (多态)
事件的话,是必须要用到虚函数重写的,这个是规定的。
来看代码
cpp
widget.cpp
#include "ui_widget.h"
#include <QPixmap>
#include <QResizeEvent>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QRect windowRect = this->geometry();//先获取到这个窗口的尺寸大小
//先把 QLabel 设置成和窗口一样大, 并且把这个 QLabel 左上角设置到窗口的左上角这里.
// 让整个 QLabel 铺满整个窗口
ui->label->setGeometry(0,0,windowRect.width(),windowRect.height());//然后根据窗口的尺寸大小
//设置一下你的label的窗口大小
QPixmap pixmap = QPixmap(":/image.png");
ui->label->setPixmap(pixmap);
// 启动自动拉伸. 此时图片就能够填充满整个窗口了.
ui->label->setScaledContents(true);
}
Widget::~Widget()
{
delete ui;
}
void Widget::resizeEvent(QResizeEvent *event)
{
// 此处的形参 event 是非常有用的, 这里就包含了触发这个 resize 事件这一时刻, 窗口的尺寸的数值.就是窗口尺寸
//随着你拖拽窗口,你的图片尺寸也会发生改变
ui->label->setGeometry(0,0,event->size().width(), event->size().height());//别忘了包含头文件
}
那么实际执行的效果就是图标随着窗口的改变而改变大小了
此处的 resizeEvent 函数我们没有⼿动调⽤,但是能在窗⼝⼤⼩变化时被⾃动调⽤. 这个过程就是依赖C++中的多态来实现的.Qt框架内部管理着QWidget对象表⽰咱们的窗 ⼝.在窗⼝⼤⼩发⽣改变时,Qt就会⾃动调⽤ resizeEvent 函数. 但是由于实际上这个表⽰窗⼝的并⾮是QWidget,⽽是QWidget的⼦类,也就是咱们⾃⼰写 的Widget.此时虽然是通过⽗类调⽤函数,但是实际上执⾏的是⼦类的函数(也就是我们重写 后的 resizeEvent ). 此处属于是多态机制的⼀种经典⽤法.通过上述过程,就可以把⾃定义的代码,插⼊到框架内 部执⾏.相当于"注册回调函数".
ok,那么咱们现在继续来进行写代码,
咱们来看这个QFrame中的框架类型,QFrame 是 QLabel 的⽗类.其中 frameShape 属性⽤来设置边框性质.
QFrame::Box 矩形边框
Q Frame::Panel :带有可点击区域的⾯板边框
• QFrame::WinPanel :Windows⻛格的边框
• Q Frame::HLine :⽔平线边框
• Q Frame::VLine :垂直线边框
• Q Frame::StyledPanel :带有可点击区域的⾯板边框,但样式取决于窗⼝主题

那么现在我设置的是Box,矩形边框
cpp
widget.cpp
// 在构造函数中, 给这几个 label 设置不同的属性.
// 设置对齐方式
ui->label->setText("这是一段文本");
ui->label->setAlignment(Qt::AlignRight | Qt::AlignTop);
// 设置自动换行
ui->label_2->setText("这是一段很长的文本这是一段很长的文本这是一段很长的文本这是一段很长的文本这是一段很长的文本这是一段很长的文本这是一段很长的文本这是一段很长的文本这是一段很长的文本这是一段很长的文本这是一段很长的文本");
ui->label_2->setWordWrap(true);//这个是设置自动换行
// 设置缩进
ui->label_3->setText("这是一段很长的文本这是一段很长的文本这是一段很长的文本这是一段很长的文本这是一段很长的文本这是一段很长的文本这是一段很长的文本这是一段很长的文本这是一段很长的文本这是一段很长的文本这是一段很长的文本");
ui->label_3->setWordWrap(true);
ui->label_3->setIndent(50);//左侧和上⽅和边框有间距.右侧则没有.
// 设置边距
ui->label_4->setText("这是一段很长的文本这是一段很长的文本这是一段很长的文本这是一段很长的文本这是一段很长的文本这是一段很长的文本这是一段很长的文本这是一段很长的文本这是一段很长的文本这是一段很长的文本这是一段很长的文本");
ui->label_4->setWordWrap(true);
ui->label_4->setMargin(50);//这个是上下左右边框都是50像素
首行缩进注意事项

运行结果就是如图所示的结果,
Qt::AlignRight | Qt::AlignTop这个代码的意思就是靠右边,并且靠上边,就是右上角
那么咱们点进去其中一个的定义,就会看到这种,qt也是把这个给枚举出来了
| 枚举成员 | 数值 | 含义说明 |
|---|---|---|
AlignLeft |
0x0001 |
水平左对齐(通用场景) |
AlignLeading |
同 AlignLeft |
与 AlignLeft 等价,适配从左到右(LTR) 文字体系(如中文、英文) |
AlignRight |
0x0002 |
水平右对齐 |
AlignTrailing |
同 AlignRight |
与 AlignRight 等价,适配从左到右文字体系;在从右到左(RTL)体系中会自动切换为左对齐 |
AlignHCenter |
0x0004 |
水平居中对齐 |
AlignJustify |
0x0008 |
水平两端对齐(文本行左右均贴边,仅对多行文本有效) |
AlignAbsolute |
0x0010 |
绝对对齐,忽略文字方向(RTL 体系中仍强制左 / 右对齐,不自动切换) |
| 枚举成员 | 数值 | 含义说明 |
|---|---|---|
AlignTop |
0x0020 |
垂直顶部对齐 |
AlignBottom |
0x0040 |
垂直底部对齐 |
AlignVCenter |
0x0080 |
垂直居中对齐 |
AlignBaseline |
0x0100 |
按文本基线对齐(仅对文本类控件有效,如标签、按钮文字) |
QLabel设置伙伴
什么叫做伙伴关系呢,就是两个控件之间进行联系,
// 设置label 的伙伴widget
ui->label->setBuddy(ui->radioButton);
ui->label_2->setBuddy(ui->radioButton_2);
比如这个代码,
那么你既可以通过鼠标点击选项一,或者是按alt+A也可以
Qt 中,QLabel 中写的文本,是可以指定 "快捷键"此处快捷键的规则功能上要比 QPushButton 弱很多.
是在文本中使用 & 跟上一个字符来表示快捷键.
比如 &A => 通过键盘上的 alt + a 来触发这个快捷键.&B => 通过键盘上的 alt + b 来触发.
绑定了伙伴关系之后,通过快捷键就可以选中对应的单选按钮 / 复选按钮
3.2.5 LCDNumber
QLCDNumer 是⼀个专⻔⽤来显⽰数字的控件.类似于"⽼式计算器"的效果
| 属性名 | 说明 |
|---|---|
| intValue | 显示的整数值 (int 类型),与 value 联动,会自动取整。 |
| value | 显示的浮点数值 (double 类型),与 intValue 联动。设置数值需调用 display() 方法,而非 setValue()/setIntValue()。 |
| digitCount | 控制显示的数字位数(包含小数点、负号等)。 |
| mode | 数字显示进制模式,仅十进制可显示小数:1. Dec:十进制2. Hex:十六进制3. Bin:二进制4. Oct:八进制 |
| segmentStyle | 数字显示风格:1. Flat:平面风格2. Outline:轮廓风格(带阴影)3. Filled:填充风格(实心数码管) |
| smallDecimalPoint | 设置为 true 时,使用较小尺寸的小数点,避免占用过多显示位数。 |
那么咱们现在来写一个例子
来看一个倒计时器:
cpp
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QTimer>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
ui->lcdNumber->display(10);//设置一个倒计时器,从10开始进行倒计时
//这里咱们采用QTimer中有个timout信号,那么自然的,咱们也要创造出一个槽函数进行接收
//QTimer 表⽰定时器.通过QTimer start ⽅法启动定时器之后,就会每隔⼀定周期,触发⼀次QTimer::timeout 信号,那么每触发一次信号
//就会执行一次槽函数
timer = new QTimer(this);//这里咱们由于需要在槽函数中使用QTimer,所以QTimer必须定义成成员变量才可以,在类外访问它
connect(timer,&QTimer::timeout,this,&Widget::handle);
timer->start(1000);//单位是毫秒,就是每隔1秒发送一次信号,每次触发QTimer::timeout,就会触发一次handle槽函数
}
Widget::~Widget()
{
delete ui;
}
void Widget::handle()
{
//那么咱们在这里就行逻辑执行
int value=ui->lcdNumber->value();
if(value<=0)
{
timer->stop();//结束信号
return;
}
ui->lcdNumber->display(value-1);
}
cpp
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
void handle();
private:
Ui::Widget *ui;
QTimer * timer;
};
#endif // WIDGET_H
启动定时器,是在connect函数之后才可以

那么运行结果就是这样的从10开始的倒计时,一直到0结束
3.2.6ProgressBar
使⽤ QProgressBar 表⽰⼀个进度条.
注 意,不要把ProgessBar拼写成ProcessBar
核心属性:
| 属性名 | 说明 |
|---|---|
| minimum | 进度条的最小值(进度范围的下限)。(进度条在最左边的时候) |
| maximum | 进度条的最大值(进度范围的上限)。(进度条在最右边的时候) |
| value | 进度条当前显示的数值(介于 minimum 和 maximum 之间)。 |
| alignment | 进度条内文本的对齐方式,可选值:- Qt::AlignLeft:左对齐- Qt::AlignRight:右对齐- Qt::AlignCenter:居中对齐- Qt::AlignJustify:两端对齐 |
| textVisible | 控制进度条上的数字文本是否可见(true/false)。 |
| orientation | 进度条的方向:- Qt::Horizontal:水平- Qt::Vertical:垂直 |
| invertAppearance | 是否反向显示进度(true 时进度从右到左 / 从下到上增长)。 |
| textDirection | 进度条文本的朝向(仅对垂直进度条有效,控制文字阅读方向)。 |
| format | 自定义进度文本的显示格式,支持占位符:- %p:进度百分比(0-100)- %v:当前数值- %m:剩余时间(毫秒)- %t:总时间(毫秒) |
那么咱们还是来写一个例子,这个例子还是需要用到timeout信号
cpp
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QTimer>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &Widget::handle);
// 别忘了启动定时器. 启动操作要在 connect 之后.
timer->start(100);
}
Widget::~Widget()
{
delete ui;
}
void Widget::handle()
{
// 获取到进度条的当前数值.
int value = ui->progressBar->value();
if (value >= 100) {
// 进度条满了, 就可以停止定时器了.
timer->stop();
return;
}
ui->progressBar->setValue(value + 1);
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
void handle();
private:
Ui::Widget *ui;
QTimer*timer;
};
#endif // WIDGET_H

那么成果就是一个从0开始的进度条,这个地方涉及到了一个问题
咱们的QTimer头文件是包含在.cpp文件中的,那么.h文件中并没有这个头文件,那么没有这个头文件的话,.h文件中的QTimer*timer是怎么能定义的呢?不是应该报错吗?

Qt 为啥要使用上述的技巧,上述技巧能解决什么问题?有啥提升呢?
主要解决的是编译速度的问题
C/C++ 的代码,编译速度在其他语言横向对比中,是非常慢的
对于一个大规模的项目,编译速度可能非常慢!!!俺在华为的时候,我们哪怕只是给代码中添加一个 printf, 编译消耗的时间,就是 1 个小时左右
C++ 编译速度慢,和 #include 头文件,有直接关系的
由于 include 关系错综复杂~~因此,尽可能减少 include 头文件的个数,就可以有效的减少编译时间
Qt 中就使用 class 前置声明的方式,来尽量减少头文件的包含~~通过前置声明的方式,Qt 中的头文件,每个头文件包含的其他头文件数量都能得到一定的降低~~所以在 C++ 20 标准开始,就引入了 "模块" module 来替代 #include ~~
但是咱们实际开发中,还是要该包含就包含~~与其通过特殊技巧来缩短编译时间,不如说引入更好的硬件资源,来更高效的编译
一些互联网大厂,都有专门的 "编译集群" (分布式编译)
在实际开发中,进度条的取值,往往是根据当前任务的实际进度来进⾏设置的. ⽐如需要读取⼀个很⼤的⽂件,就可以获取⽂件的总的⼤⼩,和当前读取完毕的⼤⼩,来设置进 度条的⽐例. 由于上⾯我们介绍了Qt禁⽌在其他线程修改界⾯,因此进度条的更新往往也是需要搭配定时 器来完成的. 通过定时器周期触发信号,主线程调⽤对应的slot函数.再在slot函数中对当前的任务进度进 ⾏计算,并更新进度条的界⾯效果.
3.2.7Calendar Widget
这个其实就是个电子日历
QCalendarWidget 核心属性与重要信号整理
| 属性名 | 说明 |
|---|---|
| selectDate | 当前选中的日期(QDate 类型) |
| minimumDate | 可选择的最小日期(限制日期范围下限) |
| maximumDate | 可选择的最大日期(限制日期范围上限) |
| firstDayOfWeek | 设置每周的第一天(即日历第一列显示的星期几,如周一 / 周日) |
| gridVisible | 是否显示日历表格的网格边框(true/false) |
| selectionMode | 日期选择模式:控制是否允许选择日期、是否支持多选等 |
| navigationBarVisible | 是否显示日历顶部的导航栏(年月切换栏,true/false) |
| horizontalHeaderFormat | 日历上方水平标题的日期格式(如显示月份 / 年份、星期缩写等) |
| verticalHeaderFormat | 日历左侧垂直列的内容格式(如显示周数、星期全称 / 缩写等) |
| dateEditEnabled | 是否允许直接编辑日期(可手动输入日期,true/false) |
重要信号
| 信号名 | 说明 |
|---|---|
| selectionChanged(const QDate&) | 当选中的日期发生改变时触发,形参为新选中的 QDate |
| activated(const QDate&) | 双击有效日期或按下回车键时触发,形参为被激活的 QDate |
| currentPageChanged(int, int) | 当切换年份 / 月份时触发,形参依次为新的年份 、新的月份 |
cpp
widget.cpp
void Widget::on_calendarWidget_selectionChanged()
{
QDate date = ui->calendarWidget->selectedDate();
qDebug() << date;
ui->label->setText(date.toString());//setText():QLabel 的成员函数,用于设置标签显示的文本内容;
//date.toString():将 QDate 对象转换成字符串(默认格式为 yyyy-MM-dd,如 2026-03-07)
}
这个就是你选中了日期之后,它可以显示到label上面
3.2.8Line Edit
QLineEdit ⽤来表⽰单⾏输⼊框.可以输⼊⼀段⽂本,但是不能换⾏
QLineEdit 核心属性整理表
| 属性 | 说明 |
|---|---|
| text | 输入框中的文本 |
| inputMask | 输入内容格式约束 |
| maxLength | 最大输入长度 |
| frame | 是否添加边框 |
| echoMode | 显示方式,可选值:• QLineEdit::Normal:默认值,正常显示输入文本• QLineEdit::Password:隐藏输入字符,通常用星号 * 或等号 = 代替• QLineEdit::NoEcho:不显示任何输入字符 |
| cursorPosition | 光标所在位置 |
| alignment | 文字对齐方式,可设置水平和垂直方向对齐 |
| dragEnabled | 是否允许拖拽 |
| readOnly | 是否为只读状态(不允许修改内容) |
| placeHolderText | 输入框为空时显示的提示信息 |
| clearButtonEnabled | 是否自动显示 "清除按钮" |



QLineEdit 核心信号整理表
| 信号签名 | 说明 |
|---|---|
void cursorPositionChanged(int old, int new) |
当光标位置移动时发出此信号,old 为先前的位置,new 为新位置。 |
void editingFinished() |
当按下返回 / 回车键,或编辑框失去焦点时,发出此信号。 |
void returnPressed() |
当返回 / 回车键按下时发出此信号。若设置了验证器,必须验证通过才能触发。 |
void selectionChanged() |
当选中的文本改变时,发出此信号。 |
void textChanged(const QString &text) |
当 QLineEdit 中的文本改变时发出此信号,text 为新文本。代码对文本的修改也能触发该信号。 |
void textEdited(const QString &text) |
当 QLineEdit 中的文本改变时发出此信号,text 为新文本。代码对文本的修改不能触发该信号,仅用户手动编辑时触发。 |
那么核心信号是什么呢?就是你右击控件,有个转到槽,就是那个里面的槽函数
就是这些
咱们来看一个了例子
cpp
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 初始化第一个输入框, 用来输入姓名
ui->lineEdit_name->setPlaceholderText("请输入姓名");
ui->lineEdit_name->setClearButtonEnabled(true);
// 初始化第二个输入框, 用来输入密码
ui->lineEdit_password->setPlaceholderText("请输入密码");
ui->lineEdit_password->setClearButtonEnabled(true);
// 把显示模式设置成显示密码的模式.
ui->lineEdit_password->setEchoMode(QLineEdit::Password);
// 初始化第三个输入框
ui->lineEdit_phone->setPlaceholderText("请输入手机号码");
ui->lineEdit_phone->setClearButtonEnabled(true);
// 手机号码是有固定格式的. 此处的 0 代表 "数字"
ui->lineEdit_phone->setInputMask("000-0000-0000");//inputMask 可以针对输入框的内容进行简单校验。
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_submit_clicked()
{
QString gender = ui->radioButton_male->isChecked() ? "男" : "女";//咱们知道,ischecked就是是否被选中
qDebug() << "姓名: " << ui->lineEdit_name->text()
<< "密码: " << ui->lineEdit_password->text()
<< "性别: " << gender
<< "电话: " << ui->lineEdit_phone->text();
}

可以看出来,姓名和密码这里,你没有输入之前,都有提示词,但是你一旦输入了进去,那么这个提示词就会没有,并且会在最右边出现一个叉号,就是清空的意思
那么咱们看这个inputMask只能进⾏简单的输⼊格式校验。实际开发中,基于正则表达式的⽅式是更核⼼的⽅法
正则表达式⽂档https://learn.microsoft.com/zh-cn/previous versions/visualstudio/visual-studio-2008/ae5bf541(v=vs.90)?redirectedfrom=MSDN
那么下面咱们来看一个正则表达式的案例
cpp
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QRegExpValidator>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 就需要给单行输入框设置验证器. 基于正则表达式来完成验证的~~
QRegExp regExp("^1\\d{10}$");
ui->lineEdit->setValidator(new QRegExpValidator(regExp));
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_lineEdit_textEdited(const QString &text)
{
QString content = text;// 把用户刚输入的内容存起来
int pos = 0;// 标记光标位置(暂时用不到,只是验证函数要求传)
// 调用验证器,检查当前输入的内容是否符合规矩
if (ui->lineEdit->validator()->validate(content, pos) == QValidator::Acceptable) {
// 验证通过,(比如用户输入了13812345678)
ui->pushButton->setEnabled(true);// 点亮按钮(可以点击了)
} else {
// 验证不通过(比如只输了138,或者输了1a812345678)
ui->pushButton->setEnabled(false);// 灰掉按钮(点不了)
}
}
代码解析
ui->setupUi(this);:初始化界面,简单说就是把你用 Qt Designer 画的窗口、输入框、按钮这些显示出来。QRegExp regExp("^1\\d{10}$");:定 "规矩" 的核心 ------
^1:输入内容必须以 1 开头(手机号都是 1 开头);\\d{10}:后面必须跟10 个数字(\d 代表 0-9 的数字,{10} 代表刚好 10 个);$:结尾,意思是输入完 11 位就结束,不能多也不能少。合起来就是:必须是 11 位、以 1 开头的纯数字(标准手机号格式)。ui->lineEdit->setValidator(...):把这个 "规矩" 绑定到输入框(lineEdit)上,相当于告诉输入框:"你只准接受符合这个规矩的内容!"on_lineEdit_textEdited:这是 Qt 的 "信号槽" 机制 ------ 只要用户手动在输入框里改了内容(比如打字、删字),这个函数就会自动触发(代码改输入框内容不会触发,这是 textEdited 和 textChanged 的区别)。validator()->validate(...):调用我们之前绑定的 "规矩",检查当前输入的内容:
- 返回
QValidator::Acceptable:就是 "合格",比如输满 11 位正确手机号;- 其他返回值(比如 Intermediate/Invalid):就是 "不合格",比如位数不够、有字母。
pushButton->setEnabled(true/false):控制按钮能不能点 ------ 合格就点亮,不合格就灰掉,避免用户填错还能提交。举个实际使用的例子
- 用户先输入 "138":只有 3 位,验证不通过 → 提交按钮灰的,点不了;
- 用户继续输入到 "13812345678":刚好 11 位、以 1 开头的数字 → 验证通过 → 提交按钮瞬间点亮,能点击了;
- 用户如果输入 "138a1234567":有字母 a → 验证不通过 → 按钮还是灰的。
总结
- 核心逻辑:给输入框设 "手机号格式规矩",用户输入时实时检查,合格才让点提交按钮;
- 关键知识点:
QRegExp(定验证规则)、QRegExpValidator(验证器)、textEdited(用户手动输入触发的信号);- 作用:避免用户填错手机号,提升界面交互体验,不用等用户点提交才提示错误。
结果就是你输入的东西必须满足这个正则表达式,它才可以让你去提交

那么咱们再来写一个例子吧,就是验证两个密码是否一致:
先来看代码
cpp
widget.cpp
#include "widget.h"
#include "ui_widget.h"
//#incldue <QString>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
ui->lineEdit->setEchoMode(QLineEdit::Password);//注意这个地方是QLineEdit
ui->lineEdit_2->setEchoMode(QLineEdit::Password);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_lineEdit_textEdited(const QString &arg1)
{
this->handle();
}
void Widget::on_lineEdit_2_textEdited(const QString &arg1)
{
this->handle();
}
void Widget::handle()
{
//如果两个密码一样,现实的Label的内容就是两个密码一样
const QString& s1=ui->lineEdit->text();//获取到密码用的是text()这个函数
const QString& s2=ui->lineEdit_2->text();
if(s1==s2)
{
ui->label->setText("本次输入的密码一致");
ui->label->setEnabled(true);
}
else
{
ui->label->setText("本次输入的密码不一致,请重新检查后重拾");
}
}
//本次代码中采用了代码的复用
那么结果就是当两次的密码输入的一致的话,Label显示的就是密码一致,否则就是密码不一致
那么咱们今天的博客先写到这里,咱们下次再见