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

Qt文字滚动效果学习

Qt文字滚动效果学习

1. 项目概述

本项目实现了一个简单的文字横向滚动效果,类似于LED显示屏上的跑马灯效果。主要功能包括:

  • 使用QPainter在窗口上绘制文字
  • 使用QTimer实现定时更新,产生动画效果
  • 计算文字宽度,实现文字从右向左循环滚动
  • 自定义文字样式(颜色、大小等)

2. 项目结构

46/
├── 46.pro           # 项目文件
├── main.cpp         # 主函数入口
├── widget.h         # 主窗口头文件
├── widget.cpp       # 主窗口实现
└── widget.ui        # 主窗口界面设计

3. 类设计

3.1 Widget类定义 (widget.h)

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTimer>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();// 重写绘图事件,用于绘制滚动文字void paintEvent(QPaintEvent *event) override;private:Ui::Widget *ui;QFont font;           // 文字字体int offset;           // 文字偏移量QTimer *timer;        // 定时器,用于更新偏移量QString textContent;  // 显示的文字内容int textContentWidth; // 文字内容的宽度private slots:// 定时器超时处理函数void onTimerTimeOut();
};
#endif // WIDGET_H

3.2 Widget类实现 (widget.cpp)

#include "widget.h"
#include "ui_widget.h"
#include <QPainter>#include <QDebug>
#include <QFontMetrics>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget), offset(0)                          // 初始偏移量为0, textContent("正点原子Linux开发板")  // 设置显示的文字内容
{ui->setupUi(this);// 创建定时器timer = new QTimer(this);// 设置定时间隔为20毫秒timer->start(20);// 设置字体大小为50像素font.setPixelSize(50);// 计算文字宽度QFontMetrics fontMetrics(font);textContentWidth = fontMetrics.width(textContent);// 连接定时器的timeout信号到onTimerTimeOut槽函数connect(timer, SIGNAL(timeout()), this, SLOT(onTimerTimeOut()));
}Widget::~Widget()
{delete ui;
}void Widget::paintEvent(QPaintEvent *event)
{Q_UNUSED(event)  // 未使用的参数,避免编译警告// 创建QPainter对象QPainter painter(this);// 创建并设置画笔QPen pen;pen.setColor(QColor(Qt::red));  // 设置文字颜色为红色// 设置画笔painter.setPen(pen);// 设置字体painter.setFont(font);// 获取窗口矩形区域QRectF rectF = this->rect();// 设置文字绘制的起始位置(从窗口右侧减去当前偏移量开始)rectF.setLeft(this->rect().width() - offset);// 输出当前矩形宽度(调试用)qDebug() << rectF.width() << endl;// 绘制文字,垂直居中对齐painter.drawText(rectF, Qt::AlignVCenter, textContent);
}void Widget::onTimerTimeOut()
{// 更新偏移量if (offset < this->width() + textContentWidth)offset += 1;  // 每次增加1个像素elseoffset = 0;   // 当文字完全移出窗口后,重置偏移量// 更新界面,触发重绘this->update();
}

3.3 主函数 (main.cpp)

#include "widget.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}

3.4 界面设计 (widget.ui)

界面设计非常简单,只包含一个基本的QWidget窗口,大小设置为400x100像素。

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"><class>Widget</class><widget class="QWidget" name="Widget"><property name="geometry"><rect><x>0</x><y>0</y><width>400</width><height>100</height></rect></property><property name="windowTitle"><string>Widget</string></property></widget><resources/><connections/>
</ui>

4. 关键技术详解

4.1 文字宽度计算

在实现文字滚动效果时,需要知道文字的宽度,以便确定何时重置偏移量。Qt提供了QFontMetrics类来计算文字的尺寸。

// 创建字体
QFont font;
font.setPixelSize(50);  // 设置字体大小// 使用QFontMetrics计算文字宽度
QFontMetrics fontMetrics(font);
int textWidth = fontMetrics.width("正点原子Linux开发板");

QFontMetrics类提供了多种方法来获取文字的尺寸信息:

  • width(const QString &text): 获取文字的宽度
  • height(): 获取字体的高度
  • boundingRect(const QString &text): 获取文字的边界矩形
  • lineSpacing(): 获取行间距

4.2 定时器使用

使用QTimer可以实现定时触发某个操作,在本例中用于定时更新文字的偏移量。

