前言
大家平时刷剧、看视频、看直播都能看到弹幕,记得之前《爱情公寓》中就有一集是弹幕互动剧,而且我平时看b站学习什么新东西的时候也喜欢开着弹幕,看不懂的可以看弹幕寻找思路,看的懂的也可以寻找其他人思路中的亮点。最近在计划开发哪些QT组件,又碰巧看到了某个视频中的弹幕,于是突发奇想的就想用QT开发一个弹幕组件,没做过之前就觉得挺厉害的,做起来发现其实并不复杂,整个过程也很顺利,先来看一下实现效果:
文字弹幕:
图片弹幕:(ps 录制的gif看上去好像有点卡顿,其实很流畅...)
弹幕如何展现?
首先弹幕有文字弹幕和图片弹幕,那么如何展现文字和图片是我们首先需要解决的问题,那么QT中有哪个控件既可以显示文字又可以显示图片呢,于是我想到了QLabel,所以我定了了一个BulletScreen类继承自QLabel。
解决了载体,接下来我们就需要思考弹幕有哪些属性需要展现了,当然图片弹幕就是一张图片嘛,这个我们就不说了,那么文字弹幕呢?然后我回想了一下看过的一些弹幕的样式总结了以下几点常规的样式:
- 文字颜色
- 文字大小
- 移动速度
- 字体
- 弹幕大小
当然这不是全部属性,只是一个弹幕的基本属性,我们就先来实现基本属性。当我要着手实现每个属性的设置功能时,又发现QLabel已经实现了设置文字颜色、字体和文字大小的函数,那么我们现在就只需要实现弹幕大小和移动速度即可。有朋友会说,QLabel也有设置大小的函数啊,没错,QLabel是有设置大小的函数,但是字幕的长短、字体、字号都有可能不一样,因此我们很难确定一个合适的大小,又不能统一设置一个很大的尺寸,这样也太不规范。那么我们如何根据弹幕中的文字来确定文字的大小呢?
设置弹幕大小
不用担心,QT也给我们造好了车轮,QFontMetrics类即可满足我们的需求,QFontMetrics构造时可以传入一个QFont类型的参数,根据这个参数和文字内容,就可以轻松的得到该段文字的长度和宽度。具体用法如下:
QFontMetrics metrics(font);
m_nWidth = metrics.width(this->text()) + 5; //5是余量
m_nHeight = metrics.height() + 5;//5是余量
设置弹幕移动和控制移动速度
还剩下最后一个移动速度了,既然是移动速度,肯定先要动起来啊,于是我想到了QT中的动画类
QPropertyAnimation,该类可以很好地实现弹幕那种横向的移动动画,该类具体用法如下:
QLabel *pLabel = new QLabel(this);
m_pAnimation = new QPropertyAnimation(pLabel, "pos", this);
m_pAnimation->setDuration(5000);//持续时间
m_pAnimation->setStartValue(QPoint(100, 100));//起始位置
m_pAnimation->setEndValue(QPoint(0, 100));//结束位置
m_pAnimation->setEasingCurve(QEasingCurve::Linear);
connect(m_pAnimation, SIGNAL(finished()), this, SLOT(yourslot())); //动画结束后需要执行的函数
m_pAnimation->start(QAbstractAnimation::DeleteWhenStopped);//开始运行动画
根据上面的代码我们可以看到动画中即可设置持续时间,于是我们的移动速度即可不用实现,完全可以使用动画的持续时间来代替,在移动同样距离的前提下,动画持续时间越短,速度就越快,动画持续时间越长,速度就越慢。
设置弹幕起止位置
弹幕可以移动以后,我们的弹幕该让哪移动到哪呢?查看了多个视频网站的弹幕发现,绝大多数的弹幕都是从屏幕右侧移动到屏幕左侧的,那么我们也就这么实现。
就这么实现?怎么实现?我不知道屏幕大小啊!难道还要用尺子量吗?
不用不用,QT也帮我们实现了获取屏幕大小的函数:
QDesktopWidget *pDesktop = QApplication::desktop(); //获取桌面大小
int nHeight = pDesktop->height();
int nWidth = pDesktop->width();
随机数
当我完成了弹幕的编码以后,我想试一下效果啊,然后就想创建100个弹幕刷一波,夸一下自己,但是我不能每个都设置一样的文本、颜色、大小、移动速度和起止位置啊,那100个和一个有什么区别,都重叠在一起了嘛。于是我想随机生成这些属性,既然要随机生成,我们肯定要使用随机数了,QT中随机数的用法如下:
qsrand(QTime(0,0,0).msecsTo(QTime::currentTime()));
int nRand = rand() % 10;//产生[0, 10)的随机数
至于怎么生成随机的文本、颜色、大小、移动速度和起止位置我就不再一一列举,大家可以直接看最后的源码。
图片弹幕怎么实现呢?
其实实现了文字弹幕,再要实现图片弹幕就很简单了,只需要把QLabel中的文字换成图片或动图就行了,QLabel设置动图显示的方法如下:
QLabel *pLabel = new QLabel(this);
QMovie *pMovie = new QMovie("G:/Qt code/J_Component/gif/1.gif");
pLabel->setMovie(pMovie);
pMovie->start();
源码
#ifndef BULLETSCREEN_H
#define BULLETSCREEN_H
#include <QLabel>
#include <QPropertyAnimation>
class BulletScreen : public QLabel
{
public:
BulletScreen();
void setGif(); //设置动图
void setColor(QColor qColor); //设置指定字体颜色
void setRandColor(); //设置随机字体颜色
void setFontAndResize(); //设置字体并自动调整弹幕大小
void setOpacity(int nOpacity); //设置背景透明度
void setRunTime(int nTime); //设置运行时间
void run(); //开始运动
QString getDefaultStr(); //获取一条默认弹幕
private:
QString m_strText; //弹幕文本
QColor m_qColor; //弹幕颜色
int m_nRunTime; //弹幕运动时间
QPropertyAnimation * m_pAnimation; //动画
int m_nWidth; //保存弹幕宽度
int m_nHeight; //保存弹幕高度
QStringList m_strList; //默认弹幕
};
#endif // BULLETSCREEN_H
#include "BulletScreen.h"
#include <QPalette>
#include <QTime>
#include <QDesktopWidget>
#include <QApplication>
#include <QMovie>
#include <QDebug>
BulletScreen::BulletScreen()
{
this->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint); //设置窗体无边框且在最顶端
this->setAttribute(Qt::WA_TranslucentBackground);//设置背景透明
this->setFocusPolicy(Qt::NoFocus);
this->setAttribute(Qt::WA_DeleteOnClose);
setColor(QColor(255, 0, 0)); //默认颜色为红色
m_nRunTime = 5000; //默认运行时间为5秒
m_strList << "66666666" << "还有这种操作???" << "优秀啊" << "这波你在第五层"
<< "欢迎来到Mikasoi的直播间" << "牛逼" << "厉害厉害" << "这个我也会啊"
<< "已关注" << "一键三连" << "Mikasoi";
}
//设置动图
void BulletScreen::setGif()
{
QMovie *pMovie = new QMovie("G:/Qt code/J_Component/gif/1.gif");
this->setMovie(pMovie);
pMovie->start();
}
//设置字体颜色
void BulletScreen::setColor(QColor qColor)
{
QPalette palette;
palette.setColor(QPalette::WindowText, qColor);
this->setPalette(palette);
}
//设置随机字体颜色
void BulletScreen::setRandColor()
{
int r = 0;
int g = 0;
int b = 0;
QString strColor = "";
QString strR = "";
QString strG = "";
QString strB = "";
qsrand(QTime(0,0,0).msecsTo(QTime::currentTime()));
r = rand() % 256;
g = rand() % 256;
b = rand() % 256;
strR.setNum(r, 16);
if (r < 16)
strR.prepend("0");
strG.setNum(g, 16);
if (g < 16)
strG.prepend("0");
strB.setNum(b, 16);
if (b < 16)
strB.prepend("0");
strColor.append("#" + strR + strG + strB);
setColor(QColor(strColor));
}
//设置字体并自动调整弹幕大小
void BulletScreen::setFontAndResize()
{
QFont font("Microsoft YaHei", 14, QFont::Bold, false);
this->setFont(font);
QFontMetrics metrics(font);
m_nWidth = metrics.width(this->text()) + 5;
m_nHeight = metrics.height() + 5;
this->setFixedWidth(m_nWidth); //弹幕设置固定的宽度
this->setFixedHeight(m_nHeight); //弹幕设置固定的高度
}
//设置背景透明度
void BulletScreen::setOpacity(int nOpacity)
{
this->setWindowOpacity(nOpacity);
}
//设置运行时间
void BulletScreen::setRunTime(int nTime)
{
m_nRunTime = nTime;
}
//开始运动
void BulletScreen::run()
{
show();
QDesktopWidget *pDesktop = QApplication::desktop(); //获取桌面大小
qsrand(QTime(0,0,0).msecsTo(QTime::currentTime()));
int nHeight = (rand() % (pDesktop->height() - m_nWidth - 10)) + 5;
int nWidth = pDesktop->width() + 5;
m_pAnimation = new QPropertyAnimation(this, "pos", this);
m_pAnimation->setDuration(m_nRunTime);
m_pAnimation->setStartValue(QPoint(nWidth+5, nHeight));
m_pAnimation->setEndValue(QPoint(-m_nWidth-5, nHeight));
m_pAnimation->setEasingCurve(QEasingCurve::Linear);
connect(m_pAnimation, SIGNAL(finished()), this, SLOT(deleteLater())); //动画结束后需要执行的函数
m_pAnimation->start(QAbstractAnimation::DeleteWhenStopped);
}
//获取一条默认弹幕
QString BulletScreen::getDefaultStr()
{
qsrand(QTime(0,0,0).msecsTo(QTime::currentTime()));
return m_strList.at(rand() % m_strList.count());
}
使用方法:
//显示弹幕
void showBulletScreen()
{
for (int i=0; i<100; i++)
{
BulletScreen *pBulletScreen = new BulletScreen;
if (显示文字) //说明文字,实际使用时删除改行
{
pBulletScreen->setText(pBulletScreen->getDefaultStr());
pBulletScreen->setFontAndResize();//要在设置文本之后调用,可以根据文本改变弹幕大小
pBulletScreen->setRandColor();
}
else //说明文字,实际使用时删除改行
pBulletScreen->setGif();
qsrand(QTime(0,0,0).msecsTo(QTime::currentTime()));
int nSec = (rand() % 10) + 5;
pBulletScreen->setRunTime(nSec * 1000);
pBulletScreen->run();
QCoreApplication::processEvents(QEventLoop::AllEvents, 100); //100毫秒发送一个弹幕,该方法可以防止事件循环阻塞
}
}
原创不易,还请各位点个关注三连支持一下,O(∩_∩)O哈哈~
本文暂时没有评论,来添加一个吧(●'◡'●)