1. 前言
经常感觉自己的桌面有点单调,一直想养一只桌面宠物,但是一直没有找到合适的,或者说是没有找到我想要的,我想要的是可以随意添加很多其他的功能的,那么就只有自己手搓了。本来之前就想做的但是无奈一直没有找到合适的宠物的外观,不仅没有合适的外观没有找到就连能够在桌面上运行的2D动画也没有找到合适的,于是索性就采用最简单粗暴的方式用图片的不断变换来组成一个2D的动画。
2. 桌面宠物素材制作
2.1 宠物素材选择
宠物的素材选择首先就是能够录制到清晰流畅的视频,其次就是能够有比较丰富的动作可以选择。
我这里使用的是手机上的一个桌面的宠物软件,可以在手机桌面上养一只小猫,里面的动画还是比较丰富的,而且小猫本身和背景的色差也比较大可以很方便的使用ps把小猫抠出来。
2.2 录制视频
接下来就是在手机端录制视频了,将手机录屏的画质调到最高,主要就是录制小猫的各种各样的动作,将录制的动作发到电脑上用来做之后的处理。
2.3 分解视频成图片
录制好小猫的动作视频之后,接下来就是要将录制的视频做处理。要在视频中找到例如小猫走路、玩耍、睡觉等等的一组动画,因为小猫的动作很多都是一个动作重复进行的,因此我们需要找到这一组动画。
-
将视频导入到pr软件中
-
删除视频的音频部分只保留视频部分,并找到需要的一组动画帧
-
将这段视频导出为图片的格式,也就是将这段视频的每帧分解为一张图片
-
这样就得到了很多张的图片,将这些图片以每秒90张速度播放出来其实就是原始的视频的样子了
2.4 处理图片
在得到所有的图片后接下来的工作就是枯燥无味且漫长的抠图了,需要将所有的图片中的小猫一张一张的抠出来。这里是最耗费时间的,虽然中间使用了一些快捷的方式加速,但是还是避免不了。
-
将所有图片导入到ps中,首先使用ps的对象选择工具,选择小猫,之后再使用魔棒工具进行更加精细的调整。尤其是小猫胡子的部分要注意选取上不然会导致导出的图片的大小不一样,在qt中使用的时候会鬼畜。
-
使用快捷键Ctrl+Alt+J进行快速创建图层,或者可以使用更加快速的方法就是鼠标宏或者键盘宏,这样就可以更加方便快速的创建图层
-
在图层创建成功后就需要先对其进行裁切,也就是裁切掉多余的空白部分,然后导出为png图片。这一部分可以直接使用鼠标宏或者键盘宏进行快速的创建
-
这样导出的图片其实就是可以使用了,但是由于这样使用工具的抠出的小猫的边缘过度不光滑而且还有一点背景的颜色,因此还需要对图片做锐化处理。一张张图片的处理起来就有点太过于麻烦了,其实ps是自带批量处理图片操作的。ps的批处理其实就是ps会记录下我们对图片的所有的操作,然后自动的对每张图片进行相同的操作。下面就简单介绍一下批处理的使用
-
首先就是录制需要的操作,也就是对图片需要进行的操作
-
在录制好之后就可以对所有的图片批量的操作了。ps可以自动的对文件夹中的所有图片执行相同的图片处理操作,这样就可以节省大量的时间和精力
-
-
来对比一下处理前和处理后的效果
可以看到经过处理之后右边边缘的位置白色明显少了很多,如果不做这样处理的话在之后导入到qt中的时候或看到小猫周围有一圈的白边放在桌面上非常的不和谐。
在经过漫长漫长漫长的抠图之后,我们的桌面宠物小猫的所有素材就已经准备好了~~
3. qt制作桌面宠物
3.1 qt加载图片
-
在qt中新建一个qt的项目,在项目里新建qrc资源文件用来保存所有的小猫素材文件
-
把我们之前制作的小猫图片素材加入到资源列表中
3.2 使用QPainter加载图片
3.2.1 QPainter类的说明和简介
QPainter提供高度优化的功能来完成大多数图形用户界面程序所需的工作。它能画出从简单线条到复杂形状如饼图和弦等一切图形。它还可以绘制对齐的文本和像素图。通常,它绘制一个“自然”坐标系,但它也可以进行视图和世界变换。QPainter可以对继承QPaintDevice类的任何对象进行操作。
QPainter的核心功能是绘图,但是类还提供了几个功能,允许自定义QPainter的设置及其渲染质量,以及其他启用剪辑的功能。此外,还可以通过指定绘制者的合成模式来控制不同形状合并在一起的方式。与QPaintDevice和QPaintEngine类一起,QPainter构成了qt绘图系统的基础。QPainter是用于执行绘图操作的类。QPaintDevice表示可以使用QPainter绘制的设备。QPaintEngine提供了一个接口,绘图使用它来绘制不同类型的设备。
3.2.2 QPainter类的使用
我们使用的QPainter类的主要目的是将我们的小猫图片显示到屏幕上,其他的所有的东西都隐藏掉
-
首先需要做的就是将主窗口设置成当前图片的小猫形状。因为之前我们经过抠图已经把除小猫本体之外的所有区域都设置成了透明的区域,所以这里也不需要做额外的处理直接就可以使用
QPixmap newPixmap; images = QString(":/img/walking/") + QString::number(value) + ".png"; newPixmap.load(images); // 从资源文件加载新的图片 qreal wid = newPixmap.width(); //获取图像的宽高 qreal hei = newPixmap.height(); newPixmap = newPixmap.scaled(wid/max,hei/max,Qt::IgnoreAspectRatio); resize(newPixmap.size()); // 调整窗口大小以适应新图片 setMask(newPixmap.mask()); // 设置窗口形状为新图片的透明区域 update(); // 请求窗口重新绘制
-
使用QPainter类将小猫的图片绘制在主窗口的小猫形状的区域
QPixmap newPixmap(images); qreal wid = newPixmap.width(); //获取图像的宽高 qreal hei = newPixmap.height(); // 缩放图像以适应窗口,保持宽高比,并应用平滑转换 newPixmap = newPixmap.scaled(wid/max,hei/max,Qt::IgnoreAspectRatio,Qt::SmoothTransformation); QPainter painter(this); // 设置绘制时的平滑和抗锯齿效果 painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); painter.drawPixmap(0,0,newPixmap); // 在窗口上绘制缩放后的图像,位置(0, 0)
-
经过上面的设置之后这样就能在桌面上显示一个小猫咪的图片了,要想让小猫能够动起来只需要更改一下图片的显示就可以了,定义一个定时器,每隔一段时间切换一次图片的显示
tim = new QTimer(); tim->setInterval(31); connect(tim,SIGNAL(timeout()),this,SLOT(onTimeOut())); tim->start(); //定时器槽函数 void MainWindow::onTimeOut() { static int value = 0; QPixmap newPixmap; images = QString(":/img/walking/") + QString::number(value) + ".png"; newPixmap.load(images); // 从资源文件加载新的图片 qreal wid = newPixmap.width(); //获取图像的宽高 qreal hei = newPixmap.height(); newPixmap = newPixmap.scaled(wid/max,hei/max,Qt::IgnoreAspectRatio); resize(newPixmap.size()); // 调整窗口大小以适应新图片 setMask(newPixmap.mask()); // 设置窗口形状为新图片的透明区域 update(); // 请求窗口重新绘制 value = value + 1; if(value > 95) value = 0; }
-
为了能够让小猫在屏幕上显示的时候一直能够在其他应用的上层显示,因此还需要设置窗口把持置顶
music_item_ui =new Music(this); //创建secondwin窗体对象 Qt::WindowFlags m_flags = windowFlags(); //保持窗口置顶1 setWindowFlags(m_flags|Qt::WindowStaysOnTopHint); //保持窗口置顶2 this->setWindowIcon(QIcon(":/img/walking/0.png")); //设置窗口图标
在这样设置之后我们就能在桌面上得到一只小猫咪了
3.3 增加移动功能
3.3.1 宠物移动功能
在能够成功的在桌面上显示小猫之后,让小猫移动起来就比较简单了。小猫的本身就是qt的窗口,所以只需要移动窗口就可以实现移动小猫咪了。这里同样定义一个定时器,每隔一段时间更改一下小猫的位置信息,然后在重新绘制小猫的时候就可以更新小猫的位置了。
tim1 = new QTimer();
tim1->setInterval(70);
connect(tim1,SIGNAL(timeout()),this,SLOT(onTimeOut1()));
tim1->start();
//定时器槽函数
void MainWindow::onTimeOut1()
{
int i = QRandomGenerator::global()->bounded(5);
int j = QRandomGenerator::global()->bounded(2);
count_x = count_x - i;
count_y = count_y - j;
}
3.3.2 鼠标移动功能
为了让小猫更加的方便的控制,比如小猫自己走到了不合适的位置,想让它走开的话就只能让小猫自己走。因此加一个鼠标控制的功能就显得比较的合理了。要想让鼠标自由的控制小猫的移动,首先就需要捕获鼠标的移动和点击事件,然后根据移动和点击的操作来不断的更新小猫的位置,同时还需要记录鼠标移动后最后的位置,以方便更新小猫自动移动时候的位置信息。
void MainWindow::mousePressEvent(QMouseEvent *event)
{
m_isPressed = true; // 设置鼠标按下标志为真
m_mousePoint = event->globalPos()-pos(); // 计算鼠标相对于窗口的位置
QWidget::mousePressEvent(event); // 调用基类的鼠标按下事件处理函数
static bool i = true;
if(event->buttons()&Qt::RightButton)
{
if(i == true)
{
music_item_ui->show();
i = false;
}
else
{
music_item_ui->hide();
i = true;
}
}
}
void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
//只有左键才可以拖动
if(m_isPressed==true&&event->buttons()&Qt::LeftButton)
{
move(event->globalPos()-m_mousePoint); // 移动窗口位置
m_mousePoint = event->globalPos()-pos();
QWidget::mouseMoveEvent(event); // 调用基类的鼠标移动事件处理函数
QPoint currentPosition = this->pos(); // 获取当前窗口位置,并保存到全局变量 count_x 和 count_y
count_x = currentPosition.x();
count_y = currentPosition.y();
}
}
在添加上上面的功能之后,我们的小猫咪的雏形就基本的完成了。之后就可以在这个基础之上添加其他想要的功能了。
4. 测试qt播放歌曲
通过以上的制作,桌面的宠物的雏形已经基本做好了,但是现在只是这样就显得太单一了。因此,首先要添加的就是歌曲的播放功能,毕竟听歌撸代码已经成了我的日常习惯。
4.1 播放本地歌曲
因为我是用的是qt6制作的,网上能找到的代码大部分都是基于qt5制作的,无奈找了好多天都没有找到可以使用的代码,于是只能去啃qt的帮助手册了。虽然之前也看过qt的帮助手册,但是基本都是为了找一些参数之类的,像这样完全看一个没接触过的还是第一次看。经过一段时间的研究之后,还是很幸运的把功能实现了,总体来说用法还是比较简单的。
player = new QMediaPlayer(this);
audioOutput = new QAudioOutput(this);
player->setAudioOutput(audioOutput );
connect(player,SIGNAL(positionChanged(qint64)),this,SLOT(onPlayerPositionChanged(qint64)));
connect(player,SIGNAL(durationChanged(qint64)),this,SLOT(getduration(qint64)));
audioOutput->setVolume(0.5); //调节音频音量
QString str = "D:/Desktop/Desktop/王艳薇 - 天使亲吻过的声音.flac";
player->setSource(QUrl(str));
player->play();
4.2 播放网络歌曲
要想实现网络的播放,首先就要有网络歌曲才能行,这里测试使用的是网易云的歌曲,一方面是网易云的歌曲的api比较好找,另一方面是在之后还是需要使用到的。有了歌曲的api之后播放就比较简单了,在上面播放本地歌曲的时候可以看到在加载本地音乐文件的时候使用的类型其实是QUrl的类型,也就是说我们只需要向播放的接口传入歌曲的网络地址就可以正常的播放歌曲了。
4.3 添加歌词
要想在qt中实现播放歌曲的同时能够显示歌词,首先我们需要先知道歌词是加载的
- 内置歌词显示:有些歌曲本身有内置的歌词,是通过一些特定的工具把歌词封装到歌曲中。当你播放歌曲时,歌曲的播放软件会自动读取歌曲的内部的歌词会以文字形式显示在屏幕的特定区域,通常是在歌曲封面或播放界面的底部。
- 外部歌词文件:有些音乐文件(通常是以.mp3或其他音频格式存储的)可能包含与之关联的歌词文件,如.LRC文件。当你播放这样的音乐文件时,支持此格式的音乐播放器会自动加载相关的歌词文件并显示在屏幕上。这种方式可以让你在没有互联网连接的情况下查看歌词。
这里我们使用的是LRC歌词的外部歌词文件,LRC歌词(Lyric)是一种文本文件格式,通常用于存储歌曲的歌词文本,以便在支持LRC格式的音乐播放器中显示歌词。LRC歌词文件包含了歌曲的时间标签和相应的歌词文本,以便播放器可以根据歌曲的进度将歌词以同步的方式显示在屏幕上。
一个典型的LRC歌词文件像这样:
[00:00.00]歌曲的标题 - 歌手名
[00:10.00]第一行歌词
[00:15.00]第二行歌词
[00:20.00]第三行歌词
在上面的示例中,方括号中的内容是时间标签,用于指示歌曲的特定时间点。时间标签的格式通常是 [分钟:秒.毫秒]
。在每个时间标签之后是相应的歌词文本。
音乐播放器会读取这些时间标签,根据当前播放的歌曲进度,以同步的方式显示与时间匹配的歌词文本。这样,用户可以在听歌的同时查看歌词,更容易地跟唱或理解歌曲的歌词内容。
要想获取LRC歌词可以通过很多方式,比如从音乐的播放软件中获取或者从一些网站上获取,为了能够让歌词和歌曲能够完美的匹配上,我们这里使用的是从网易云下载歌词,因此还需要一个网易云的歌词下载工具,在github网站上找到一个可以完美下载网易云歌词的工具**MusicLyrics**,只要输入网易云的歌曲的id号就可以获取对应歌曲的歌词了。
接下来就是要qt中解析歌词了,主要要做就是读取歌词文件,然后解析歌词的文件,可以使用qt的关联式容器(QMap/QMultiMap)来存储解析到的数据,就是要把歌词的时间和对应时间的给歌词对应起来。在播放歌曲的同时获取歌词的播放进度,在上面我们测试播放歌曲的时候就已经添加上了 connect(player,SIGNAL(positionChanged(qint64)),this,SLOT(onPlayerPositionChanged(qint64)));
,这个 positionChanged(qint64)
信号量其实就是歌曲位置的信号量,然后在信号槽中在QMap中查询是否有这个时间,如果有就把这个对应时间的歌词显示出来,这样就可以实现在播放歌曲的同时显示歌词的功能了。
//歌词解析函数
QString lrc_line = getTask("http://116.206.93.242:5000/download/张德伊玲-心空.lrc");
QList lrc_list = lrc_line.split("\n");
QString lrc_time, lrc;
for(int i = 0; i < lrc_list.length(); i++)
{
lrc_time = lrc_list.at(i).split("[")[1];
lrc_time = lrc_time.split(".")[0];
lrc = lrc_list.at(i).split("]")[1];
map[lrc_time] = lrc;
}
//歌曲时间信号槽
void MainWindow::onPlayerPositionChanged(qint64 time)
{
int h,m,s;
time /= 1000; //获得的时间是以毫秒为单位的
h = time/3600;
m = (time-h*3600)/60;
s = time-h*3600-m*60;
QString loca_time = QString("%2:%3").arg(m, 2, 10, QChar('0')).arg(s, 2, 10, QChar('0'));
ui->label->setText(loca_time); //把int型转化为string类型后再设置为label的text
ui->label->setStyleSheet("color:black"); //设置字体颜色为白色
if(map.contains(loca_time))
ui->label_2->setText(map[loca_time]);
}
评论区