Qt development to achieve subtitle scrolling effect

1. Effect display

We can often see that kind of rolling subtitles outside, so let's use qt to make one.

2. Implement ideas

Implement a widget that displays a string of text banners that moves one pixel to the left every t milliseconds. If the widget is wider than the text, the text will be repeated multiple times until it fills the entire width of the widget.

3. Scroll widget

Create a rolling window class and name it ticker.

3.1. Member variables

We need to provide several member variables.

  • myText is used to represent the text content to be displayed.
  • offset represents the current offset.
  • myTimerId represents the ID number of the timer.
    QString myText;
    int offset;
    int myTimerId;

3.2. Event rewriting

It is necessary to reimplement the four event handlers in Ticker, namely paintEvent(), timerEvent(), showEvent() and hideEvent(); the responsibilities of each event will be discussed later.

    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. Member methods

Several member methods also need to be provided. The responsibilities of each method will be discussed later.

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

3.4. Method implementation

1. Constructor

The constructor initializes the offset variable to 0. The x coordinate value used to draw the text is taken from this offset value.

The timer ID is usually non-zero, so you can use 0 to indicate that the timer has not started yet.

Ticker::Ticker(QWidget *parent)
    : QWidget{parent}
{
    offset = 0;
    myTimerId = 0;
}

2.setText function

The setText() function is used to set the text to be displayed. It calls update() to force a redraw operation, and calls updateGeometry() to notify the layout manager responsible for the Ticker widget that the size of the widget has changed.

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

3.sizeHint function

The sizeHint() function returns the amount of space required for the text and uses this as the ideal size for the widget. The QWidget::fontMetrics() function returns a QFontMetrics object; you can use this object to query and obtain information related to the font of this widget.

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

4.paintEvent event

The paintEvent() function uses QPainter::drawText() to draw text. It uses fontMetrics() to determine how much space the text requires horizontally, and, taking into account offset values, draws the text multiple times until it fills the entire width of the widget.

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 timer event

The system calls the timerEvent() function at regular intervals.

Movement is simulated by adding 1 to the offset, resulting in continuous scrolling of the width of the text. Then, it uses QWidget::scroll() to scroll the widget's content one pixel to the left.

If this timer event is not the timer we are interested in, we can pass it to the base class.

You can also call update() here instead of scroll(), but using scroll() will be more efficient, because it simply moves the pixels that already exist on the screen and only changes the new display area of ​​this widget (at this time, it is just a 1 pixel times the width of the pixel bar) generates a draw event.

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 displays events

The showEvent() function is used to start a timer. The QObject::startTimer() call will return an ID number, use this number to identify the timer. QObject supports multiple independent timers, each of which can have its own time interval.

After the startTimer() call, Qt will generate a timer event approximately every 30 milliseconds. As for the specific time accuracy, it depends on the operating system.

We can also complete the call to startTimer() in the Ticker constructor, but it is necessary to save those resources for the timer events generated by Qt only when the widget is actually visible. Make reasonable use of resources.

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

7.hideEvent hidden event

The hideEvent() function calls QObject::killTimer() to stop the timer.

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

Timer events are low-level events, and if multiple timers are needed, keeping track of all timer IDs can become cumbersome.

In this case, it is usually easier to create a QTimer object for each timer. QTimer emits the timeout() signal at each time interval. Of course, QTimer also provides a very convenient interface that can be used for single-shot timers (timers that only trigger once) QTimer::singleShot(t, this, &Ticker::onTimer).

Benefits of this article, receive free Qt development learning materials package and technical videos, including (Qt practical project video tutorial + code, C++ Language foundation, C++ design pattern, introduction to Qt programming, QT signal and slot mechanism, QT interface development-image drawing, QT network, QT database programming, QT project practice, QSS, OpenCV, Quick module, interview questions, etc.) ↓↓↓ ↓↓↓See below↓↓Click at the bottom of the article to receive the fee↓↓

Guess you like

Origin blog.csdn.net/hw5230/article/details/134675965