大体思路:
借助于QTimer实现,以下为核心思路:
字幕显示:字幕(字符串,subtitle,长度为记为length)的长度不是固定的,但是显示字幕的容器(控件)的宽度是一定的,每个字符宽度(所占的像素)是一定的,也就是说每次刷新需要显示的字符个数是一定的,记为n,每刷新一次,就是从原始字幕(subtitle)中不同的位置截取n个字符进行显示;
字幕滚动:如果每次都从0的位置开始截取字幕的话,那么字符一直就是字幕的前n个字符,是无法看到滚动效果的,我们只需要每刷新一次,将开始截取的位置(index)+ 1,然后再截取随后的n个字符,并进行显示,即可达到字幕滚动的目的;
字幕循环:字幕现在可以显示和滚动了,但是滚动的时候,会出现一种情况,上一次的尾巴(t个字符)和下一次的头(n-t个字符)同时出现,这种情况该如何解决?小技巧:将字幕乘以2(即subtitle += subtitle),这样我们就可以截取到像上面所描述的那样的一个长度为n的字符串。如果开始截取的位置(index)等于length(index == length),则将截取位置归为0(index = 0),从而达到循环的目的;
其它:相邻两次字幕之间靠得很紧密,不好看,我们可以现在字幕后面加些空格(即subtitle += " "),然后再给他乘以2,这样相邻两次之间就会存在间隔,看起来比较舒服。
完成代码如下:
#include "TextTicker.h"
#include <QtWidgets/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TextTicker w;
w.showFullScreen();
return a.exec();
}
#pragma once
#include <QLabel>
#include <QTimer>
class TextTicker : public QLabel
{
Q_OBJECT
public:
TextTicker(QWidget *parent = 0);
~TextTicker();
protected:
void paintEvent(QPaintEvent *event);
void updateIndex();//刷新
private:
int m_charWidth;//每个字符所占的宽度(单位是像素)
int m_curIndex;//从哪里开始显示当前字符串
int m_length;//需要显示的字符串加了空格之后的字符串长度
int m_maxCount;//窗体能容纳的最大字符数,即显示字符的个数
QString m_showText;//需要显示的字符串(初始字符串--》加空格之后的字符串--》乘以2倍后的字符串)
};
#include "TextTicker.h"
TextTicker::TextTicker(QWidget *parent)
: QLabel(parent)
{
//设置背景颜色
this->setStyleSheet("background-color:red");
//设置字体大小
QFont font;
font.setPointSize(56);
font.setBold(true);
this->setFont(font);
//设置字体颜色
QPalette pa;
pa.setColor(QPalette::WindowText, Qt::yellow);
this->setPalette(pa);
//给需要被显示的字符串赋初值
m_showText = QStringLiteral("床前明月光,疑是地上霜,举头望明月,低头思故乡。床前明月光,疑是地上霜,举头望明月,低头思故乡。");
//字符串初值后边加空格(当前一遍的尾巴和头需要同时显示的时候,加上少量空格,使显示更好看)
m_showText += " ";
//获取添加空格后的需要显示的字符串的长度
m_length = m_showText.size();
//解决当前一遍的尾巴和头需要同时显示
m_showText += m_showText;//需要打印的字符串 * 2
//当前角码
m_curIndex = 0;
//每个字符的宽度
m_charWidth = fontMetrics().width("a");
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &TextTicker::updateIndex);
timer->start(200);
}
TextTicker::~TextTicker()
{
}
void TextTicker::paintEvent(QPaintEvent *event)
{
__super::paintEvent(event);
this->setText(m_showText.mid(m_curIndex, m_maxCount));
}
void TextTicker::updateIndex()
{
m_maxCount = width() / m_charWidth;
update();
m_curIndex++;
if (m_curIndex >= m_length)
m_curIndex = 0;
}
效果图如下所示:
参考文献:https://blog.csdn.net/u011417605/article/details/51211853