QT项目 -仿QQ音乐的音乐播放器(第三节)
目录
自定义recBox:
RecBoxItem类中添加动画效果:
两个添加TEXT和imgStyle的函数:
图片随机函数:
qqmusic.cpp:
recbox的初始化函数:
QT的一些额外加餐:
关于如何设置按钮的功能
connect函数
事件过滤器:实现监视目标对象事件 的作用
QPropertyAnimation的基本使用
QString
QJsonArray和QJsonObject
自定义recBox:
1. RecBox界⾯布局① 新添加设计师界⾯,命名为RecBox。geometry的宽⾼修改为:685*440。② 添加三个Widget,objectName依次修改为leftPage、musicContent、rightPage;leftPage 和 rightPage的minimumSize和maximumSize修改宽为30,然后选中RecBox点击⽔平布局。将RecBox的 margin和Spacing修改为0③ 在upPage和downPage中各拖⼀个按钮,upPage中按钮objectName修改为btUp,minimumSize的⾼度修改为 220;downPage中按钮objectName修改为btDown,minimumSize的⾼度修改为220;然后选中upPage和 downPage点击⽔平布局。将upPagedownPage和的margin和Spacing修改为0。③ 在musicContent中拖两个Widget,objectName依次修改为recListUp和recListDown,然后选中musicContent点 击垂直布局,将musicContent的margin和Spacing修改为0。(为了看清楚效果可临时将recListUp背景⾊设置 为:background-color:green; 将recListDown背景⾊设置为:background-color:red;)④ 在recListUp和recListDown中分别拖两个⽔平布局器,依次命名为recListUpHLayout和recListDownHLayout,选 中recListUp和recListDown点击⽔平布局,将margin和Spacing修改为0