// 创建定时器
QTimer *timer = new QTimer(this);// 设置定时间隔(毫秒)
timer->start(20);  // 每20毫秒触发一次// 连接定时器的timeout信号到槽函数
connect(timer, SIGNAL(timeout()), this, SLOT(onTimerTimeOut()));// 定时器槽函数
void Widget::onTimerTimeOut()
{// 更新偏移量offset += 1;if (offset > maxOffset)offset = 0;// 触发重绘update();
}

定时器的常用方法:

  • start(int msec): 启动定时器,设置间隔为msec毫秒
  • stop(): 停止定时器
  • setInterval(int msec): 设置定时间隔
  • isActive(): 检查定时器是否处于活动状态

4.3 自定义绘图

在Qt中,自定义绘图通常通过重写QWidget的paintEvent方法实现。

void Widget::paintEvent(QPaintEvent *event)
{Q_UNUSED(event);  // 未使用的参数,避免编译警告// 创建QPainter对象QPainter painter(this);// 设置绘图属性painter.setRenderHint(QPainter::Antialiasing);  // 抗锯齿painter.setPen(QPen(Qt::red));                  // 设置画笔颜色painter.setFont(QFont("Arial", 20));            // 设置字体// 绘制文字painter.drawText(x, y, "Hello, Qt!");
}

绘图的关键点:

  1. 创建QPainter对象,并指定绘图设备(通常是this,即当前窗口)
  2. 设置绘图属性(画笔、画刷、字体等)
  3. 调用绘图函数(如drawText、drawRect等)
  4. QPainter对象会在方法结束时自动销毁,结束绘图

4.4 文字滚动算法

本例中实现的是从右向左的文字滚动效果,核心算法如下:

  1. 初始时,文字位于窗口右侧外部(不可见)
  2. 通过定时器,逐渐减小文字的X坐标,使其向左移动
  3. 当文字完全移出窗口左侧时,重置位置到窗口右侧,形成循环滚动效果
// 设置文字绘制的起始位置
rectF.setLeft(this->rect().width() - offset);// 更新偏移量
if (offset < this->width() + textContentWidth)offset += 1;  // 每次增加1个像素
elseoffset = 0;   // 当文字完全移出窗口后,重置偏移量

5. 扩展功能示例

5.1 调整滚动速度

可以通过修改定时器的间隔和每次更新的偏移量来调整滚动速度。

// 在构造函数中
// 慢速滚动
timer->start(50);  // 50毫秒更新一次
// 或者
// 快速滚动
timer->start(10);  // 10毫秒更新一次// 在onTimerTimeOut方法中
// 大步长滚动
offset += 2;  // 每次增加2个像素
// 或者
// 小步长滚动
offset += 0.5;  // 每次增加0.5个像素(需要将offset改为float类型)

5.2 添加暂停/继续功能

可以添加按钮或键盘事件来控制滚动的暂停和继续。

