目录
[事件过滤器:实现监视目标对象事件 的作用](#事件过滤器:实现监视目标对象事件 的作用)
自定义recBox:
- 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
做好美化后将QQMusic主界⾯中recPage⻚⾯中的recMusicBox和supplyMusicBox提升为RecBox
RecBoxItem类中添加动画效果:
重写eventfilter函数
cpp
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的函数:
cpp
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的返回值会作为参数。
cpp
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;
}
cpp
recbox.h:
#ifndef RECBOX_H
#define RECBOX_H
#include <QWidget>
#include <QJsonArray>
namespace Ui {
class RecBox;
}
class RecBox : public QWidget
{
Q_OBJECT
public:
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:
cpp
srand(time(NULL));
ui->recMusicBox->initRecBoxUi(RandomPicture(),1);
ui->supplyMusicBox->initRecBoxUi(RandomPicture(),2);
在recbox的构造函数里初始化行列数值
cpp
#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的初始化函数:
cpp
recbox.cpp
void RecBox::initRecBoxUi(QJsonArray data, int row)
{
// 如果是两⾏,说明当前RecBox是主界⾯上的supplyMusicBox
if(2 == row)
{
this->row = row;
this->col = 8;
}
else
{
// 否则:只有⼀⾏,为主界⾯上recMusicBox
ui->recListDown->hide();
}
// 图⽚保存起来
imageList = data;
// 往RecBox中添加图⽚
createRecBoxItem();
}
void RecBox::createRecBoxItem()
{
// 创建RecBoxItem对象,往RecBox中添加
// col
for(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中实例化类然后添加ui
cppRecBoxItem* item = new RecBoxItem(); ui->recListUpHLayout->addWidget(item);
4.用connect函数连接
下面介绍connect函数connect函数
信号槽机制,按钮是发送信号,窗口是接收信号,槽的本质就是对信号响应的函数,是一个回调函数
例1:
cppvoid 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:
cppconnect(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 指向 的是 事件本应传递到的目标对象。
重写是类似这样的:
cppbool 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 processing return 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 类型。
例如:
cppQString 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 ="拐卖" //等等还有好多函数
RecBox添加RecBoxItem
random_shuffle是打乱列表顺序的函数
QJsonArray和QJsonObject
这两个类都是用于处理JSON数据
在Qt中,QJsonArray和QJsonObject是Qt JSON模块的一部分,用于表示JSON数据
- QJsonArray: - 功能:QJsonArray类用于封装一个JSON数组。 - 一个JSON数组是一个值的有序列表,这些值可以是不同的类型(包括字符串、数字、布尔值、对象、数组,以及null)。 - 在QJsonArray中,元素是通过索引(从0开始)来访问的。 - 常用操作: * 添加值:使用`append`、`push_back`或`insert`方法。 * 访问值:使用`at`方法或`operator[]`(注意:operator[]返回的是非const的引用,而at返回的是const引用)。 * 删除值:使用`removeAt`方法。 * 获取数组大小:使用`size`方法。 * 遍历:可以使用迭代器或简单的for循环(基于索引)。
- QJsonObject: - 功能:QJsonObject类用于封装一个JSON对象。 - 一个JSON对象是一个无序的键值对集合,其中键是字符串,值可以是各种JSON类型(包括数组、对象、基本类型等)。 - 在QJsonObject中,通过键(字符串)来访问对应的值。 - 常用操作: * 插入键值对:使用`insert`方法。 * 访问值:使用`value`方法或`operator[]`(注意:operator[]如果键不存在则会插入一个null值,而value方法不会修改对象)。 * 删除键值对:使用`remove`方法。 * 检查键是否存在:使用`contains`方法。 * 获取所有键:使用`keys`方法。 * 获取键值对数量:使用`size`方法。 * 遍历:可以使用迭代器或遍历键列表。
QJsonArray:表示JSON数组,有序列表,通过索引访问。
QJsonObject:表示JSON对象,键值对映射,通过键访问。
例如:
cppQJsonArray: 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(); // 判空
cppQJsonObject: 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(); // 键值对数量