参考
功能
- 桌面挂件动画置顶
- 切换挂件动画
- 图片选择更换桌面壁纸
- 显示时改变桌面壁纸,隐藏/退出时还原桌面壁纸
- 系统托盘菜单,可选择开/关悬浮挂件功能按键
- 悬浮挂件功能按键随鼠标区域显示/隐藏
实现
05DesktopPattern.pro
链接 user32 Advapi32库
# 对于 Windows 平台,GetDesktopWindow 函数位于 user32.lib 库
LIBS += -luser32 -lAdvapi32
main.cpp
#include "desktoppattern.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
DesktopPattern w;
w.show();
return a.exec();
}
desktoppattern.h
#ifndef DESKTOPPATTERN_H
#define DESKTOPPATTERN_H
#include <QWidget>
#include <QTimer>
#include <QLabel>
#include <QDebug>
#include <QPushButton>
#include <QGraphicsDropShadowEffect>
#include <QEvent>
#include <QMouseEvent>
#include <QFileDialog>
#include <QApplication>
#include <QSystemTrayIcon> // 将窗口嵌入到系统托盘
#include <QMenu>
#include "wallpaper.h"
class DesktopPattern : public QWidget
{
Q_OBJECT
public:
DesktopPattern(QWidget *parent = nullptr);
~DesktopPattern();
bool eventFilter(QObject *watched,QEvent *ev) override;
void setVisible(bool visible)override;
void initButton();
void showButton();
void hideButton();
void initWindowToSystemTray();// 初始化系统托盘
public slots:
void updateRoleAnimation();// 更新角色动画
private:
QLabel* roleLabel;
qint8 curFrame; //当前帧
qint8 curPath; //当前路径
QList<QString> pathList;
bool timerRunning = false;// 在类中添加一个标志变量
bool hoverChoose = true; // 悬浮选择按钮开关
QPushButton* closeBtn;
QPushButton* cutBtn;
QPushButton* openBtn;
QSystemTrayIcon *trayIcon; // 系统托盘
Wallpaper *mWallpaper;
QString wallpaperPath; // 替换为你的壁纸文件路径
};
#endif // DESKTOPPATTERN_H
desktoppattern.cpp
#include "desktoppattern.h"
DesktopPattern::DesktopPattern(QWidget *parent)
: QWidget(parent)
{
//setWindowFlags(Qt::FramelessWindowHint);// 无窗口的边框,
//窗口将始终显示在其他窗口之上
setWindowFlags(Qt::Window | Qt::WindowStaysOnTopHint|Qt::FramelessWindowHint);
setAttribute(Qt::WA_TranslucentBackground);// 背景透明 属性
setWindowIcon(QIcon(":/resource/icon.ico"));
curFrame=0;
curPath = 0; //当前路径
pathList.append("background-image:url(:/resource/desktopRole/summerGril/%1.png);");
pathList.append("background-image:url(:/resource/desktopRole/littleBoy/%1.png);");
pathList.append("background-image:url(:/resource/desktopRole/blackGril/action1-happy/%1.png);");
pathList.append("background-image:url(:/resource/desktopRole/blackGril/action2-sad/%1.png);");
pathList.append("background-image:url(:/resource/desktopRole/blackGril/action3-naughty/%1.png);");
pathList.append("background-image:url(:/resource/desktopRole/blackGril/action4-shy/%1.png);");
// 定时器更新角色动画
QTimer *updateTimer = new QTimer(this);
updateTimer->callOnTimeout(this,&DesktopPattern::updateRoleAnimation);
updateTimer->start(500);
roleLabel = new QLabel(this);
roleLabel->resize(500, 500);
//给窗口设置阴影
QGraphicsDropShadowEffect * effect=new QGraphicsDropShadowEffect(this);
effect->setColor(QColor(230,231,232,220));
effect->setBlurRadius(5);// 设置模糊半径
this->setGraphicsEffect(effect);
this->installEventFilter(this);// 安装事件过滤器
initButton();
initWindowToSystemTray();
mWallpaper = new Wallpaper();
}
DesktopPattern::~DesktopPattern()
{
if(mWallpaper)
delete mWallpaper;
}
bool DesktopPattern::eventFilter(QObject *watched, QEvent *ev)
{
if (/*watched == this && */ev->type() == QEvent::Enter) {
// 鼠标进入窗口时执行的操作
showButton();
} else if (/*watched == this &&*/ ev->type() == QEvent::Leave) {
// 鼠标离开窗口时执行的操作
if (!timerRunning) {
timerRunning = true;
QTimer::singleShot(3000,this,&DesktopPattern::hideButton);
}
}
QMouseEvent *mouseEv=static_cast<QMouseEvent*>(ev);
static QPoint beginPos;
if(ev->type()==QEvent::MouseButtonPress) // 事件为 鼠标按下
{
beginPos = mouseEv->globalPos()-this->pos();
}
else if(ev->type()==QEvent::MouseMove && mouseEv->buttons()&Qt::MouseButton::LeftButton)
{// 事件为 鼠标移动 && 鼠标是左键
this->move(mouseEv->globalPos()-beginPos);
}
return QObject::eventFilter(watched, ev);
}
void DesktopPattern::setVisible(bool visible)
{
if(visible){
if(mWallpaper)
mWallpaper->setPixmap(wallpaperPath);
qDebug() << " ";
}
else {
if(mWallpaper)
mWallpaper->hide();
}
QWidget::setVisible(visible);
}
void DesktopPattern::initButton()
{
closeBtn = new QPushButton(this);
cutBtn= new QPushButton(this);
openBtn= new QPushButton(this);
closeBtn->setGeometry(320, 200, 36, 36);
cutBtn->setGeometry(320, 240, 36, 36);
openBtn->setGeometry(320, 280, 36, 36);
closeBtn->setObjectName("closeBtn");
cutBtn->setObjectName("cutBtn");
closeBtn->setStyleSheet("background-image:url(:/resource/button/quit.png);background-repeat:no-repeat;");
cutBtn->setStyleSheet("background-image:url(:/resource/button/cut.png);background-repeat:no-repeat;");
openBtn->setStyleSheet("background-image:url(:/resource/button/open.png);background-repeat:no-repeat;");
this->setStyleSheet("QPushButton{border:none;border-radius:5px;background-color:rgb(64,173,250)}\
QPushButton#closeBtn:hover{background-color:rgb(233,31,48);}\
QPushButton#cutBtn:hover{background-color:rgb(200,150,100);}");
hideButton();
connect(closeBtn,&QPushButton::pressed,this,&DesktopPattern::hide);
connect(cutBtn,&QPushButton::pressed,this,[=](){
curPath=(curPath+1)%pathList.count();
});
connect(openBtn,&QPushButton::pressed,this,[=](){
QString filename = QFileDialog::getOpenFileName(nullptr,"选择壁纸","./","Image(*jpg *png)");
if(filename.isEmpty())
return;
mWallpaper->setPixmap(filename);
wallpaperPath= filename;
});
closeBtn->installEventFilter(this);
cutBtn->installEventFilter(this);
openBtn->installEventFilter(this);
closeBtn->setToolTip("关闭");
cutBtn->setToolTip("切换");
openBtn->setToolTip("壁纸");
}
void DesktopPattern::showButton()
{
if(!hoverChoose)
return;
closeBtn->show();
cutBtn->show();
openBtn->show();
}
void DesktopPattern::hideButton()
{
closeBtn->hide();
cutBtn->hide();
openBtn->hide();
timerRunning = false;
}
// 初始化系统托盘
void DesktopPattern::initWindowToSystemTray()
{
trayIcon = new QSystemTrayIcon(this);
trayIcon->setIcon(QIcon(":/resource/icon.ico"));
trayIcon->setToolTip("桌面挂件动画");
QMenu *trayMenu = new QMenu(this);
QAction *hoverChooseAction = new QAction("HoverChoose", this);
QAction *showAction = new QAction("Show", this);
QAction *hideAction = new QAction("Hide", this);
QAction *quitAction = new QAction("Quit", this);
hoverChooseAction->setIcon(QIcon(":/resource/button/radio_btn_checked.png"));
showAction->setIcon(QIcon(":/resource/button/sub.png"));
hideAction->setIcon(QIcon(":/resource/button/quit.png"));
quitAction->setIcon(QIcon(":/resource/button/shut.png"));
trayMenu->addAction(hoverChooseAction);
trayMenu->addAction(showAction);
trayMenu->addAction(hideAction);
trayMenu->addAction(quitAction);
QString styleSheet = "QMenu{background-color: black;}\
QMenu::item {color: white;}\
QMenu::item:selected {color: yellow;}";
trayMenu->setStyleSheet(styleSheet);//设置菜单背景色为黑色、字体颜色为白色、选中项字体颜色为黄色
trayIcon->setContextMenu(trayMenu);
connect(hoverChooseAction, &QAction::triggered, this, [=](){
hoverChoose=!hoverChoose;
if(hoverChoose)
hoverChooseAction->setIcon(QIcon(":/resource/button/radio_btn_checked.png"));
else
hoverChooseAction->setIcon(QIcon(":/resource/button/radio_btn_normal.png"));
});
connect(showAction, &QAction::triggered, this, &DesktopPattern::show);
connect(hideAction, &QAction::triggered, this, &DesktopPattern::hide);
//connect(quitAction, &QAction::triggered, qApp, QApplication::quit);
connect(quitAction, &QAction::triggered, qApp, [=](){
// 在应用程序关闭前执行
setVisible(false);
QApplication::quit();
});
// 显示系统托盘图标
trayIcon->show();
}
void DesktopPattern::updateRoleAnimation()
{
QString qss("background-repeat:no-repeat;");// 关闭重复平铺
roleLabel->setStyleSheet(qss+pathList.at(curPath).arg(curFrame));
curFrame= (curFrame+1)%6;
}
wallpaper.h
#ifndef WALLPAPER_H
#define WALLPAPER_H
#include <QWidget>
#include <QLabel>
#include <QFile>
#include <QPixmap>
#include <QHBoxLayout>
#include<qt_windows.h>
#include <Windows.h>
#include<QDebug>
class Wallpaper : public QWidget
{
Q_OBJECT
public:
explicit Wallpaper(QWidget *parent = nullptr);
~Wallpaper();
void setAllWallpaper();
void restoreAllWallpaper(); // 还原壁纸
QString getOriginalWallpaperPath();// 获取原壁纸
void setPixmap(const QString& fileName);
void setVisible(bool visible)override;
private:
QLabel* bkLabel; //放壁纸
QPixmap bkPixmap;
QString originalWallpaperPath; // 替换为你保存原始壁纸路径的变量
QString wallpaperPath; // 替换为你的壁纸文件路径
signals:
};
#endif // WALLPAPER_H
wallpaper.cpp
#include "wallpaper.h"
Wallpaper::Wallpaper(QWidget *parent)
: QWidget{parent}
{
setWindowFlags(Qt::FramelessWindowHint);// 无窗口的边框
setAttribute(Qt::WA_TranslucentBackground);// 属性为透明
bkLabel = new QLabel(this);
QHBoxLayout *horizon=new QHBoxLayout(this);
horizon->setMargin(0);// 边界
horizon->addWidget(bkLabel);
originalWallpaperPath=getOriginalWallpaperPath();
// setPixmap(":/resource/wallpaper/1.jpg");
// setAllWallpaper();
}
Wallpaper::~Wallpaper()
{
}
void Wallpaper::setAllWallpaper()
{
#if 0
//找到桌面的句柄(标识)
// TCHAR className[MAX_PATH];
// GetClassName(GetDesktopWindow(), className, MAX_PATH);
// HWND desktopHwnd = FindWindow(className, nullptr);
HWND desktopHwnd = GetDesktopWindow();
if (!desktopHwnd)
{
qDebug() << "查找失败"<< desktopHwnd;
return;
}
//把this设置给找到的窗口
SetParent((HWND)this->winId(),desktopHwnd);
#endif
}
// 还原壁纸
void Wallpaper::restoreAllWallpaper()
{
// 在应用程序关闭之前将 originalWallpaperPath 设置为原始壁纸的路径
// 应用程序关闭时恢复原始壁纸
if (!SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, (PVOID)originalWallpaperPath.utf16(), SPIF_UPDATEINIFILE | SPIF_SENDCHANGE))
{
qDebug() << "还原壁纸失败";
return;
}
qDebug() << "还原壁纸成功"<<originalWallpaperPath;
}
// 获取原壁纸
QString Wallpaper::getOriginalWallpaperPath()
{
wchar_t wallpaperPath[MAX_PATH];
if (SystemParametersInfoW(SPI_GETDESKWALLPAPER, MAX_PATH, wallpaperPath, 0))
{
return QString::fromWCharArray(wallpaperPath);
}
return QString();
}
void Wallpaper::setPixmap(const QString &fileName)
{
#if 0
if(QPixmap(fileName).isNull())
return;
bkPixmap.load(fileName);
bkLabel->setPixmap(bkPixmap);
this->hide();
this->showFullScreen();// 全屏显示
#endif
if(!QFile(fileName).exists())
return;
wallpaperPath = fileName;
if (!SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, (PVOID)wallpaperPath.utf16(), SPIF_UPDATEINIFILE | SPIF_SENDCHANGE))
{
qDebug() << "更改壁纸失败";
return;
}
qDebug() << "更改壁纸成功"<<wallpaperPath;
}
void Wallpaper::setVisible(bool visible)
{
if(visible)
{
qDebug() << "壁纸显示";
}
else
restoreAllWallpaper();
QWidget::setVisible(visible);
}
效果
模糊知识点
- 系统托盘应用
#include <QSystemTrayIcon>
#include <QMenu>
trayIcon = new QSystemTrayIcon(this);
trayIcon->setIcon(QIcon("xxx"));
trayIcon->setToolTip("xxx");
QMenu *trayMenu = new QMenu(this);
QAction *hoverChooseAction = new QAction("HoverChoose", this);
trayMenu->addAction(hoverChooseAction);
trayIcon->setContextMenu(trayMenu);
trayIcon->show();
- 当应用程序接收到
quitAction
的触发信号后,会调用QApplication::quit()
来退出应用程序。因此,在退出之前,可能没有足够的时间来执行setVisible(bool visible)
方法。
如果你希望在应用程序退出之前执行一些操作,可以绑定使用 aboutToQuit
信号,该信号在应用程序即将退出时发出
connect(qApp, &QApplication::aboutToQuit, this, [=](void){ });
SystemParametersInfoW
是Windows API
的函数
SystemParametersInfoW(
_In_ UINT uiAction,
_In_ UINT uiParam,
_Pre_maybenull_ _Post_valid_ PVOID pvParam,
_In_ UINT fWinIni);
`uiAction`:表示要执行的操作,可以是以下之一:
SPI_SETDESKWALLPAPER :设置桌面壁纸。
其他例如 SPI_SETICONMETRICS、SPI_SETKEYBOARDDELAY 等用于设置其他系统参数的标识符。
`uiParam`:取决于 uiAction 的值,通常用于传递额外的参数信息。比如,如果 uiAction 是 SPI_SETDESKWALLPAPER,那么 uiParam 可以是 0 或者其他与壁纸设置相关的参数。
`pvParam`:是一个指向参数数据的指针。具体取决于 uiAction 的值以及所需参数类型。例如,如果 uiAction 是 SPI_SETDESKWALLPAPER,那么 pvParam 应该是指向壁纸文件路径的指针。
`fWinIni`:是一个标志,指示是否应更新用户配置文件中的设置并通知系统更改。可以使用以下标志之一或它们的组合:
SPIF_UPDATEINIFILE:将更改写入用户配置文件(如 INI 文件)。
SPIF_SENDCHANGE:在更改后立即向其它组件发送系统更改通知。
// 设置桌面壁纸
QString wallpaperPath="xxx";
SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, (PVOID)wallpaperPath.utf16(), SPIF_UPDATEINIFILE | SPIF_SENDCHANGE)
// 获取桌面壁纸路径
wchar_t wallpaperPath[MAX_PATH];
if (SystemParametersInfoW(SPI_GETDESKWALLPAPER, MAX_PATH, wallpaperPath, 0))
{
return QString::fromWCharArray(wallpaperPath);
}