Qt 显示类控件

Label

QLabel 可以用来显示文本和图片

核心属性如下

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

代码示例:显示不同格式的文本

(1) 界面上创建三个 QLabel

尺寸放大一些。obiectName 分别为 label,label 2,label 3

在这里插入图片描述

(2) 修改 widget.cpp,设置三个 label 的属性

Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
	ui->setupUi(this);
	ui->label->setTextFormat(Qt::PlainText);
	ui->label->setText("这是⼀段纯⽂本");
	ui->label_2->setTextFormat(Qt::RichText);
	ui->label_2->setText("<b> 这是⼀段富⽂本 </b>");
	ui->label_3->setTextFormat(Qt::MarkdownText);
	ui->label_3->setText("## 这是⼀段 markdown ⽂本");
}

(3) 运行程序,观察效果

在这里插入图片描述

代码示例:显示图片

虽然 QPushButton 也可以通过设置图标的方式设置图片,但是并非是一个好的选择。更多的时候还是希望通过 QLabel 来作为一个更单纯的显示图片的方式。

(1) 在界面上创建一个 QLabel,objectNamelabel

在这里插入图片描述

(2) 创建 resource.qrc 文件,并把图片导入到 qrc中

在这里插入图片描述

(3) 修改 widget.cpp,给 QLabel 设置图片

// 设置 label ⼤⼩和窗⼝⼀样⼤
ui->label->setGeometry(0, 0, 800, 600);
QPixmap pixmap(":/huaji.png");
ui->label->setPixmap(pixmap);

执行程序,观察效果

在这里插入图片描述

这个图片本身的尺寸是 480 * 480, 并没有把 QLabel 填充满.

(4) 修改代码,设置 scaledContents 属性

// 设置内容伸缩
ui->label->setScaledContents(true);

再次运行,观察效果,可以看到图片已经被拉伸,可以把窗口填满了

在这里插入图片描述

(5) 此时如果拖动窗口大小可以看到图片并不会随着窗口大小的改变而同步变化.

在这里插入图片描述

为了解决这个问题,可以在 Widget 中重写 resizeEvent 函数

// 重写 widget的resizeEvent函数. 这个函数会在窗⼝⼤⼩发⽣改变时被⾃动调⽤.
void Widget::resizeEvent(QResizeEvent *event) {
	// 可以直接通过 this->width() 和 this->height() 设置 label 新的尺⼨, 也可以通过 event 参数拿到新的尺⼨.
	// ui->label->setGeometry(0, 0, this->width(), this->height());
	ui->label->setGeometry(0, 0, event->size().width(), event->size().height());

	qDebug() << event->size();
}

执行程序,此时改变窗口大小,图片也会随之变化.

在这里插入图片描述

于此同时,在控制台里也能够看到尺寸变化的过程

在这里插入图片描述

此处的 resizeEvent 函数我们没有手动调用,但是能在窗口大小变化时被自动调用。

这个过程就是依赖 C++ 中的多态来实现的。Qt 框架内部管理着 QWidget 对象表示咱们的窗口。在窗口大小发生改变时,Qt 就会自动调用 resizeEvent 函数。

但是由于实际上这个表示窗口的并非是 QWidget,而是 QWidget 的子类。也就是咱们自己写的 Widget。此时虽然是通过父类调用函数,但是实际上执行的是子类的函数(也就是我们重写后的 resizeEvent ).

此处属于是多态机制的一种经典用法,通过上述过程,就可以把自定义的代码,插入到框架内部执行。相当于“注册回调函数”;

代码示例:文本对齐,自动换行,缩进,边距

(1) 创建四个 label,objectName 分别是 label 到 label_4

并且在 QFrame 中设置 frameShape 为 Box (设置边框之后看起来会更清晰一些)

在这里插入图片描述

在这里插入图片描述

QFrameQLabel 的父类。其中 frameshape 属性用来设置边框性质

  • OFrame::Box:矩形边框
  • QFrame::Panel:带有可点击区域的面板边框
  • QFrame::WinPanel :Windows风格的边框
  • QFrame::HLine:水平线边框
  • QFrame::VLine:垂直线边框
  • OFrame::StyledPanel :带有可点击区域的面板边框,但样式取决于窗口主题

