“This is the first day of my participation in the First Challenge 2022. For details: First Challenge 2022”

At the forefront of

Recently may be a small video obsession, especially the effect of animation subtitles, as a technical developer, of course, is to try, even if it is just a simple move is also possible ~

This is not, dry dry pick up my C++ language will try, fortunately the use of Qt framework, so is the use of MFC framework to write a small demo, really good difficult ah!

Let’s take a look at what I’ve achieved

The effect is simply that the text moves upwards, making the text larger or smaller as it moves.

So, let me explain how I did it!

Function implementation

In implementing this text movement effect, the following functions are used:

1: Timer

2: QLabel control self-drawing

Timer operation

There is a timer manipulation function provided in QWidget that we can implement by inheritance

virtual void timerEvent(QTimerEvent *event);
Copy the code

When using the timer of the QWidget, you do not need to use the new QTiemr method. Instead, you need to use an int value to record the number of the timer that is currently enabled and process it when the trigger time is reached.

Text offset implementation

First of all, before the implementation, to explain the main process is how it is!

1: defines the text movement timer

2: trigger once every second, each trigger needs to create a new control to display the content.

3: After triggered, the displayed text traversal mode will be shifted upward as a whole. During the offset process, the size of the text font will be changed randomly according to the random number.

4: font changes, resulting in changes in the width and height of the text. Use the new width and height to calculate the offset position.

Here, we can redraw the QLabel control, let’s say it’s called QCustomLabel, and its parent class is QLabel. So let me explain step by step how I implemented the timer offset

The first step

Define a container to store the text content to be displayed. In this case, we can use a simple vector, STD ::vector< STD ::string >m_vetContent;

The second step

Define a container to store the text controls you have already shown, using QVector to record, QVector<QCustomLabel*> m_vetControls;

Why are the first and second steps recorded in vector, but one in C++ and the other in Qt?

In fact, both step 1 and step 2 procedures can use QVector to record, but it is important to note that step 2 must use QVector.

Why is that? Since both vector and QVector stores first-in, first-out data, when we record a control pointer, the first control pointer we pull out should be the data inserted last. It’s easier to insert data from the front of a QVector, but the containers used for these two steps are slightly different. Did you get it?

The third step

After the timer is triggered, the control data that displays text is created temporarily and stored in the container m_vetControls in time to prevent memory leakage caused by not destroying pointer in time when destroying window.

QCustomLabel *lab = new QCustomLabel(this);
QSize size = lab->SetTextData(m_vetContent[m_nTimerTriggerNumber], 1);
int nTop = (height() - size.height()) / 2;
lab->setGeometry(DistanceLeft, nTop, size.width(), size.height());
lab->show();
m_vetControls.push_font(lab);
Copy the code

Using the QVector push_font() method, each time the stored data is displayed first, that is, the data is stored at a subscript 0.

The fourth step

After the data is stored, update all the displayed text control positions using the UpdateShowRectStyle() function

for (int i = 0; i < m_vetControls.size(); i++)
{
	QCustomLabel *lab = m_vetControls[i];
	QSize size = lab->UpdateZoomStyle(bFontZoom);
	QRectF rectF = lab->geometry();
	if (nTop == 0)
	{
		nTop = lab->geometry().top();
	}
	else
	{
		nTop = nTop - size.height();
	}
	lab->move(DistanceLeft, nTop);
}
this->update();
Copy the code

Loop through the entire storage control pointer data content, in the update position at the same time change the text zoom size (that is, change font size), get the latest change position, regain the width, height.

If the current height is 0, it indicates that the first data needs to be changed, and the offset position is directly the height of the control. If the current height is not 0, it indicates that it is a certain data in the offset process. Because the offset is upward, subtraction is required each time the offset height is calculated. If the offset is downward, the offset height is added each time.

Step 5

When all the contents are read and written, stop the timer operation

if (m_nTimerTriggerNumber == m_vetContent.size())
{
	killTimer(m_nTimerId);
	m_nTimerId = 0;
}
Copy the code

Here, the function of automatic text offset is realized, let’s talk about how to draw the QLabel control ~

Control since the draw

First of all, we need to define the self-drawing class of QLabel, here I give in addition to the simple framework, what function can be added directly in the future ~

Use.h

#pragma once

#include <QLabel>

class QCustomLabel : public QLabel
{
	Q_OBJECT

public:
	QCustomLabel(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags());
	~QCustomLabel();
};
Copy the code

.cpp use

#include "QCustomLabel.h"
QCustomLabel::QCustomLabel(QWidget *parent, Qt::WindowFlags f)
	: QLabel(parent, f)
{
}

QCustomLabel::~QCustomLabel()
{
}
Copy the code

If you want to achieve any function, you just need to expand on this basis.

There are two main points in self-painted QLabel

1: How to fix the text area according to the font size?

2: text flashing effect realization

Draw the QLable control based on these two points!

Feature 1:

The font size can be achieved using the random number qrand().

Usage:

QTime time = QTime::currentTime();
qsrand(time.msec() + time.second() * 1000);
int nFontSize = qrand() % 30 + 20;
Copy the code

The random numbers generated in this way guarantee uniqueness.

Set the QFont property based on the font size

QFont fontContent =this->font(); // Set: Font style: Microsoft YaHei FontContent.setFamily ("Microsoft YaHei"); // Set: font size: 22 fontContent.setpixelSize (nFontSize); This ->setFont(fontContent);Copy the code

Here we go!!

After setting the font style, we can get the height of the font at this time, but the overall width is not available and needs to be dynamically obtained.

QFontMetrics metrics(font()); int nheight = metrics.height(); // set the content and store the text content m_qsTextContent = QString::fromLocal8Bit(stext.c_str ()); setFixedHeight(nheight); this->setText(m_qsTextContent); this->adjustSize(); int nwidth = this->width(); QSize size(nwidth, nheight); M_nTimerId = startTimer(100); // startTimer m_nTimerId = startTimer(100); return size;Copy the code

Feature 2:

Text color gradient display.

This function is very simple, the core is to update the QColor value in real time, here I use a random number to make each generated color value is not the same

QFontMetrics metrics(font()); int x = 0; int y = (height() + metrics.ascent() - metrics.descent()) / 2; QColor color; for (int i = 0; i < m_qsTextContent.size(); I ++) {// set: hue (H), saturation (S), brightness (Y) int nIndex = (m_nStep + I) % 16; color.setHsv((15 - nIndex) * 16, 255, 191); painter->setPen(color); DrawText (x, y, QString(m_qsTextContent[I])); X += metrics.width(m_qsTextContent[I]); }Copy the code

conclusion

Here, the text movement effect has been achieved, the function is relatively simple, the only difficulty lies in the text style changes, the change of the region, as long as we understand the rule of change, location display is not a piece of cake?

I am a good citizen of China, focusing on C++ development program ape ~