// 在widget.h中添加
private:bool isPaused;  // 是否暂停public slots:void togglePause();  // 切换暂停/继续状态// 在widget.cpp中实现
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget), offset(0), textContent("正点原子Linux开发板"), isPaused(false)  // 初始不暂停
{// ... 其他初始化代码 ...
}void Widget::togglePause()
{isPaused = !isPaused;if (isPaused)timer->stop();  // 暂停定时器elsetimer->start(20);  // 继续定时器
}void Widget::onTimerTimeOut()
{if (!isPaused) {  // 只有在非暂停状态才更新if (offset < this->width() + textContentWidth)offset += 1;elseoffset = 0;this->update();}
}// 添加键盘事件处理
void Widget::keyPressEvent(QKeyEvent *event)
{if (event->key() == Qt::Key_Space) {togglePause();  // 空格键切换暂停/继续}
}

5.3 多行文字滚动

可以扩展为支持多行文字同时滚动。

// 在widget.h中修改
private:QList<QString> textLines;       // 多行文字QList<int> textWidths;          // 每行文字的宽度QList<int> offsets;             // 每行文字的偏移量QList<QColor> textColors;       // 每行文字的颜色// 在widget.cpp中实现
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 初始化多行文字textLines << "第一行:正点原子Linux开发板"<< "第二行:ALIENTEK开发板"<< "第三行:嵌入式开发学习平台";// 初始化颜色textColors << Qt::red << Qt::blue << Qt::green;// 初始化字体font.setPixelSize(30);// 计算每行文字宽度QFontMetrics fontMetrics(font);for (const QString &line : textLines) {textWidths.append(fontMetrics.width(line));offsets.append(0);  // 初始偏移量都为0}// 设置定时器timer = new QTimer(this);timer->start(20);connect(timer, SIGNAL(timeout()), this, SLOT(onTimerTimeOut()));
}void Widget::paintEvent(QPaintEvent *event)
{Q_UNUSED(event);QPainter painter(this);painter.setFont(font);// 计算每行文字的高度int lineHeight = height() / textLines.size();// 绘制每行文字for (int i = 0; i < textLines.size(); ++i) {QRectF rectF = QRectF(0, i * lineHeight, width(), lineHeight);rectF.setLeft(width() - offsets[i]);painter.setPen(textColors[i]);painter.drawText(rectF, Qt::AlignVCenter, textLines[i]);}
}void Widget::onTimerTimeOut()
{bool needUpdate = false;// 更新每行文字的偏移量for (int i = 0; i < textLines.size(); ++i) {if (offsets[i] < width() + textWidths[i]) {offsets[i] += 1 + i;  // 不同行可以有不同的速度needUpdate = true;} else {offsets[i] = 0;needUpdate = true;}}if (needUpdate) {update();}
}

5.4 添加渐变色文字

可以使用QLinearGradient为文字添加渐变色效果。

void Widget::paintEvent(QPaintEvent *event)
{Q_UNUSED(event);QPainter painter(this);painter.setFont(font);painter.setRenderHint(QPainter::Antialiasing);// 创建线性渐变QLinearGradient gradient(0, 0, 0, height());gradient.setColorAt(0, Qt::red);gradient.setColorAt(0.5, Qt::yellow);gradient.setColorAt(1, Qt::blue);// 设置渐变画笔painter.setPen(QPen(QBrush(gradient), 1));// 绘制文字QRectF rectF = this->rect();rectF.setLeft(this->rect().width() - offset);painter.drawText(rectF, Qt::AlignVCenter, textContent);
}
http://www.xdnf.cn/news/1479583.html

相关文章:

  • MySQL 高可用方案之 MHA 架构搭建与实践
  • 常用配置文件
  • 去中心化投票系统开发教程 第三章:智能合约设计与开发
  • [网络入侵AI检测] docs | 任务二分类与多分类
  • 算法题-链表03
  • react native 出现 FATAL EXCEPTION: OkHttp Dispatcher
  • LeetCode 2841.几乎唯一子数组的最大和
  • AI智能体架构全流程全解析
  • [光学原理与应用-432]:非线性光学 - 既然光也是电磁波,为什么不能直接通过电生成特定频率的光波?
  • 打造一款高稳定、低延迟、跨平台RTSP播放器的技术实践
  • 基于FPGA的电梯控制系统设计(论文+源码)
  • 动态内存分配
  • DeepSeek辅助在64位Linux中编译运行32位的asm-xml-1.4程序
  • Day22_【机器学习—集成学习(1)—基本思想、分类】
  • leetcode 215 数组中的第K个最大元素
  • Jupyter Notebook与cpolar:构建跨地域数据科学协作平台
  • 正态分布 - 计算 Z-Score 的 无偏估计
  • 计算机主板上的那颗纽扣电池的作用是什么?
  • OSG中TerrainManipulator(地形适配操纵器)
  • STM32CubeProgrammer软件安装
  • Qt 中的 Q_OBJECT 宏详解 —— 从源码到底层机制的全面剖析
  • 2023年ASOC SCI2区TOP,改进元启发式算法+考虑医护人员技能水平的家庭健康护理路径规划,深度解析+性能实测
  • 【Redis】缓存的穿透、击穿和雪崩
  • 一个正常的 CSDN 博客账号,需要做哪些基础准备?
  • C++基础知识
  • 《sklearn机器学习——聚类性能指标》Silhouette 系数
  • 用 Hashcat 提取哈希值并找回遗忘的密码:一次实用的尝试
  • 【Big Data】Apache Kafka 分布式流处理平台的实时处理实践与洞察
  • uniapp基础组件概述
  • SPI 三剑客:Java、Spring、Dubbo SPI 深度解析与实践​