(2) 编写 widget.cpp, 给这四个 label 设置属性.

Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
	ui->setupUi(this);
	// 设置⽂字居中对⻬
	ui->label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
	ui->label->setText("垂直⽔平居中的⽂本");
	// 设置⾃动换⾏
	ui->label_2->setAlignment(Qt::AlignTop | Qt::AlignLeft);
	ui->label_2->setWordWrap(true);
	ui->label_2->setText("这是⼀个很⻓的⽂本这是⼀个很⻓的⽂本这是⼀个很⻓的⽂本这是⼀个很⻓的⽂本这是⼀个很⻓的⽂本这是⼀个很⻓的⽂本");
	// 设置⾸⾏缩进
	ui->label_3->setAlignment(Qt::AlignTop | Qt::AlignLeft);
	ui->label_3->setIndent(20);
	ui->label_3->setText("这是⼀个很⻓的⽂本这是⼀个很⻓的⽂本这是⼀个很⻓的⽂本这是⼀个很⻓的⽂本这是⼀个很⻓的⽂本这是⼀个很⻓的⽂本");
	// 设置边距
	ui->label_4->setAlignment(Qt::AlignTop | Qt::AlignLeft);
	ui->label_4->setMargin(20);
	ui->label_4->setText("这是⼀个很⻓的⽂本这是⼀个很⻓的⽂本这是⼀个很⻓的⽂本这是⼀个很⻓的⽂本这是⼀个很⻓的⽂本这是⼀个很⻓的⽂本");
}

在这里插入图片描述

代码示例:设置伙伴

(1) 创建两个 label 和 两个 radioButton.

objectName 分别为 labellabel_2radioButtonradioButton_2

在这里插入图片描述

此处把 label 中的文本设置为“快捷键 &A”这样的形式

其中 & 后面跟着的字符,就是快捷键

可以通过 alt + A的方式来触发该快捷键

但是注意,这里的快捷键和 QPushButton 的不同,需要搭配 alt 和 单个字母的方式才能触发

(2) 编写 widget.cpp,设置 buddy 属性

当然这里也可以使用 Qt Designer 直接设置.

Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
	ui->setupUi(this);
	// 设置 label 的伙伴 widget
	ui->label->setBuddy(ui->radioButton);
	ui->label_2->setBuddy(ui->radioButton_2);
}

(3) 运行程序,可以看到,按下快捷键 alt +a 或者 alt + b 即可选中对应的选项

在这里插入图片描述

LCD Number

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::Pct:八进制模式,以八进制格式显示数字
只有十进制的时候才能显示小数点后的内容.
segmentStyle设置显示风格
QLCDNumber::Flat:平面的显示风格,数字呈现在一个平坦的表面上。
QLCDNumber::Outline: 轮廓显示风格,数字具有清晰的轮廓和阴影效果。
QLCDNumber::Filled:填充显示风格,数字被填充颜色并与背景区分。
smallDecimalPoint设置比较小的小数点.

代码示例:倒计时

(1) 在界面上创建一个 QLCDNumber,初始值设为 10。 objectNamelcdNumber

在这里插入图片描述

(2) 修改 widget.h 代码,创建一个 QTimer 成员,和一个 updateTime 函数

QTimer* timer;
void updateTime();

(3) 修改 widget.cpp,在构造函数中初始化 QTimer

QTimer 表示定时器通过 start 方法启动定时器之后,就会每隔一定周期,触发一次 QTimer::timeout 信号

使用 connectQTimer::timeout 信号和 Widget::updateTime 连接起来,意味着每次触发 QTimer::timeout 都会执行 Widget::updateTime

Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
	ui->setupUi(this);
	// 创建 QTimer 实例
	timer = new QTimer(this);
	// 连接信号槽. QTimer 会每隔⼀定的时间触发⼀个 timeout 信号. 现在把 timeout 信号和 updateTime 连接起来.
	// 此时意味着每次触发 timeout 信号都会伴随 updateTime 函数的执⾏.
	connect(timer, &QTimer::timeout, this, &Widget::updateTime);
	// 启动 QTimer, 并且规定每隔 1000ms 触发⼀次 timeout 信号.
	timer->start(1000);
}

(4) 修改 widget.cpp, 实现 updateTime

  • 通过 intValue 获取到 QLCDNumber 内部的数值.
  • 如果 value 的值归 0 了,就停止 QTimer。接下来 QTimer 也就不会触发 timeout 信号了
void Widget::updateTime() {
	qDebug() << "updateTime";
	int value = ui->lcdNumber->intValue();
	if (value <= 0) {
	// 如果时间到, 停⽌定时器.
	timer->stop();
	return;
	}
	ui->lcdNumber->display(value - 1);
}

(5) 执行程序,可以看到每隔一秒钟,显示的数字就减少 1.

在这里插入图片描述

针对上述代码,存在两个问题

(1) 上述代码如果直接在 Widget 构造函数中,通过一个循环 + sleep 的方式是否可以呢?

代码形如

Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
	ui->setupUi(this);
	int value = ui->lcdNumber->intValue();
	while (true) {
		std::this_thread::sleep_for(std::chrono::seconds(1));
		if (value <= 0) {
		break;
		}
	ui->lcdNumber->display(value - 1);
	}
}

