写点什么

运用事件与定时器实现字幕滚动效果(Qt 开发)

作者:向阳逐梦
  • 2023-07-25
    四川
  • 本文字数:2071 字

    阅读完需:约 7 分钟

运用事件与定时器实现字幕滚动效果(Qt开发)

1、效果展示

我们经常能够在外面看到那种滚动字幕,那么就拿 qt 来做一个吧。

2、实现思路

实现一个窗口部件,这个窗口部件显示了一串文本标语,它会每 t 毫秒向左移动一个像素。如果窗口部件比文本宽,那么文本将会被多次重复,直到能够填满整个窗口部件的宽度为止。

3、滚动窗口部件

创建一个滚动窗口类,将其命名为 ticker。

3.1、成员变量

我们需要提供几个成员变量。

  • myText 用来表示要显示的文本内容。

  • offset 表示当前偏移量。

  • myTimerId 表示定时器的 ID 编号。

    QString myText;    int offset;    int myTimerId;
复制代码

3.2、事件重写

需要重新实现了 Ticker 中的 4 个事件处理器,分别为 paintEvent()、timerEvent()、showEvent()和 hideEvent();关于每个事件的职责后面再说。

    virtual void paintEvent(QPaintEvent* event) override; // 绘制事件    virtual void timerEvent(QTimerEvent* event) override; // 定时器事件    virtual void showEvent(QShowEvent* event) override; // 显示事件    virtual void hideEvent(QHideEvent* event) override; // 隐藏事件
复制代码

3.3、成员方法

还需要提供几个成员方法。关于每个方法的职责后面再说。

    void setText(const QString& newText);    QString text() const { return myText; }    QSize sizeHint() const;
复制代码

3.4、方法实现

1.构造函数

构造函数把 offset 变量初始化为 0。用来绘制文本的 x 坐标值就取自于这个 offset 值。

定时器的 ID 通常是非零的,所以可以使用 0 来表示定时器还没有启动。

Ticker::Ticker(QWidget *parent)    : QWidget{parent}{    offset = 0;    myTimerId = 0;}
复制代码

2.setText 函数

setText()函数用来设置要显示的文本。它调用 update()强制执行一个重绘操作,并且调用 updateGeometry()通知对 Ticker 窗口部件负责的布局管理器,提示该窗口部件的大小发生了变化。

void Ticker::setText(const QString &newText){    myText = newText;    update();    updateGeometry();}
复制代码

3.sizeHint 函数

sizeHint()函数返回文本所需的空间大小,并以此作为窗口部件的理想尺寸。QWidget::fontMetrics()函数返回一个 QFontMetrics 对象;可以用这个对象查询并获得与这个窗口部件字体相关的信息。

QSize Ticker::sizeHint() const{    return fontMetrics().size(0, text());}
复制代码

4.paintEvent 事件

paintEvent()函数使用 QPainter::drawText()绘制文本。它使用 fontMetrics()确定文本在水平方向上所需要的空间,并且在考虑 offset 值的同时,多次绘制文本,直到能够填充整个窗口部件的宽度为止。

void Ticker::paintEvent(QPaintEvent *event){    QPainter painter(this);    int textWidth = fontMetrics().width(text());    if(textWidth < 1)    {        return;    }    int x = -offset;    while(x < width())    {        painter.drawText(x, 0, textWidth, height(), Qt::AlignLeft | Qt::AlignVCenter, text());        x += textWidth;    }}
复制代码

5.timerEvent 定时器事件

系统每隔一定时间,都会调用一次 timerEvent()函数。

通过在 offset 上加 1 来模拟移动,从而形成文本宽度的连续滚动。然后,它使用 QWidget::scroll()把窗口部件的内容向左滚动一个像素。

如果这个定时器事件不是我们所关注的那个定时器,就可以把它传递给基类。

这里也可以调用 update()代替 scrol(),但使用 scroll()会更有效率,因为它只是简单地移动屏幕上已经存在的像素并且只对这个窗口部件的新显示区域(此时,只是一个 1 像素乘以宽度的像素条)产生一个绘制事件。

void Ticker::timerEvent(QTimerEvent *event){    if(event->timerId() == myTimerId)    {        ++offset;        if(offset >= fontMetrics().width(text()))        {            offset = 0;        }        scroll(-1, 0);    }    else    {        QWidget::timerEvent(event);    }}
复制代码

6.showEvent 显示事件

showEvent()函数用来启动个定时器。QObject::startTimer()调用会返回一个 ID 数字,用这个数字识别该定时器。QObject 支持多个独立的定时器,每一个都可以有自己的时间间隔。

在 startTimer()调用之后,大约每 30 毫秒 Qt 都会产生一个定时器事件。至于具体的时间精度,则取决于所在的操作系统。

我们也可以在 Ticker 的构造函数中完成 startTimer()的调用,但是只有在窗口部件实际可见的时候,才有必要保存由 Qt 产生的定时器事件的那些资源。让资源合理利用。

void Ticker::showEvent(QShowEvent *event){    Q_UNUSED(event);    myTimerId = startTimer(30);}
复制代码

7.hideEvent 隐藏事件

hideEvent()函数调用 QObject::killTimer()来停止该定时器。

void Ticker::hideEvent(QHideEvent *event){    killTimer(myTimerId);    myTimerId = 0;}
复制代码

定时器事件是一种低级事件,而且如果需要多个定时器时,保持对所有定时器 ID 的跟踪将会变得很麻烦。

在这种情况下,通常更为简单的方式是为每一个定时器分别创建一个 QTimer 对象。QTimer 会在每个时间间隔发射 timeout()信号。当然 QTimer 也提供了一个非常方便的接口,可用于单触发定时器(只触发一次的定时器)QTimer::singleShot(t, this, &Ticker::onTimer)。

发布于: 刚刚阅读数: 3
用户头像

向阳逐梦

关注

人生享受编程,编程造就人生! 2022-06-01 加入

某公司芯片测试工程师,嵌入式开发工程师,InfoQ签约作者,阿里云星级博主,华为云·云享专家。座右铭:向着太阳,追逐梦想!

评论

发布
暂无评论
运用事件与定时器实现字幕滚动效果(Qt开发)_向阳逐梦_InfoQ写作社区