前言
不知道大家有没有发现今天的文章有什么不一样,哈哈,我自己胡拼乱凑弄了一个logo,好不好看就先不说了,最起码萌萌哒...
当然这不是今天的重点,在做logo的时候,我原本想让文字动起来的,奈何技术有限也没做出很好的效果,最终还是使用了静态的文本。因为最近在做QT组件吗,如是就产生了制作一个抖动文字控件的想法。不过在搜集相关资料的时候发现原来QT提供的示例中就有抖动文字,且实现方法也比较简单,看了源码以后觉得可以稍微改造一下,就又可以实现类似与LED广告牌上的滚动文字。本篇文章就跟大家分享一下抖动文字即滚动文字的实现方法。先来看一下实现效果:
抖动文字:
滚动文字:(有些类似于上篇文章中的弹幕效果)
抖动文字实现方法
首先要实现抖动文字,当然要有文字,因此需要先实现一个设置文本的接口:
void setText(const QString &newText)
{
m_strText = newText;
}
然后要实现文字的抖动,就要重写重绘函数paintEvent,那么我们该怎么实现文字的运动呢,QT示例中使用了一种简单好用的方法,即定义了一个静态数组:
static constexpr int sineTable[16] = { 0, 38, 71, 92, 100, 92, 71, 38, 0, -38, -71, -92, -100, -92, -71, -38 };
然后利用定时器,以数组中的数字为增量,周期的改变每个字符的纵坐标。注意数组中的数字呈正弦曲线样式分布,这样取数的目的是保证一次循环结束以后,字符能够又回到最初的起点,呆呆的站在镜子前,笨拙系上红色领带的结......
至于文字的基础摆放位置,示例中也进行如下设置:
int x = (width() - metrics.width(m_strText)/*metrics.horizontalAdvance(m_strText)*/) / 2;
int y = (height() + metrics.ascent() - metrics.descent()) / 2;
基础横坐标由窗口宽度和字符串总宽度算得,注意我将示例中的实现方法metrics.horizontalAdvance(m_strText)改为了metrics.width(m_strText),这样做的目的是因为有些版本的QT并不支持metrics.horizontalAdvance函数,使用metrics.width函数的效果是一样的。基础高度由窗口高度和文字高度算得,其中:
ascent是指从一个字的基线(baseline)到最顶部的距离
descent是指一个 字的基线到最底部的距离g文字实现方法
滚动文字实现方法
由抖动文字改为滚动文字其实很简单,保持纵坐标不变,只需要将横坐标的变换改为水平移动,并控制移动的距离和复位时机,保证文字能够完整的滚动一周并能正确复位即可。
m_nX -= 5;
if (m_nX < (0 - metrics.width(m_strText)))
m_nX = width();
源码
#ifndef WIGGLYTEXT_H
#define WIGGLYTEXT_H
#include
#include
//抖动的文字
class WigglyText : public QWidget
{
Q_OBJECT
public:
explicit WigglyText(QWidget *parent = 0);
public slots:
void setText(const QString &newText) { m_strText = newText; }
void setMode(int nMode);
protected:
void paintEvent(QPaintEvent *event) override;
void timerEvent(QTimerEvent *event) override;
private:
QBasicTimer m_qTimer;
QString m_strText;
int m_nMode;
int m_nStep;
int m_nX;
int m_nY;
};
#endif // WIGGLYTEXT_H
#include "WigglyText.h"
#include
#include
#include
WigglyText::WigglyText(QWidget *parent) : QWidget(parent)
{
resize(250, 80);
setAttribute(Qt::WA_DeleteOnClose);
setWindowTitle("抖动和滚动文字");
setBackgroundRole(QPalette::Midlight);
setAutoFillBackground(true);
QFont newFont = font();
newFont.setPointSize(newFont.pointSize() + 20);
setFont(newFont);
m_qTimer.start(60, this);
m_nMode = 0; //默认为抖动
m_nX = width();
QFontMetrics metrics(font());
m_nY = (height() + metrics.ascent() - metrics.descent()) / 2;
}
//设置运动方法,0为抖动,1为滚动
void WigglyText::setMode(int nMode)
{
m_nMode = nMode;
}
void WigglyText::paintEvent(QPaintEvent *event)
{
QFontMetrics metrics(font());
QPainter painter(this);
if (m_nMode == 0)
{
static constexpr int sineTable[16] = { 0, 38, 71, 92, 100, 92, 71, 38, 0, -38, -71, -92, -100, -92, -71, -38 };
int x = (width() - metrics.width(m_strText)/*metrics.horizontalAdvance(m_strText)*/) / 2;
int y = (height() + metrics.ascent() - metrics.descent()) / 2;
QColor color;
for (int i = 0; i < m_strText.size(); i++)
{
int index = (m_nStep + i) % 16;
color.setHsv((15 - index) * 16, 255, 191);
painter.setPen(color);
painter.drawText(x, y - ((sineTable[index] * metrics.height()) / 400), QString(m_strText[i]));
x += metrics.width(m_strText[i]);/*metrics.horizontalAdvance(m_strText[i])*/;
}
}
else
{
painter.setPen(QColor(255, 0, 0));
painter.drawText(m_nX, m_nY, m_strText);
m_nX -= 5;
if (m_nX < (0 - metrics.width(m_strText)))
m_nX = width();
}
}
void WigglyText::timerEvent(QTimerEvent *event)
{
if (event->timerId() == m_qTimer.timerId())
{
++m_nStep;
update();
}
else
QWidget::timerEvent(event);
}
使用方法:
void showWigglyText()
{
WigglyText *pWigglyText = new WigglyText;
pWigglyText->setText("Mikasoi");
pWigglyText->setMode(1);//设置为滚动
pWigglyText->show();
}