显然,这个代码是不行的。循环会使 Widget 的构造函数无法执行完毕,此时界面是不能正确构造和显示

(2) 上述代码如果是在 Widget 构造函数中,另起一个线程,在新线程中完成循环 + sleep 是否可以呢?

代码形如

Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
	ui->setupUi(this);
	std::thread t([this]() {
		int value = this->ui->lcdNumber->intValue();
		while (true) {
			std::this_thread::sleep_for(std::chrono::seconds(1));
			if (value <= 0) {
			break;
			}
			this->ui->lcdNumber->display(value - 1);
		}
	});
}

这个代码同样是不行的。Qt 中规定,任何对于 GUI 上内容的操作,必须在主线程中完成。像 Widget 构造函数,以及 connect 连接的 slot 函数,都是在主线程中调用的。而我们自己创建的线程则不是。当我们自己的线程中尝试对界面元素进行修改时,Qt 程序往往会直接崩溃。

这样的约定主要是因为 GUI 中的状态往往是牵一发动全身的,修改一个地方,就需要同步的对其他内容进行调整。

比如调整了某个元素的尺寸,就可能影响到内部的文字位置,或者其他元素的位置。这里一连串的修改,都是需要按照一定的顺序来完成的。

由于多线程执行的顺序无法保障,因此 Qt 从根本上禁止了其他线程修改 GUI 状态避免后续的一系列问题。

ProgressBar

使用 QProgressBar 表示一个进度条

在这里插入图片描述

核心属性

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

代码示例: 设置进度条按时间增长

(1) 在界面上创建进度条,objectNameprogressBar

在这里插入图片描述

其中最小值设为 0,最大值设为 100。当前值设为0

(2) 修改 widget.h, 创建 QTimer 和 updateProgressBar 函数

QTimer* timer;
void updateProgressBar ();

(3) 修改 widget.cpp, 初始化 QTimer

此处设置 100ms 触发一次 timeout 信号,也就是一秒钟触发 10次

Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
	ui->setupUi(this);
	timer = new QTimer(this);
	connect(timer, &QTimer::timeout, this, &Widget::updateProgressBar);
	timer->start(100);
}

(4) 修改 widget.cpp, 实现 updateProgressBar

void Widget::updateProgressBar() {
	int value = ui->progressBar->value();
	if (value >= 100) {
		timer->stop();
		return;
	}
	ui->progressBar->setValue(value + 1);
}

(5) 运行程序,可以看到进度条中的进度在快速增长

在这里插入图片描述

在实际开发中进度条的取值,往往是根据当前任务的实际进度来进行设置的。

比如需要读取一个很大的文件,就可以获取文件的总的大小,和当前读取完毕的大小,来设置进度条的比例。

由于上面我们介绍了 Qt 禁止在其他线程修改界面,因此进度条的更新往往也是需要搭配定时器来完成的。

通过定时器周期触发信号,主线程调用对应的 slot 函数,再在 slot 函数中对当前的任务进度进行计算,并更新进度条的界面效果。

代码示例:创建一个红色的进度条

不要忘了,QProgressBar 同样也是 QWidget 的子类,因此我们可以使用 styleSheet 通过样式来修改进度条的颜色。

(1) 在界面上创建一个进度条

在这里插入图片描述

(2) 在 Qt Designer 右侧的属性编辑器中,找到 QWidget 的 stylesheet 属性

编辑如下内容:

其中的 chunk 是选中进度条中的每个“块”,使用 QProgressBar::text 则可以选中文本

QProgressBar::chunk {background-color: #FF0000;}

同时把 QProcessBaralignment 属性设置为垂直水平居中

在这里插入图片描述

此处如果不设置 alignment,进度条中的数字会跑到左上角。这个怀疑是 Qt 本身的 bug,暂时只能先使用 alignment 来手动调整下。

(3) 执行程序,可以看到如下效果。我们就得到了一个红色的进度条

在这里插入图片描述

通过上述方式,也可以修改文字的颜色,字体大小等样式

Calendar Widget

QCalendarWidget 表示一个“日历",形如

在这里插入图片描述

核心属性

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

重要信号

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

代码示例:获取选中的日期

(1) 在界面上创建一个 QCalendarwidget 和一个label ,objectNamecalendarWidget ,label

在这里插入图片描述

(2) 给 QCalendarWidget 添加 slot 函数

void Widget::on_calendarWidget_selectionChanged()
{
	QDate date = ui->calendarWidget->selectedDate();
	qDebug() << date;
	ui->label->setText(date.toString());
}

(3) 执行程序,可以看到当选择不同的日期时,label 中的内容就会随之改变

在这里插入图片描述

  • 15
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值