动态壁纸软件开发
项目源代码在下面链接获取:
-----------------------------
开发者:CodeSharkSJ
希望此项目能加强你对Qt的应用
文章目录
- 项目图与开发环境
- 核心技术原理
- 自定义窗口程序
- UI布局
- 背景绘制
- 样式表
- 基本实现
- QWebEngine
- QMedia使用
- 系统托盘隐藏
- 记忆功能
- 应用程序打包
项目图与开发环境
开发环境: visual studio 2022 + Qt 5.14.1
项目图解:
核心技术原理
桌面图标后面有一个背景窗体,这个窗体没有名字,但是类型属于workerW
它的父类是Program Maneger,
遍历所有workerW类型的窗体,逐一比较它的父窗体是不是Program Manager就可以找到背景窗体。 但如果没有找到可以发送消息生成一个生成一个WorkerW窗体,设置为Program Manager的儿子,再在此上面播放视频。
自定义窗口程序
打开VS2022创建 [ Qt Widgets Application ]
这里Base Class(基类)你必须选择Qwidget
立即编译运行 ,能正常运行就开始下面步骤 。
鼠标无法拖动窗口
您需要添加额外的代码
1.在头文件添加两个继承的方法和一个私有的数据成员
#include <qevent.h>
protected:
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
private:
QPoint _Point;
2.实现
mousePressEvent // 鼠标按下事件
void Wallpaper::mousePressEvent(QMouseEvent* event)
{
_Point = event->globalPos() - this->pos();
}
mouseMoveEvent // 鼠标移动事件
void Wallpaper::mouseMoveEvent(QMouseEvent* event)
{
move(event->globalPos() - _Point);
}
UI布局
打开
右上角皮肤,设置,最小化 ,关闭
图标文件自行准备,在属性栏添加。
我会把项目发给你们🥝🥝
刷新率选择
60HZ设置固定(因为暂时没有120的方案)
调节音量
设置步长1,旁边是标签 设置为0
------------------------
xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>WallpaperClass</class>
<widget class="QWidget" name="WallpaperClass">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1370</width>
<height>827</height>
</rect>
</property>
<property name="windowTitle">
<string>Wallpaper</string>
</property>
<property name="windowIcon">
<iconset resource="Wallpaper.qrc">
<normaloff>:/Wallpaper/ico/Wall.png</normaloff>:/Wallpaper/ico/Wall.png</iconset>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<widget class="Line" name="line">
<property name="geometry">
<rect>
<x>0</x>
<y>40</y>
<width>1381</width>
<height>16</height>
</rect>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>131</width>
<height>21</height>
</rect>
</property>
<property name="palette">
<palette>
<active>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
</active>
<inactive>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</colorrole>
</inactive>
<disabled>
<colorrole role="WindowText">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>120</red>
<green>120</green>
<blue>120</blue>
</color>
</brush>
</colorrole>
</disabled>
</palette>
</property>
<property name="font">
<font>
<family>微软雅黑</family>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>Wallpaper</string>
</property>
</widget>
<widget class="QPushButton" name="closeBtn">
<property name="geometry">
<rect>
<x>1325</x>
<y>13</y>
<width>33</width>
<height>29</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">QPushButton#closeBtn:hover{
background-color: rgb(219, 0, 0);
color: rgb(255, 255, 255);
border-radius: 1px;
}</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="Wallpaper.qrc">
<normaloff>:/Wallpaper/MS/CLOSE.png</normaloff>:/Wallpaper/MS/CLOSE.png</iconset>
</property>
<property name="iconSize">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
<widget class="QPushButton" name="SkinBtn">
<property name="geometry">
<rect>
<x>1200</x>
<y>11</y>
<width>37</width>
<height>33</height>
</rect>
</property>
<property name="toolTip">
<string>更换主题</string>
</property>
<property name="statusTip">
<string/>
</property>
<property name="styleSheet">
<string notr="true">QPushButton#SkinBtn:hover{
background-color: rgb(90, 90,90);
color: rgb(255, 255, 255);
border-radius: 1px;
}</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="Wallpaper.qrc">
<normaloff>:/Wallpaper/MS/theme.png</normaloff>:/Wallpaper/MS/theme.png</iconset>
</property>
<property name="iconSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
<widget class="QPushButton" name="setBtn">
<property name="geometry">
<rect>
<x>1243</x>
<y>11</y>
<width>37</width>
<height>33</height>
</rect>
</property>
<property name="toolTip">
<string>更多选项</string>
</property>
<property name="statusTip">
<string/>
</property>
<property name="styleSheet">
<string notr="true">QPushButton#setBtn:hover{
background-color: rgb(90, 90,90);
color: rgb(255, 255, 255);
border-radius: 1px;
}</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
...
背景绘制
默认为黑色,点换肤按钮更换
QString tempBg = ConfigFile->value("ckbg").toString(); // 启动程序看配置文件里的背景文件名
if (tempBg != "") // 有就设置
{
startBg(tempBg);
}
else
{
QPalette pal;
pal.setColor(QPalette::Background, QColor(46, 46, 46));
this->setPalette(pal);
}
void Wallpaper::startBg(QString file)
{
QPalette pal = this->palette();
pal.setBrush(QPalette::Background, QBrush(QPixmap(file)));
setPalette(pal);
}
void Wallpaper::onSkinBtn()
{
QString tempFile = QFileDialog::getOpenFileName(this, "选择图片", "", "src(*.jpg *.png *.jpeg)"); // 选择背景图
ConfigFile->setValue("ckbg", tempFile); // 写到tempFile下次启动就加载 ini
startBg(tempFile); // 设置背景的函数
}
样式表
qss(样式表)参考了css 但是并不能像css那样炫酷。
为按钮添加样式表:
关闭:
QPushButton#closeBtn:hover{ #鼠标浮在上面的效果
background-color: rgb (219, 0, 0);
color: rgb(255, 255, 255);
border-radius: 1px;
}
最小化:
QPushButton#minBtn:hover{
background-color: rgb(90, 90,90);
color: rgb(255, 255, 255);
border-radius: 1px;
}
设置:
QPushButton#setBtn:hover{
background-color: rgb(90, 90,90);
color: rgb(255, 255, 255);
border-radius: 1px;
}
改一下颜色
color: rgb(149, 149, 149)
拉动条 :
QSlider::groove:horizontal {
border: 0px solid #bbb;
}
QSlider::sub-page:horizontal {
background: rgb(90,49,255);
border-radius: 2px;
margin-top:8px;
margin-bottom:8px;
}
QSlider::add-page:horizontal {
background: rgb(255,255, 255);
border: 0px solid #777;
border-radius: 2px;
margin-top:9px;
margin-bottom:9px;
}
QSlider::handle:horizontal {
background: rgb(193,204,208)
width: 5px;
border: 1px solid rgb(193,204,208);
border-radius: 2px;
margin-top:6px;
margin-bottom:6px;
}
QSlider::handle:horizontal:hover {
background: rgb(193,204,208);
width: 10px;
border: 1px solid rgb(193,204,208);
border-radius: 5px;
margin-top:4px;
margin-bottom:4px;
}
基本实现
😎右上角按钮实现
头文件添加槽,在构造函数内进行信号连接。
private slots:
void onCloseBtn();
void onMinBtn();
void onSetBtn();
void onSkinBtn();
构造函数内添加
connect(ui.closeBtn,SIGNAL(clicked()),this,SLOT(onCloseBtn()));
connect(ui.minBtn, SIGNAL(clicked()), this, SLOT(onMinBtn()));
connect(ui.setBtn, SIGNAL(clicked()), this, SLOT(onSetBtn()));
connect(ui.SkinBtn, SIGNAL(clicked()), this, SLOT(onSkinBtn()));
🍉closeBtn:
void Wallpaper::onCloseBtn()
{
hide(); // 隐藏用于托盘显示
//close();
}
🍎onMinBtn{ showMinimized(); }
🥰onSetBtn { /* 暂不实现 */ }
🍰onSkinBtn // 换肤
QString tempFile = QFileDialog::getOpenFileName(this, "选择图片", "", "src(*.jpg *.png *.jpeg)"); // user选择背景图
ConfigFile->setValue("ckbg", tempFile); // 写 到tempFile下次启动就加载
startBg(tempFile); // 设置背景的函数
🍊隐藏到托盘
使用#include <qsystemtrayicon.h> 实现
定义数据成员 在头文件 QSystemTrayIcon* systemtrayicon;
由于有大量的弹出菜单,我们把弹出菜单的需要的东西封在initSpecific()
void Wallpaper::initSpecific()
{
systemtrayicon = new QSystemTrayIcon(QIcon(":/Wallpaper/ico/Wall.png"));
systemtrayicon->setToolTip(("动态壁纸:运行中"));
systemtrayicon->show();
QMenu* tray_Menu = new QMenu(this);
/*托盘弹出的菜单*/
QAction* action1 = new QAction("显示主界面");
QAction* action2 = new QAction("退出壁纸");
tray_Menu->setStyleSheet("background-color: rgb(92,92,92);");
tray_Menu->addAction(action1);
tray_Menu->addSeparator();
tray_Menu->addAction(action2);
systemtrayicon->setContextMenu(tray_Menu); // 放入
connect(action1, SIGNAL(triggered(bool)), this, SLOT(onAction1())); // 注意信号
connect(action2, SIGNAL(triggered(bool)), this, SLOT(onAction2()));
}
🥰主界面切换
三个按钮
三按钮槽函数
private slots:
void onInstalledBtn();
void onDiscovBtn();
void onMoberBtn();
void Wallpaper::onInstalledBtn()
{
ui.stackedWidget->setCurrentIndex(0);
}
void Wallpaper::onDiscovBtn()
{
ui.stackedWidget->setCurrentIndex(1);
}
void Wallpaper::onMoberBtn()
{
ui.stackedWidget->setCurrentIndex(2);
}
// 默认在你设计后停留的页面
🥩拉动条
void Wallpaper::onSliderSetNum(int num)
{
ui.valuseShow->setText(QString::number(num)); //拉动了就设置旁边的标签
mediaPlayer->setVolume(num); // 根据标签设置音量 这个mediaPlayer后面会写
}
connect(ui.vloueQSlider, SIGNAL(valueChanged(int)), SLOT(onSliderSetNum(int))); // 当进度条拉动 valueChanged发射信号
QWebEngine使用
显示网页
#include <QWebEngineView>
// 网址
ui.webEngineView->load(QUrl("https://www.pgyer.com/0uTR"));
把这个放在界面上
QMedia使用
#include <QMediaPlayer>
#include <QMediaPlaylist> // 播放列表 用于循环播放
#include <QVideoWidget> // 播放视频的窗口
QVideoWidget* videoWidget;
QMediaPlayer* mediaPlayer;
QMediaPlaylist* Videolist;
Videolist = new QMediaPlaylist;
mediaPlayer = new QMediaPlayer;
videoWidget = new QVideoWidget;
谈一谈这个按钮,按下后选择视频,并在桌面显示出来😎
先来个查找的工具,用于杀死视频窗口,不然释放
QVideoWidget还是会播放。
工具:
#include <Windows.h>
//获取背景窗体句柄
HWND GetBackground() {
//背景窗体没有窗体名,但是知道它的类名是workerW,且有父窗体Program Maneger,所以只要
//遍历所有workerW类型的窗体,逐一比较它的父窗体是不是Program Manager就可以找到背景窗体
HWND hwnd = FindWindowA("progman", "Program Manager");
HWND worker = NULL;
do {
worker = FindWindowExA(NULL, worker, "workerW", NULL); // 根据类名获取窗体句柄
if (worker != NULL) {
char buff[200] = { 0 };
int ret = GetClassNameA(worker, (PCHAR)buff, sizeof(buff) * 2);
if (ret == 0) {
return NULL;
}
}
if (GetParent(worker) == hwnd) {
return worker;//返回结果
}
} while (worker != NULL);
//没有找到
//发送消息生成一个WorkerW窗体
SendMessage(hwnd, 0x052C, 0, 0);
//重复上面步骤
do {
worker = FindWindowExA(NULL, worker, "workerW", NULL);
if (worker != NULL) {
char buff[200] = { 0 };
int ret = GetClassNameA(worker, (PCHAR)buff, sizeof(buff) * 2);
if (ret == 0) {
return NULL;
}
}
if (GetParent(worker) == hwnd) {
return worker;//返回结果
}
} while (worker != NULL);
return NULL;
}
void SetBackground(HWND child) {
SetParent(child, GetBackground()); // 把视频窗口设置为Program Manager的儿子
}
🤪按钮的实现
void onGetVideo(); // 槽
connect(ui.getVideo, SIGNAL(clicked()), this, SLOT(onGetVideo()));
void Wallpaper::onGetVideo()
{
if (isPlay == false) // 判断是否有过视频窗口
{
QString file;
file = QFileDialog::getOpenFileName(this, "选择图片或视频", "", "src(*.mp4)");
ConfigFile->setValue("videos", file); // 写入配置文件
isPlay = true; // 现在有了
showVoide(file); // 放视频具体操作
}
else
{
// 不创建窗口模式 直接设置播放列表里面的视频
mediaPlayer->stop();
QString file;
file = QFileDialog::getOpenFileName(this, "选择图片或视频", "", "src(*.mp4)");
ConfigFile->setValue("videos", file);
NextVideo(file); // 启动下一个视频
}
return;
}
showVoide
void Wallpaper::showVoide(QString Name)
{
HWND hwnd = (HWND)videoWidget->winId(); //获取播放视频的窗口id
SetBackground(hwnd);
videoWidget->setWindowFlags(Qt::FramelessWindowHint); // // 隐藏标题栏
videoWidget->showFullScreen(); // 最大化显示
/*
this->windowClose = tempWork; //获取子窗口id后面用来关闭
2023年1月29日21:30:01 发现bug 这段代码是直接关了系统背景资源管理器会崩溃
*/
this->windowClose = hwnd; // 到时候直接杀播放视频的窗口就行了 但会留下壁纸
// mediaPlayer为播放控制器 用于启动播放 Videolist是播放列表
Videolist->addMedia(QMediaContent(QUrl::fromLocalFile(Name)));// 设置要播放的文件路径
Videolist->setCurrentIndex(0);
Videolist->setPlaybackMode(QMediaPlaylist::Loop); // 循环
mediaPlayer->setVideoOutput(videoWidget); // 设置视频输出窗口
mediaPlayer->setPlaylist(Videolist);
mediaPlayer->play();
}
NextVideo
void Wallpaper::NextVideo(QString Name)
{
Videolist->clear();
Videolist->addMedia(QMediaContent(QUrl::fromLocalFile(Name)));
mediaPlayer->play();
}
记忆功能
程序启动时检查配置文件,进行响应的调度 。
QSettings可以提供方便的ini配置操作
#include <QSettings>
QString GetAPPDATAFolder()
{
wchar_t path[255] = { 0 };
SHGetSpecialFolderPath(
NULL,
path,
CSIDL_APPDATA,
FALSE
);
QString rlt = QString::fromWCharArray(path);
return rlt;
}
QString folder = GetDesktopFolder(); //获取用户数据文件夹 一般配置文件放里面
folder.append("\\Wallpaper_user.ini");
ConfigFile = new QSettings(folder, QSettings::IniFormat);
ConfigFile->beginGroup("USERRCONFIG"); // 节点名
QString tempBg = ConfigFile->value("ckbg").toString(); // 读这个ckbg下的数据
// ConfigFile->setValue("ckbg", tempFile); // 写
// 加载上次设置的视频
QString tempVid = ConfigFile->value("videos").toString();
if (tempVid != "")
{
if (isPlay == false)
{
isPlay = true;
showVoide(tempVid);
}
}
应用程序打包
如何在让程序在别的计算机执行
一、使用这个工具
找不到用Everything 搜。
选Release 和 x64 编译
打开终端程序,进入程序所在目录
输入
windeployqt D:\local\Wallpaper.exe
会自动加载所需。
二、Enigma Virtual Box
虚拟目录
使一些dll和其他文件隐藏,只有exe程序。
---------------------------------------------------------
由于没有使用MD编辑文章,观感可能不舒服,请见谅。
有问题私信
------------------------------------------------------------
源代码:
链接:https://pan.baidu.com/s/1-HUPkdniFPPHUJ2B8AC0wQ?pwd=sjfd
提取码:sjfd