QT-label滚动字幕
想通过QSS实现更多效果的请搜索QT自带帮助文档
Qt Style Sheets Examples
,使用样式表来定制程序界面
原理
让label字母滚动起来的原理很简单
所以就是这么一个过程:
1,判断字符串的像素宽度是否超过窗体宽度,超过则开启滚动 (主要是开启定时器)
2,定时器固定毫秒去修改位移值left
,然后调用绘图事件
3,绘图事件根据left值,生成一个矩形(默认左上角为0,0),然后drawText
根据矩形绘画文本。由于left一直在变动,于是矩形也在不停变动,生成的文本也在不停变动,就实现了滚动字幕。
***定时器用的是定时器事件,适合用来处理比较简单的重复任务,具体可以看这里
代码
根据上面的分解,整个流程就很清晰了,public
继承QLabel
,第一步判断可以先从setText开始
需要注意的是,必须要设置label的窗口最大值。因为是否滚动的关键是判断是否超出
this->with
,所以this->with
不能变动,一变动那触发滚动的阈值也变动了。
//在设置文本、缩放事件两次调用自适应的函数
void label_scroll::setText(const QString &txt)
{
if(Qt::mightBeRichText(txt))//判断是否为富文本 需要包含<QTextDocument>
flag = 0; //0不处理,直接用原本的绘画事件显示
else
flag = 1;
QLabel::setText(txt);
upateLabelRollingState();// 这个函数就是判断的核心
}
upateLabelRollingState();
// 这个函数就是判断是否开启滚动的关键核心,计算文本像素长度和开启定时器
//用来判断label文本是否需要滚动起来,是这块功能的核心
void label_scroll::upateLabelRollingState()
{
//获取文本大小,小于文本框长度,则无需滚动
QFont ft = font();// 获取当前字体的格式,里面有文本大小和文本像素大小
QFontMetrics fm(ft); // 以当前的字体格式为基础
#if QT_VERSION > QT_VERSION_CHECK(5,11,0)//根据官方文档说明,5.11后使用新的函数
text_wpixel = fm.horizontalAdvance(text() ); //以当前的字体格式为基础,计算字符串的像素宽度
#else
text_wpixel = fm.width(text() ); //同上,低于5.11使用此函数
#endif
// 长度超出本身label的像素大小,则开启滚动***关键判断
if( (text_wpixel > this->width() ) && flag == 1 )
{
left = 0; // 清空像素滚动量
#if QT_VERSION > QT_VERSION_CHECK(5,11,0)//根据官方文档说明,5.11后使用新的函数
blank = " ";//空格
blank_wp = fm.horizontalAdvance(blank );//空格的像素宽度,方便后面计算是否到达末尾
#else
blank = " ";//空格
blank_wp = fm.width(blank );//空格的像素宽度
#endif
//开启定时器,定时器定时改变滚动量left
timerId = startTimer(speedt);
}
else//关闭文本框滚动
{
flag = 0; //关闭
if(timerId >= 0){
killTimer(timerId);//关闭定时器
timerId = -1;
}
}
}
开启定时器之后,重载定时器事件timerEvent
,负责按时修改位移值left
//定时改位移量,到末尾时改为开头 负责修改当前像素位移值
void label_scroll::timerEvent(QTimerEvent *e)
{
if(e->timerId() == timerId && isVisible())
{
left += spixel;// 每次增加对应像素
if((left + 20) > (text_wpixel + blank_wp) )// 判断当前宽度是否超过字符串的总宽度,代表到末尾了
left = 1-( this->width() ); //重新添加,负数代表从最右边开始
//repaint();//立即触发一次刷新,不会产生冗余,但是耗性能
update();//不会立马刷新,有可能产生事件冗余,但是节省性能
//update和repaint的具体区别,请看QT文档说明
}
QLabel::timerEvent(e); // 如果没有进去上面那个滚动判断,则执行默认操作
}
重载绘图事件,根据timerEvent
修改的位移值left
绘制矩形,再根据矩形位置绘画字符串
//重绘事件,根据位移量left显示文本
void label_scroll::paintEvent(QPaintEvent *e)
{
if(flag == 0){ // 不处理,直接调用标签的默认函数,适配一般情况
QLabel::paintEvent(e);
return;
}
QPainter pen(this);
// 获取当前label的矩形大小
QRect rc = rect();
rc.setHeight(rc.height() );
rc.setWidth(rc.width() );
QString strText = blank + text();// 组合完整文本
//修改矩形x轴, 由于left在不断变大,setLeft就在不断变小,(0,0)在左上角,固左移
rc.setLeft(rc.left() - left);
pen.drawText(rc,Qt::AlignVCenter, strText);//根据给定的矩形坐标,绘制文本
}
完整源码 + 部件提升
.h
文件
#ifndef LABEL_SCROLL_H
#define LABEL_SCROLL_H
#include <QDebug>
#include <QLabel>
#include <QTimerEvent>
#include <QPaintEvent>
#include <QTextDocument> //判断富文本用的
#include <QPainter>
// 继承于标签,之后在qt设计师内右键选择"提升" 使得这个继承类控制对应需要滚动的标签
// https://www.kanzhun.com/jiaocheng/517505.html
class label_scroll :public QLabel
{
Q_OBJECT
public:
explicit label_scroll(QWidget *parent = nullptr);
~label_scroll();
//自适应函数,判断label文本是否需要滚动起来
void upateLabelRollingState();
public slots:
//定时改位移量,到末尾时改为开头 负责修改当前像素位移值left startTimer开始,killTimer结束
void timerEvent(QTimerEvent *e) Q_DECL_OVERRIDE;
//重绘事件,根据位移量left显示文本
void paintEvent(QPaintEvent *e) Q_DECL_OVERRIDE;
//在设置文本、缩放事件两次调用自适应的函数
void setText(const QString &txt);
//设置图片,主要把lt设回0,使其恢复正常的图片显示
void setPixmap(const QPixmap &pix);
//窗口变化事件
void resizeEvent(QResizeEvent *e) Q_DECL_OVERRIDE;
// 根据给定的数值,修改滚动速度 sp是一次滚动多少像素,st是多少秒触发一次滚动
void setspeed(int sp=10,int st=300);
private:
int timerId; //定时器id
int text_wpixel; //储存的当前label内字符串的像素水平长度
int speedt;// 多久触发一次滚动
int spixel;// 一次滚动多少像素
int left;// 标明当前的像素滚动量
QString blank;//空格
int blank_wp;//空格的像素宽度
int start_scroll;
uint8_t flag; //判断是否应该开启滚动 0否 1真
};
#endif // LABEL_SCROLL_H
.cpp
文件
#include "label_scroll.h"
label_scroll::label_scroll(QWidget *parent):QLabel(parent)
{
timerId = -1;// 定时器的ID
text_wpixel = 0; //文本的像素长度
speedt = 80;// 多久触发一次滚动
spixel = 10;// 一次滚动多少像素
//start_scroll = this->width();//保存了窗体最初的宽度,避免窗体变动就不滚动
flag = 0;//默认不处理
}
label_scroll::~label_scroll()
{
if(timerId >= 0)
killTimer(timerId);
}
//在设置文本、缩放事件两次调用自适应的函数
void label_scroll::setText(const QString &txt)
{
if(Qt::mightBeRichText(txt))//判断是否为富文本
flag = 0; //0不处理,直接用原本的绘画事件显示,当属于富文本时使用这个 1左到右 2上到下
else
flag = 1;
QLabel::setText(txt);
upateLabelRollingState();
}
//设置图片,主要把lt设回0,使其恢复正常的图片显示
void label_scroll::setPixmap(const QPixmap &pix)
{
flag=0;
QLabel::setPixmap(pix);
}
//窗口变化事件
void label_scroll::resizeEvent(QResizeEvent *e)
{
QLabel::resizeEvent(e);
upateLabelRollingState();
}
// 根据给定的数值,修改滚动速度 sp是一次滚动多少像素,st是多少秒触发一次滚动
void label_scroll::setspeed(int sp,int st)
{
spixel = sp;
speedt = st;
upateLabelRollingState(); // 刷新一次滚动量
}
//用来判断label文本是否需要滚动起来,是这块功能的核心
void label_scroll::upateLabelRollingState()
{
//获取文本大小,小于文本框长度,则无需滚动
QFont ft = font();// 获取当前字体的格式,里面有文本大小和文本像素大小
QFontMetrics fm(ft); // 以当前的字体格式为基础
#if QT_VERSION > QT_VERSION_CHECK(5,11,0)//根据官方文档说明,5.11后使用新的函数
text_wpixel = fm.horizontalAdvance(text() ); //以当前的字体格式为基础,计算字体的像素宽度
#else
text_wpixel = fm.width(text() ); //以当前的字体格式为基础,计算字体的像素宽度
#endif
if( (text_wpixel > this->width() ) && flag == 1 )// **长度或高度超出本身label的像素大小,则开启滚动***关键判断
{
left = 0; // 标志当前的像素滚动量
#if QT_VERSION > QT_VERSION_CHECK(5,11,0)//根据官方文档说明,5.11后使用新的函数
blank = " ";//空格
blank_wp = fm.horizontalAdvance(blank );//空格的像素宽度,方便后面计算是否到达末尾
#else
blank = " ";//空格
blank_wp = fm.width(blank );//空格的像素宽度
#endif
qDebug()<< "OK!";
//开启定时器,定时器定时触发滚动效果
timerId = startTimer(speedt);
}
else//关闭文本框滚动
{
qDebug()<< "no OK!";
flag = 0; //关闭
if(timerId >= 0){
killTimer(timerId);
timerId = -1;
}
}
}
//定时改位移量,到末尾时改为开头 负责修改当前像素位移值
void label_scroll::timerEvent(QTimerEvent *e)
{
if(e->timerId() == timerId && isVisible())
{
left += spixel;// (0,0)在左上角,每次增加对应像素
if((left + 20) > (text_wpixel + blank_wp) )// 表示到末尾了
left = 1-( this->width() ); //重新添加,负数代表从最右边开始
//repaint();//立即触发一次刷新,不会产生冗余,但是耗性能
update();//不会立马刷新,有可能产生事件冗余,但是节省性能
//update和repaint的区别,请看QT文档说明
}
QLabel::timerEvent(e);
}
//重绘事件,根据位移量left显示文本
void label_scroll::paintEvent(QPaintEvent *e)
{
if(flag == 0){ // 不处理,直接调用标签的默认函数
QLabel::paintEvent(e);
return;
}
QPainter pen(this);
// 获取当前label的矩形大小
QRect rc = rect();
rc.setHeight(rc.height() /*- 2*/);
rc.setWidth(rc.width() /*- 2*/);
QString strText = blank + text();
rc.setLeft(rc.left() - left); //修改矩形 x轴, 由于left在不断变大,setLeft就在不断变小,(0,0)在左上角,固左移
pen.drawText(rc,Qt::AlignVCenter, strText);//根据给定的矩形坐标,绘制标签
}
然后在UI设计师里面提升一下需要滚动的label部件
即可
echo 输出彩色字符串:
- 模板:
echo -e "\e[xx;xxm 你的内容 \e[0m"
-
解析:
-e
是echo的转义字符意思。
\e[xxm
xx是数字选项,选择字体属性、颜色、背景色用的,对顺序没有要求 -
各类数字选项:
背景色:
黑色背景:40
红色背景:41
绿色背景:42
黄色背景:43
蓝色背景:44
洋红背景:45
青色背景:46
白色背景:47
字体颜色:
黑色字体:30
红色字体:31
绿色字体:32
黄色字体:33
蓝色字体:34
洋红字体:35
青色字体:36
白色字体:37
属性
0: OFF
1: 高亮显示
3: 斜体
4: 下划线
5: 闪烁
7: 反色显示
8: 不可见
9: 删除线
echo -e "\e[9;32m hello \e[0m" #绿色字体、删除线的hello
常见图片格式的文件标识符
下面是一些常见图片格式,开头固定文件头的标识符,可以用来区分是什么图片:
- BMP:
0x42 0x4D
,即ASCII字符 “BM” 的16进制表示。 - PNG:
0x89 0x50 0x4E 0x47 0x0D 0x0A 0x1A 0x0A
即ASCII字符 “PNG\r\n\x1a\n” 的16进制表示,用于标识PNG文件的开始。 - JPEG (JPG):
0xFF 0xD8
,文件结束标记是0xFF 0xD9
。 - GIF: 87a版本
0x47 0x49 0x46 0x38 0x37 0x61
或 89a版本0x47 0x49 0x46 0x38 0x39 0x61
,这取决于GIF版本(87a或89a)。这些字节是ASCII字符 “GIF87a” 或 “GIF89a” 的16进制表示。 - TIFF: 通常是
0x49 0x49
或0x4D 0x4D
,分别对应于Intel和Motorola字节序的TIFF文件。这些字节是ASCII字符 “II” 或 “MM” 的16进制表示。 - ICO:
0x00 0x00 0x01 0x00