基于Qt的音乐播放器制作
使用浏览器自带工具抓包歌曲资源
开发人员工具抓包
点击浏览器右上角的 “…” 快捷键(Alt + F);
点击其中的“更多工具” ➡ “开发人员工具”;
打开开发人员工具出现以下界面:
选中网络 ➡ 禁用缓存,并点击清除清空网络活动记录;
打开一个音乐搜索引擎(如酷狗、网易音乐、小众音乐平台网址);
ps:大平台网络加密严密且收费歌曲偏多,抓包失败可能性偏大
这里我选用的是一个小众搜索引擎:
https://l-by.cn/yinyue/
打开音乐搜索引擎和开发人员工具,搜索引擎搜索一个歌手,并点击播放该歌手的一首歌(若已经在搜索后的歌曲界面则刷新页面);
ps:每次搜索播放歌曲或刷新时要先清除开发人员工具,以便清理多余的网络活动记录更好的找到音乐资源包
如上图所示抓包到这三个 xhr 类型的文件,分别点击文件并选择标头、负载和预览查看
以url包为例,包头显示的请求方式为POST,连接类型为application/x-www-form-urlencoded; charset=UTF-8,负载中可查看源(types=url&id=1978137630&source=netease)为音乐播放资源包(url),id(每一个id对应一首歌的播放源以及歌词源)以及 source (音乐播放来源,netease为网易云);预览中则为对应歌曲的mp3格式播放网址;
ps:url(歌曲播放)与lyric(歌曲歌词)的id号相同,pic(歌曲专辑图)的id号与前两者不同
接口测试
为了更加直观的查看一首歌的各类信息,便于搜索查找想听的歌曲,我们对刚刚抓到的网络端口进行接口测试;
使用网站:https://getman.cn/
采用POST请求方式连接音乐搜索网址(网址末尾需加上/api.php),填入相应的包头连接类型,body填入查看源的数据:
body中填入
types=search&count=30&source=netease&pages=1&name=“许嵩”
点击√便可以查看歌单信息列表:
body中填入
types=url&id=1978137630&source=netease
便可以查看单首歌的播放网址、歌词和歌曲专辑:
查询 lyric 和 pic 的方式相同。
程序编写整体思路
制作流程
先创建一个 Qt Widgets Application(桌面Qt应用):MusicInterface
在 main.cpp 文件中调用打开 MusicInterface类(ui界面),由该类关联三个新创建的类: HttpHandle(http协议网络通信、数据解析类)、MusicPlayer (音乐播放、歌词解析类)、GraphicsView(专辑图片处理类);
其中的 GraphicsView 类又关联了两个新创建的类:DiskItem(光盘图元旋转类)、NeedleItem(唱针图元摆动类),最后创建一个新类:AboutInterface(关于界面窗口)依附于主窗口界面类中;
在主窗口界面上添加控件来满足音乐播放器相应的功能:
graphicsView 插入专辑图、特效动图
pushButton_playOrder 随机、顺序播放
pushButton_play 播放暂停
pushButton_lastSong 上一首
pushButton_nextSong 下一首
verticalSlider_volume 音量调节
horizontalSlider_progressBar 播放进度条
label_startTime 开始时间
label_endTime 结束时间
lineEdit_search 搜索歌单
tabWidget 在线音乐、本地音乐存放容器
tableWidget_musicList 存放歌曲列表
textEdit_lyric 存放歌曲歌词
思维框架图
使用Qt对歌曲资源包解析(http协议)
POST连接音源网址
创建一个HPPT协议连接的类继承QObject:生成 HttpHandle.h 和 HttpHandle.cpp 文件
在该类中声明并实现一个公有的歌源连接函数:
QByteArray HttpHandle::postSearch(const QString &body)
{
QNetworkRequest networkRequest(QUrl("https://l-by.cn/yinyue/api.php"));
networkRequest.setRawHeader(QByteArray("content-type"), QByteArray("application/x-www-form-urlencoded; charset=UTF-8"));
QEventLoop eventLoop;
QNetworkReply *networkReply = networkAccessManager->post(networkRequest, body.toUtf8());
connect(networkReply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
return networkReply->readAll();
}
该函数需要绑定音乐搜索引擎网址以及包头里的连接类型,然后采用POST的方式连接接口;
使用QtJSON解析歌单数据
在HttpHandle类中声明并实现一个解析歌单数据函数:
void HttpHandle::searchMusicList(const QString &searchData)
{
QString body = QString("types=search&count=30&source=netease&pages=1&name=%1").arg(searchData);//30是一面歌曲数,1是页面数,可以用%2添加参数进行翻页,后面加上.arg(int)
QByteArray musicData = postSearch(body);
QJsonParseError error;
QJsonDocument JsonDocument = QJsonDocument::fromJson(musicData, &error);
if (error.error != QJsonParseError::NoError) {
qDebug() << "解析音乐列表JSON数据失败!错误码:" << error.errorString();
return;
}
QJsonArray musicInfoArray = JsonDocument.array();
for (int i = 0; i < musicInfoArray.size(); ++i) {
QJsonObject musicObject = musicInfoArray[i].toObject();
QStringList musicInfo;
QString id = QString::number(musicObject["id"].toInt());
QString picId = musicObject["pic_id"].toString();
QString name = musicObject["name"].toString();
QJsonArray artistArray = musicObject["artist"].toArray();
QString artist;
for (int j = 0; j < artistArray.size(); ++j) {
artist = artist + artistArray[j].toString() + ',';
}
artist.chop(1); //删除最后一个多余的','
QString album = musicObject["album"].toString();
musicInfo << id << picId << name << artist << album;
emit signalShowMusicInfoList(musicInfo); }
}
获取歌单数据顺序分别为:歌曲歌词id,专辑图片id,歌曲名,歌手名,专辑名;
将该函数解析出来的数据通过信号发送到MusicInterface的槽函数中;
在HttpHandle中声明信号:
signals:
void signalShowMusicInfoList(QStringList musicInfo);
在MusicInterface类中创建一个HttpHandle类的对象,声明接受信号的槽并实现并在构造函数中完成信号与槽的连接:
private slots:
void slotShowMusicInfoList(QStringList musicInfo);
private:
Ui::MusicInterface *ui; //播放器界面对象
HttpHandle *httpHandle;
MusicInterface::MusicInterface(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MusicInterface),
httpHandle(new HttpHandle(this))
{
ui->setupUi(this);
setWindowIcon(QIcon("(该音乐播放器图标的地址)"));
connect(httpHandle, SIGNAL(signalShowMusicInfoList(QStringList)), this, SLOT(slotShowMusicInfoList(QStringList)));
}
解析音乐源网址JSON数据
在HttpHandle类中声明并实现一个解析音乐源网数据函数:
QString HttpHandle::searchMusicUrl(const QString &id)
{
//qDebug() << id;
QString body = QString("types=url&id=%1&source=netease").arg(id);
QByteArray musicUrl = postSearch(body);
QJsonParseError error;
QJsonDocument JsonDocument = QJsonDocument::fromJson(musicUrl, &error);
if (error.error != QJsonParseError::NoError) {
qDebug() << "解析音乐源网址JSON数据失败!错误码:" << error.errorString();
return QString();
}
QJsonObject musicObject = JsonDocument.object();
return musicObject["url"].toString();
}
解析歌词JSON数据
在HttpHandle类中声明并实现一个解析歌词数据函数:
QString HttpHandle::searchMusicLyric(const QString &id)
{
//qDebug() << id;
QString body = QString("types=lyric&id=%1&source=netease").arg(id);
QByteArray musicLyric = postSearch(body);
QJsonParseError error;
QJsonDocument JsonDocument = QJsonDocument::fromJson(musicLyric, &error);
if (error.error != QJsonParseError::NoError) {
qDebug() << "解析歌词JSON数据失败!错误码:" << error.errorString();
return QString();
}
QJsonObject musicObject = JsonDocument.object();
return musicObject["lyric"].toString();
}
解析专辑图片网址JSON数据
在HttpHandle类中声明并实现一个解析专辑图片网址数据函数:
QString HttpHandle::searchMusicPicUrl(const QString &picId)
{
//qDebug() << picId;
QString body = QString("types=pic&id=%1&source=netease").arg(picId);
QByteArray musicData = postSearch(body);
QJsonParseError error;
QJsonDocument JsonDocument = QJsonDocument::fromJson(musicData, &error);
if (error.error != QJsonParseError::NoError) {
qDebug() << "解析专辑图片网址JSON数据失败!错误码:" << error.errorString();
return QString();
}
QJsonObject musicPicUrl = JsonDocument.object();
//qDebug() << musicPicUrl["url"].toString();
return musicPicUrl["url"].toString();
}
实现搜索歌单控件并测试解析歌单是否正确
在 ui 窗口界面右键搜索歌单控件 lineEdit_search 转到 pressed 槽,于是在该控件输入数据后便会被解析输出歌单(注意要在上述解析数据函数末尾处用去Debug()输出测试):
void MusicInterface::on_lineEdit_search_returnPressed()
{
QString searchData = ui->lineEdit_search->text(); //获取到用户输入的搜索内容
httpHandle->searchMusicList(searchData); //获取解析歌单数据
//测试代码
httpHandle->searchMusicUrl("174956"); //获取解析声源下载地址
httpHandle->searchMusicLyric("174956"); //获取解析歌词
httpHandle->searchMusicPicUrl("109951164006892980"); //获取pic对应的音乐专辑图片的网址
}
测试成功后显示如下:
测试完后注销掉后三排测试代码
实现http协议网络连接类完整代码
http协议网络通信、数据解析类头文件
#ifndef HTTPHANDLE_H
#define HTTPHANDLE_H
#include <QObject>
#include <QNetworkAccessManager>
class HttpHandle : public QObject
{
Q_OBJECT
public:
explicit HttpHandle(QObject *parent = nullptr);
QByteArray postSearch(const QString &body);
QByteArray getSearch(const QString &url);
void searchMusicList(const QString &searchData);
QString searchMusicUrl(const QString &id);
QString searchMusicLyric(const QString &id);
QString searchMusicPicUrl(const QString &picId);
signals:
void signalShowMusicInfoList(QStringList musicInfo);
public slots:
private:
QNetworkAccessManager *networkAccessManager;
};
#endif // HTTPHANDLE_H
http协议网络通信、数据解析类实现文件
#include "Httphandle.h"
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QEventLoop>
#include <QDebug>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonParseError>
#include <QJsonObject>
HttpHandle::HttpHandle(QObject *parent) : QObject(parent),
networkAccessManager(new QNetworkAccessManager(this))
{
}
QByteArray HttpHandle::postSearch(const QString &body)
{
QNetworkRequest networkRequest(QUrl("https://l-by.cn/yinyue/api.php"));
networkRequest.setRawHeader(QByteArray("content-type"), QByteArray("application/x-www-form-urlencoded; charset=UTF-8"));
QEventLoop eventLoop;
QNetworkReply *networkReply = networkAccessManager->post(networkRequest, body.toUtf8());
connect(networkReply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
return networkReply->readAll();
}
QByteArray HttpHandle::getSearch(const QString &url)
{
QNetworkRequest networkRequest(url);
QEventLoop eventLoop;
QNetworkReply *networkReply = networkAccessManager->get(networkRequest);
connect(networkReply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
return networkReply->readAll();
}
void HttpHandle::searchMusicList(const QString &searchData)
{
QString body = QString("types=search&count=30&source=netease&pages=1&name=%1").arg(searchData);//30是一面歌曲数,1是页面数,可以用%2添加参数进行翻页,后面加上.arg(int)
QByteArray musicData = postSearch(body);
QJsonParseError error;
QJsonDocument JsonDocument = QJsonDocument::fromJson(musicData, &error);
if (error.error != QJsonParseError::NoError) {
qDebug() << "解析音乐列表JSON数据失败!错误码:" << error.errorString();
return;
}
QJsonArray musicInfoArray = JsonDocument.array();
for (int i = 0; i < musicInfoArray.size(); ++i) {
QJsonObject musicObject = musicInfoArray[i].toObject();
QStringList musicInfo;
QString id = QString::number(musicObject["id"].toInt());
QString picId = musicObject["pic_id"].toString();
QString name = musicObject["name"].toString();
QJsonArray artistArray = musicObject["artist"].toArray();
QString artist;
for (int j = 0; j < artistArray.size(); ++j) {
artist = artist + artistArray[j].toString() + ',';
}
artist.chop(1); //删除最后一个多余的','
QString album = musicObject["album"].toString();
musicInfo << id << picId << name << artist << album;
emit signalShowMusicInfoList(musicInfo); }
}
QString HttpHandle::searchMusicUrl(const QString &id)
{
//qDebug() << id;
QString body = QString("types=url&id=%1&source=netease").arg(id);
QByteArray musicUrl = postSearch(body);
QJsonParseError error;
QJsonDocument JsonDocument = QJsonDocument::fromJson(musicUrl, &error);
if (error.error != QJsonParseError::NoError) {
qDebug() << "解析音乐源网址JSON数据失败!错误码:" << error.errorString();
return QString();
}
QJsonObject musicObject = JsonDocument.object();
//qDebug() << musicObject["url"].toString();
return musicObject["url"].toString();
}
QString HttpHandle::searchMusicLyric(const QString &id)
{
//qDebug() << id;
QString body = QString("types=lyric&id=%1&source=netease").arg(id);
QByteArray musicLyric = postSearch(body);
QJsonParseError error;
QJsonDocument JsonDocument = QJsonDocument::fromJson(musicLyric, &error);
if (error.error != QJsonParseError::NoError) {
//qDebug() << "解析歌词JSON数据失败!错误码:" << error.errorString();
return QString();
}
QJsonObject musicObject = JsonDocument.object();
//qDebug() << musicObject["lyric"].toString();
return musicObject["lyric"].toString();
}
QString HttpHandle::searchMusicPicUrl(const QString &picId)
{
//qDebug() << picId;
QString body = QString("types=pic&id=%1&source=netease").arg(picId);
QByteArray musicData = postSearch(body);
QJsonParseError error;
QJsonDocument JsonDocument = QJsonDocument::fromJson(musicData, &error);
if (error.error != QJsonParseError::NoError) {
qDebug() << "解析专辑图片网址JSON数据失败!错误码:" << error.errorString();
return QString();
}
QJsonObject musicPicUrl = JsonDocument.object();
//qDebug() << musicPicUrl["url"].toString();
return musicPicUrl["url"].toString();
}
实现双击点播
新创建一个音乐播放类(MusicPlayer),该类中使用Map容器将音乐列表与其对应的歌曲信息保存下来,根据系统QMediaplayer里的 play()函数可自动解析音源网址并播放,从而达到点播的效果;
MusicPlayer 音乐播放、歌词解析类头文件
#ifndef MUSICPLAYER_H
#define MUSICPLAYER_H
#include <QMediaPlayer>
#include <QMap>
#include <QTime>
class MusicPlayer : public QMediaPlayer
{
Q_OBJECT
public:
explicit MusicPlayer(QObject *parent = nullptr);
QString parsingLyrics(QString lyric);
signals:
void getTextEditLine(int line);
public slots:
void slotPositionChange(qint64 ms);
private:
QMap<qint64, int> lyricTime;
};
#endif // MUSICPLAYER_H
MusicPlayer 音乐播放、歌词解析类实现文件
#include "MusicPlayer.h"
MusicPlayer::MusicPlayer(QObject *parent) : QMediaPlayer(parent)
{
setVolume(50);
setNotifyInterval(200);
connect(this, SIGNAL(positionChanged(qint64)), this, SLOT(slotPositionChange(qint64)));
}
QString MusicPlayer::parsingLyrics(QString lyric)
{
QStringList lyricList = lyric.split('\n'); //以'\n'为界限拼接字符串
QString newLyric;
lyricTime.clear();
int line = 0;
for (int i = 0; i < lyricList.size(); ++i) {
QStringList lyricLineList = lyricList[i].split(']');
if (lyricLineList.size() != 2 || lyricLineList[1].size() < 1) {
continue;
}
QString lyricLine = lyricLineList[1].trimmed(); //去掉首位空格
newLyric = newLyric + lyricLine + "\r\n";
QString time = lyricLineList[0].remove('[');
if (time.size() == 8) {
time = time + '0'; //老歌时间补0
}
QTime ms = QTime::fromString(time, "mm:ss.zzz");
lyricTime[ms.msecsSinceStartOfDay()] = line ++;
}
//qDebug() << lyricTime;
return newLyric;
}
void MusicPlayer::slotPositionChange(qint64 ms)
{
if (lyricTime.empty()) {
return;
}
QMap<qint64, int>::iterator it = lyricTime.upperBound(ms);
int endLine = (lyricTime.end() - 1).value();
if (it == lyricTime.end()) {
-- it;
//qDebug() << it.value();
emit getTextEditLine(it.value());
}
else {
if (it.value() + 5 <= endLine) {
emit getTextEditLine(it.value() + 5);
}
//qDebug() << it.value() - 1;
emit getTextEditLine(it.value() - 1);
}
}
专辑图片处理
GraphicsView专辑图片处理类头文件
#ifndef GRAPHICSVIEW_H
#define GRAPHICSVIEW_H
#include <QGraphicsView>
#include <QImage>
#include <QGraphicsScene>
#include "DiskItem.h"
#include "NeedleItem.h"
class GraphicsView : public QGraphicsView
{
Q_OBJECT
public:
explicit GraphicsView(QWidget *parent = nullptr);
void paintEvent(QPaintEvent *pe);
void resizeEvent(QResizeEvent *re);
void reflushMusicPic(const QImage& pic);
QImage makeARGB32Image(QImage musicPic);
QImage makeCircleImage(QImage argb32Image);
QImage makeDiskImage(QImage circleImage);
void diskItemAnimaStart();
void diskItemAnimaPause();
signals:
public slots:
private:
QImage image;
QGraphicsScene *scene;
DiskItem *diskItem;
NeedleItem *needleItem;
};
#endif // GRAPHICSVIEW_H
GraphicsView专辑图片处理类实现文件
#include "GraphicsView.h"
#include <QPainter>
#include <QResizeEvent>
GraphicsView::GraphicsView(QWidget *parent) : QGraphicsView(parent),
scene(new QGraphicsScene(this)),
diskItem(new DiskItem(this)),
needleItem(new NeedleItem(this))
{
image.load(":/image/背景图4.png");
setScene(scene);
scene->addItem(diskItem);
scene->addItem(needleItem);
}
void GraphicsView::paintEvent(QPaintEvent *pe) //绘制事件函数
{
QPainter painter(viewport());
painter.setRenderHint(QPainter::SmoothPixmapTransform);
painter.drawImage(rect(), image);
QGraphicsView::paintEvent(pe);
}
void GraphicsView::resizeEvent(QResizeEvent *re)
{
int x = re->size().width();
int y = re->size().height();
scene->setSceneRect(x / -2.0, y / -2.0, x, y);
diskItem->setPos(0, 0);
needleItem->setPos(-80, -220);
QGraphicsView::resizeEvent(re);
}
void GraphicsView::reflushMusicPic(const QImage &pic)
{
//image = pic;
//pic.save("1.png");
QImage argb32Image = makeARGB32Image(pic);
//argb32Image.save("2.png");
QImage circleImage = makeCircleImage(argb32Image);
//circleImage.save("3.png");
QImage diskImage = makeDiskImage(circleImage);
//diskImage.save("4.png");
diskItem->setImage(diskImage);
update(); //触发绘制事件
}
QImage GraphicsView::makeARGB32Image(QImage musicPic)
{
QImage circle(":/image/circleMask.png");
musicPic = musicPic.scaled(circle.size(), Qt::KeepAspectRatio);
QImage fixedImage(circle.size(), QImage::Format_ARGB32_Premultiplied);
QPainter painter(&fixedImage);
painter.setRenderHint(QPainter::SmoothPixmapTransform);
painter.setCompositionMode(QPainter::CompositionMode_Source);
painter.fillRect(fixedImage.rect(), Qt::transparent);
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
painter.drawImage(fixedImage.rect(), musicPic);
painter.end();
return fixedImage;
}
QImage GraphicsView::makeCircleImage(QImage argb32Image)
{
QImage circle(":/image/circleMask.png");
QPainter painter(&argb32Image);
painter.setRenderHint(QPainter::SmoothPixmapTransform);
painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
painter.drawImage(0, 0, circle);
painter.end();
return argb32Image;
}
QImage GraphicsView::makeDiskImage(QImage circleImage)
{
QImage disk(":/image/disk.png");
QPainter painter(&disk);
painter.setRenderHint(QPainter::SmoothPixmapTransform);
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
#if 1
painter.drawImage(QPointF((disk.width() - circleImage.width()) / 2.0,
(disk.height() - circleImage.height()) / 2.0), circleImage);
#else
QRect rec = circleImage.rect();
QPoint centerPoint = disk.rect().center(); //重合中心点
rec.moveCenter(centerPoint);
painter.drawImage(rec, circleImage);
#endif
painter.end();
return disk;
}
void GraphicsView::diskItemAnimaStart()
{
diskItem->startAnimation();
needleItem->startAnimation();
}
void GraphicsView::diskItemAnimaPause()
{
diskItem->pauseAnimation();
needleItem->pauseAnimation();
}
动态图片处理
实现唱片图片旋转
DiskItem光盘图元旋转类头文件
#ifndef DISKITEM_H
#define DISKITEM_H
#include <QObject>
#include <QGraphicsItem>
#include <QImage>
#include <QPropertyAnimation>
class DiskItem : public QObject, public QGraphicsItem
{
Q_OBJECT
Q_INTERFACES(QGraphicsItem)
Q_PROPERTY(qreal anagle READ rotation WRITE setRotation)
public:
explicit DiskItem(QObject *parent = nullptr);
virtual QRectF boundingRect() const;
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = Q_NULLPTR);
void setImage(const QImage& musicImage);
void startAnimation();
void pauseAnimation();
signals:
public slots:
private:
QImage image;
QPropertyAnimation *animation;
};
#endif // DISKITEM_H
DiskItem光盘图元旋转类实现文件
#include "DiskItem.h"
#include <QPainter>
DiskItem::DiskItem(QObject *parent) : QObject(parent)
{
image.load(":/image/4.png");
animation = new QPropertyAnimation(this, "anagle", this);
animation->setDuration(2000);
animation->setStartValue(0);
animation->setEndValue(360);
animation->setLoopCount(-1);
}
QRectF DiskItem::boundingRect() const
{
return QRectF(image.width() / -2.0, image.height() / -2.0, image.width(), image.height());
}
void DiskItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
painter->setRenderHint(QPainter::SmoothPixmapTransform);
painter->drawImage(boundingRect(), image);
}
void DiskItem::setImage(const QImage &musicImage)
{
image = musicImage;
update();
}
void DiskItem::startAnimation()
{
animation->start();
}
void DiskItem::pauseAnimation()
{
animation->pause();
}
实现唱针图元摆动
NeedleItem唱针图元摆动类头文件
#ifndef NEEDLEITEM_H
#define NEEDLEITEM_H
#include <QObject>
#include <QGraphicsItem>
#include <QImage>
#include <QPropertyAnimation>
class NeedleItem : public QObject, public QGraphicsItem
{
Q_OBJECT
Q_INTERFACES(QGraphicsItem)
Q_PROPERTY(qreal anagle READ rotation WRITE setRotation)
public:
explicit NeedleItem(QObject *parent = nullptr);
virtual QRectF boundingRect() const;
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = Q_NULLPTR);
void startAnimation();
void pauseAnimation();
signals:
public slots:
private:
QImage image;
QPropertyAnimation *animation;
};
#endif // NEEDLEITEM_H
NeedleItem唱针图元摆动类实现文件
#include "NeedleItem.h"
#include <QPainter>
NeedleItem::NeedleItem(QObject *parent) : QObject(parent)
{
image.load(":/image/magnetNeedle.png");
animation = new QPropertyAnimation(this, "anagle", this);
setTransformOriginPoint(-102, -0.5);
animation->setDuration(200);
animation->setLoopCount(1);
}
QRectF NeedleItem::boundingRect() const
{
return QRectF(image.width() / -2.0, image.height() / -2.0, image.width(), image.height());
}
void NeedleItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
painter->setRenderHint(QPainter::SmoothPixmapTransform);
painter->drawImage(boundingRect(), image);
}
void NeedleItem::startAnimation()
{
animation->setStartValue(0);
animation->setEndValue(20);
animation->start();
}
void NeedleItem::pauseAnimation()
{
animation->setStartValue(20);
animation->setEndValue(0);
animation->start();
}
关于界面
AboutInterface关于界面窗口类头文件
#ifndef ABOUTINTERFACE_H
#define ABOUTINTERFACE_H
#include <QWidget>
namespace Ui {
class AboutInterface;
}
class AboutInterface : public QWidget
{
Q_OBJECT
public:
explicit AboutInterface(QWidget *parent = 0);
~AboutInterface();
private:
Ui::AboutInterface *ui;
};
#endif // ABOUTINTERFACE_H
AboutInterface关于界面窗口类实现文件
#include "AboutInterface.h"
#include "ui_AboutInterface.h"
AboutInterface::AboutInterface(QWidget *parent) :
QWidget(parent),
ui(new Ui::AboutInterface)
{
ui->setupUi(this);
setWindowIcon(QIcon(":/image/背景图1.jpg"));
setWindowFlag(Qt::WindowStaysOnTopHint); //界面置顶
setFixedSize(size());
}
AboutInterface::~AboutInterface()
{
delete ui;
}