RecBoxItem类中添加动画效果:
重写eventfilter函数
bool RecBoxItem::eventFilter(QObject *watched, QEvent *event)
{if(watched == ui->musicImageBox){if(QEvent::Enter == event->type()){// 添加图片上移动画QPropertyAnimation* animation = new QPropertyAnimation(ui->musicImageBox, "geometry");animation->setDuration(150);animation->setStartValue(QRect(9,9, ui->musicImageBox->width(), ui->musicImageBox->height()));animation->setEndValue(QRect(9, 0, ui->musicImageBox->width(), ui->musicImageBox->height()));animation->start();connect(animation, &QPropertyAnimation::finished, this, [=](){delete animation;});}else if(QEvent::Leave == event->type()){// 添加图标下移动画QPropertyAnimation* animation = new QPropertyAnimation(ui->musicImageBox, "geometry");animation->setDuration(150);animation->setStartValue(QRect(9,0, ui->musicImageBox->width(), ui->musicImageBox->height()));animation->setEndValue(QRect(9, 9, ui->musicImageBox->width(), ui->musicImageBox->height()));animation->start();connect(animation, &QPropertyAnimation::finished, this, [=](){delete animation;});}return true;}return QObject::eventFilter(watched, event);
}
两个添加TEXT和imgStyle的函数:
void RecBoxItem::setText(const QString &text)
{ui->recBoxItemText->setText(text);
}void RecBoxItem::setImage(const QString &Imagepath)
{QString imgStyle="border-image:url("+Imagepath+");";ui->recMusicImage->setStyleSheet(imgStyle);
}
图片随机函数:
在qqmusic.cpp中定义图片随机选取并且存成嵌套qjsonobject的qjsonarray格式返回,后面会在qqmusic调用initrecitem函数,里面randompicture的返回值会作为参数。
QJsonArray QQMusic::RandomPicture()
{// 推荐⽂本 + 推荐图⽚路径QVector<QString> vecImageName;vecImageName<<"001.png"<<"003.png"<<"004.png"<<"005.png"<<"006.png"<<"007.png"<<"008.png"<<"009.png"<<"010.png"<<"011.png"<<"012.png"<<"013.png"<<"014.png"<<"015.png"<<"016.png"<<"017.png"<<"018.png"<<"019.png"<<"020.png"<<"021.png"<<"022.png"<<"023.png"<<"024.png"<<"025.png"<<"026.png"<<"027.png"<<"028.png"<<"029.png"<<"030.png"<<"031.png"<<"032.png"<<"033.png"<<"034.png"<<"035.png"<<"036.png"<<"037.png"<<"038.png"<<"039.png"<<"040.png";std::random_shuffle(vecImageName.begin(), vecImageName.end());// 001.png// path: ":/images/rec/"+vecImageName[i];// text: "推荐-001"QJsonArray objArray;for(int i = 0; i < vecImageName.size(); ++i){QJsonObject obj;obj.insert("path", ":/images/rec/"+vecImageName[i]);// arg(i, 3, 10, QCchar('0'))// i:要放⼊%1位置的数据// 3: 三位数// 10:表⽰⼗进制数// QChar('0'):数字不够三位,前⾯⽤字符'0'填充QString strText = QString("推荐-%1").arg(i, 3, 10, QChar('0'));obj.insert("text", strText);objArray.append(obj);}return objArray;}
recbox.h:#ifndef RECBOX_H
#define RECBOX_H#include <QWidget>
#include <QJsonArray>namespace Ui {
class RecBox;
}class RecBox : public QWidget
{Q_OBJECTpublic:explicit RecBox(QWidget *parent = nullptr);~RecBox();void initRecBoxUi(QJsonArray data, int row);//初始化推荐界面void createRecBoxItem();private:Ui::RecBox *ui;int row; // 记录当前RecBox实际总⾏数int col; // 记录当前RecBox实际每⾏有⼏个元素QJsonArray imageList; // 保存界⾯上的图⽚, ⾥⾯实际为key、value键值对};#endif // RECBOX_H
上面在recbox.h中定义了row和col作为行列
qqmusic.cpp:
srand(time(NULL));ui->recMusicBox->initRecBoxUi(RandomPicture(),1);ui->supplyMusicBox->initRecBoxUi(RandomPicture(),2);
在recbox的构造函数里初始化行列数值
#include "ui_recbox.h"
#include<RecBoxItem.h>
#include <QJsonObject>RecBox::RecBox(QWidget *parent): QWidget(parent), ui(new Ui::RecBox),row(1),col(4)
{ui->setupUi(this);
}
recbox的初始化函数:
recbox.cppvoid RecBox::initRecBoxUi(QJsonArray data, int row)
{// 如果是两⾏,说明当前RecBox是主界⾯上的supplyMusicBoxif(2 == row){this->row = row;this->col = 8;}else{// 否则:只有⼀⾏,为主界⾯上recMusicBoxui->recListDown->hide();}// 图⽚保存起来imageList = data;// 往RecBox中添加图⽚createRecBoxItem();
}void RecBox::createRecBoxItem()
{// 创建RecBoxItem对象,往RecBox中添加// colfor(int i = 0; i < col; ++i){RecBoxItem* item = new RecBoxItem();// 设置⾳乐图⽚与对应⽂本QJsonObject obj = imageList[i].toObject();item->setText(obj.value("text").toString());item->setImage(obj.value("path").toString());// recMusicBox:col为4,元素添加到ui->recListUpHLayout中// supplyMuscBox: col为8, ui->recListUpHLayout添加4个,ui->recListDownHLayout添加4个// 即supplyMuscBox上下两⾏都要添加// 如果是recMusicBox:row为1,只能执⾏else,所有4个RecBoxItem都添加到ui->recListUpHLayout中// 如果是supplyMuscBox:row为2,col为8,col/2结果为4,i为0 1 2 3时,元素添加到ui->recListDownHLayout中// i为4 5 6 7时,元素添加到ui->recListUpHLayout中if(i >= col/2 && row == 2){ui->recListDownHLayout->addWidget(item);}else{ui->recListUpHLayout->addWidget(item);}}}
总结下来就是在recboxitem类里重写eventfilter函数设置动画,然后在recbox函数里添加图片/写初始化图片函数,在qqmusic类里写随机图片函数(输出json格式的array数组),在qqmusic类里调用初始化图片函数。
最后的效果:
QT的一些额外加餐:
关于如何设置按钮的功能
1.手动添加槽函数2.定义类然后在相应的Widget位置提升为新的类3.直接在cpp中实例化类然后添加uiRecBoxItem* item = new RecBoxItem(); ui->recListUpHLayout->addWidget(item);
4.用connect函数连接下面介绍connect函数
connect函数
信号槽机制,按钮是发送信号,窗口是接收信号,槽的本质就是对信号响应的函数,是一个回调函数
例1:
void QQMusic::connectSignalAndSlot() {connect(ui->Rec, &BtForm::click, this, &QQMusic::onBtFormClick);connect(ui->music, &BtForm::click, this, &QQMusic::onBtFormClick);connect(ui->audio, &BtForm::click, this, &QQMusic::onBtFormClick);connect(ui->like, &BtForm::click, this, &QQMusic::onBtFormClick);connect(ui->local, &BtForm::click, this, &QQMusic::onBtFormClick);connect(ui->recent, &BtForm::click, this, &QQMusic::onBtFormClick); }
这里连接了6个`BtForm`类型按钮(`ui->Rec`, `ui->music`, `ui->audio`, `ui->like`, `ui->local`, `ui->recent`)的`click`信号到当前对象(`this`,即`QQMusic`实例)的同一个槽函数`onBtFormClick`。- 这意味着当这些按钮中的任何一个被点击时,都会触发`QQMusic::onBtFormClick`槽函数。
这里的第一个参数是目标对象(界面中的按钮组件),第二个参数是触发信号(自定义按钮类
BtForm
的点击信号),第三个参数接收者(当前QQMusic
类实例),第四个参数槽函数(处理按钮点击的槽函数)
例2:
connect(animation, &QPropertyAnimation::finished, this, [=](){delete animation; });
这里连接了一个`QPropertyAnimation`对象(指针变量名为`animation`)的`finished`信号。- 当动画完成时,会触发一个Lambda表达式(作为槽函数)。- Lambda表达式以值捕获方式(`[=]`)捕获当前作用域的变量(注意:这里捕获的是`this`指针和`animation`指针,因为`animation`在外部定义)。- 在Lambda表达式内部,执行`delete animation;`,即删除动画对象,释放内存。
这里的第一个参数是针对musicImageBox创建的动画组件,第二个参数是结束触发信号,第三个参数是接收者this(recboxitem),第四个参数是槽函数(删除动画)
事件过滤器:实现监视目标对象事件 的作用
bool eventFilter(QObject *watched, QEvent *event);eventFilter 的第一个参数 obj 指向的是事件本应传递到的目标对象。重写是类似这样的:bool Widget::eventFilter(QObject *obj, QEvent *event){if(obj == ui->label){//鼠标进入的时候if (event->type() == QEvent::Enter){ui->label->setText("我是红色");ui->label->setStyleSheet(redStyle);return true; //拦截事件,不再传递}else if(event->type() == QEvent::Leave) //鼠标离开{ui->label->setText("我是黑色");ui->label->setStyleSheet(blackStyle);return true;}return false; //不拦截事件,允许继续传递,别的事件会传给label对象}// standard event processingreturn QWidget::eventFilter(obj, event);}
鼠标进入过滤->鼠标离开过滤
QPropertyAnimation
的基本使用常用接口函数
- setTargetObject:设置仿真对象
- setPropertyName:设置仿真属性的名称,
- setDuration:设置仿真持续的时间
- setStartValue:设置初始值
- setEndValue:设置结束值
- start:开始仿真
- currentValue:返回当前值
- setKeyValueAt:设置关键点的值
- valueChanged:只要仿真追踪的值发生变化,就发送该信号
QString
QString 是 Qt 中的一个类,用于存储字符串,QString 没有父类。QString 存储的是一串字符,每个字符是一个 QChar 类型的数据。QChar 使用的是 UTF-16 编码,一个字符包含 2 字节数据。 对于超过 65535 的 Unicode 编码,QString 使用两个连续的 QChar 字符表示。UTF-16 是一种 Unicode 编码,能表示汉字,在 QString 字符串中一个汉字是一个字符。
QString 类定义了大量的接口函数用于字符串操作。QString在 Qt 类库中应用非常广泛,很多函数的参数是 QString 类型。
例如:
QString str = "Hello Qt";QString str1= "洋洋", str2= "得意"; QString str3= str1 + str2; //str3 ="洋洋得意" str1= str2 + str1; //str1 ="得意洋洋" QString str1= "卖", str2= "拐"; QString str3= str1; str1.append(str2); //str1 ="卖拐" str3.prepend(str2); //str3 ="拐卖" //等等还有好多函数
QJsonArray和QJsonObject
这两个类都是用于处理JSON数据在Qt中,QJsonArray和QJsonObject是Qt JSON模块的一部分,用于表示JSON数据1. QJsonArray: - 功能:QJsonArray类用于封装一个JSON数组。 - 一个JSON数组是一个值的有序列表,这些值可以是不同的类型(包括字符串、数字、布尔值、对象、数组,以及null)。 - 在QJsonArray中,元素是通过索引(从0开始)来访问的。 - 常用操作: * 添加值:使用`append`、`push_back`或`insert`方法。 * 访问值:使用`at`方法或`operator[]`(注意:operator[]返回的是非const的引用,而at返回的是const引用)。 * 删除值:使用`removeAt`方法。 * 获取数组大小:使用`size`方法。 * 遍历:可以使用迭代器或简单的for循环(基于索引)。2. QJsonObject: - 功能:QJsonObject类用于封装一个JSON对象。 - 一个JSON对象是一个无序的键值对集合,其中键是字符串,值可以是各种JSON类型(包括数组、对象、基本类型等)。 - 在QJsonObject中,通过键(字符串)来访问对应的值。 - 常用操作: * 插入键值对:使用`insert`方法。 * 访问值:使用`value`方法或`operator[]`(注意:operator[]如果键不存在则会插入一个null值,而value方法不会修改对象)。 * 删除键值对:使用`remove`方法。 * 检查键是否存在:使用`contains`方法。 * 获取所有键:使用`keys`方法。 * 获取键值对数量:使用`size`方法。 * 遍历:可以使用迭代器或遍历键列表。QJsonArray:表示JSON数组,有序列表,通过索引访问。QJsonObject:表示JSON对象,键值对映射,通过键访问。例如:QJsonArray:QJsonArray arr; arr.append(42); // 添加整数 arr.append("Hello"); // 添加字符串 arr.append(QJsonObject{ {"key", "value"} }); // 添加嵌套对象int num = arr[0].toInt(); // 获取索引 0 的值 → 42 QString str = arr[1].toString(); // → "Hello"arr.replace(0, 100); // 替换索引 0 的值 arr.removeAt(1); // 删除索引 1 的元素int size = arr.size(); // 获取元素数量 bool isEmpty = arr.empty(); // 判空
QJsonObject:QJsonObject obj; obj.insert("id", 1001); obj["name"] = "Alice"; // 使用运算符[]插入 obj["scores"] = QJsonArray{90, 85, 95}; // 嵌套数组int id = obj["id"].toInt(); // → 1001 QString name = obj.value("name").toString(); // → "Alice"obj["id"] = 2002; // 修改值 obj.remove("name"); // 删除键bool hasKey = obj.contains("scores"); // 检查键是否存在 QStringList keys = obj.keys(); // 获取所有键 → ["id", "scores"] int size = obj.size(); // 键值对数量