Qt-based animation character display to replace desktop wallpaper

I have been learning qt for a while, and I just have time to write a blog today.

Project Introduction

Write a software to display anime girls (picture resources found online)
The effect is as follows


It is not difficult to realize the principle. Briefly describe your ideas. The tools are built with vs2022 cmake

A main window removes the border, makes the window transparent and supports dragging. The rest is to beautify the interface with qss (to be honest, beautification is much more convenient than mfc, and the interface is friendly).

Finally, the soft code is attached. Those who are interested can compile and run it by themselves. The environment used by the current project is QT5. Just change the qt path when compiling.

Code Display

Main program code

#include "MyDesktopSoft.h"
#include "eventfilterobject.h"
#include <QResizeEvent>
#include <QTimer>
#include <QFile>
MyDesktopSoft::MyDesktopSoft(QWidget *parent):QWidget(parent)
{<!-- -->

this->init_ui();
}

void MyDesktopSoft::updateRoleModelAnimation()
{<!-- -->
m_frames = m_roleModels[m_currentRole].size();
m_roleModelLabel->setPixmap(m_roleModels[m_currentRole][m_index]);
\t
m_index = (m_index + 1) % m_frames;
}

void MyDesktopSoft::init_ui()
{<!-- -->
setFixedSize(350, 640);
setWindowFlag(Qt::FramelessWindowHint); //Cancel window border
setWindowFlag(Qt::WindowStaysOnTopHint);//window on top
setAttribute(Qt::WA_TranslucentBackground);//window background transparent
installEventFilter(new eventFilterObject(this)); // capture window drag

//Add character resources
RoleModel roleModel;
for (int i = 0; i < 6; i ++ ) {<!-- -->
roleModel.addFrame(QString(":/assets/desktopRole/blackGril/action1-happy/%1.png").arg(i));
}
m_roleModels.insert("blackGril/happy", roleModel);

roleModel. clear();
for (int i = 0; i < 6; i ++ ) {<!-- -->
roleModel.addFrame(QString(":/assets/desktopRole/blackGril/action2-sad/%1.png").arg(i));
}
m_roleModels.insert("blackGril/sad", roleModel);

roleModel. clear();
for (int i = 0; i < 6; i ++ ) {<!-- -->
roleModel.addFrame(QString(":/assets/desktopRole/blackGril/action3-naughty/%1.png").arg(i));
}
m_roleModels.insert("blackGril/naughty", roleModel);


roleModel. clear();
for (int i = 0; i < 6; i ++ ) {<!-- -->
roleModel.addFrame(QString(":/assets/desktopRole/blackGril/action4-shy/%1.png").arg(i));
}
m_roleModels.insert("blackGril/shy", roleModel);


roleModel. clear();
for (int i = 0; i < 6; i ++ ) {<!-- -->
roleModel.addFrame(QString(":/assets/desktopRole/littleBoy/%1.png").arg(i));
}
m_roleModels.insert("littleBoy", roleModel);

roleModel. clear();
for (int i = 0; i < 6; i ++ ) {<!-- -->
roleModel.addFrame(QString(":/assets/desktopRole/summerGril/%1.png").arg(i));
}
m_roleModels.insert("summerGril", roleModel);



m_roleModelLabel = new QLabel(this);
m_wallpaper = new Wallpaper;
\t
QTimer* timer = new QTimer(this);
timer->callOnTimeout(this, &MyDesktopSoft::updateRoleModelAnimation);
timer->start(600);

m_currentRole = "summerGril"; // is summerGril by default
updateRoleModelAnimation();

m_closeBtn = new QPushButton(this);
m_settingBtn = new QPushButton(this);

m_closeBtn->move(240, 300);
m_settingBtn->move(240, 340);
m_closeBtn->setObjectName("closeBtn");
m_settingBtn->setObjectName("settingBtn");

QFile file(":/assets/style.css");
if (file.open(QIODevice::ReadOnly)) {<!-- -->
this->setStyleSheet(file. readAll());
}
m_setting = new Setting;
connect(m_closeBtn, &QPushButton::released, this, &MyDesktopSoft::close);
connect(m_settingBtn, &QPushButton::released, m_setting, &QWidget::show);

//When the main interface is closed, notify the attached interface to close
connect(m_closeBtn, &QPushButton::released, m_setting, &QWidget::close);

//The subsidiary interface sends a message to the main interface, the model has been changed
\t
connect(m_setting, & amp;Setting::roleModelChanged, this, [=](const QString & amp; role) {<!-- -->
m_currentRole = role;
});

connect(m_setting, &Setting::wallpaperChanged, m_wallpaper, &Wallpaper::setWallpaper);
}

MyDesktopSoft::~MyDesktopSoft()
{<!-- -->

//The applied pointers must be released at the end
if (m_setting) {<!-- -->
delete m_setting;
}
if (m_closeBtn) {<!-- -->
delete m_closeBtn;
}
if (m_settingBtn) {<!-- -->
delete m_settingBtn;
}
if (m_roleModelLabel) {<!-- -->
delete m_roleModelLabel;
}
if (m_wallpaper) {<!-- -->
delete m_wallpaper;
}

}

void MyDesktopSoft::resizeEvent(QResizeEvent* ev)
{<!-- -->
\t
m_roleModelLabel->resize(ev->size());

}

void MyDesktopSoft::mousePressEvent(QMouseEvent* ev)
{<!-- -->


if (ev->button() == Qt::MouseButton::RightButton) {<!-- -->
m_closeBtn->setVisible(!m_closeBtn->isVisible());
m_settingBtn->setVisible(!m_settingBtn->isVisible());
}
\t


}

Response to mouse drag code fragment

#include "eventfilterobject.h"
#include <QMouseEvent>
#include<QWidget>
eventFilterObject::eventFilterObject(QObject *parent) : QObject(parent)
{<!-- -->

}

bool eventFilterObject::eventFilter(QObject *watched, QEvent *ev)
{<!-- -->
    auto* mouseEv = static_cast<QMouseEvent*>(ev);
    static QPoint dis;
    if(ev->type() == QEvent::MouseButtonPress)
    {<!-- -->
        dis = mouseEv->pos();
    }
    else if(ev->type() == QEvent::MouseMove & amp; & amp; mouseEv->buttons() & amp; Qt::LeftButton
             & amp; & amp; !dis.isNull())
    {<!-- -->
        auto *pthis = static_cast<QWidget*>(watched);
        //if(pthis->parent()==nullptr)
        pthis->move(mouseEv->globalPos() - dis);
        //pthis->move(pthis->mapToParent(mouseEv->pos()) - dis);
    }
    else if(ev->type() == QEvent::MouseButtonRelease)
    {<!-- -->
        dis = QPoint();
    }
    return false;
}

Find the top-level window class

head File

#ifndef FINDDEKTOPHWND_H
#define FINDDEKTOPHWND_H
#include <qt_windows.h>
class QWidget;
class FindDektopHwnd
{<!-- -->
public:
    FindDektopHwnd();
    static BOOL CALLBACK EnumWindowsProc(_In_ HWND tophandle, _In_ LPARAM topparamhandle);
    /*
    * @return returns the desktop handle
    */
    static HWND GetDesktopHandle();

    /**
     * @param child is the control that needs to be set as a child window.
     * @param parent is empty, then set child as the child of the desktop, otherwise set it as the child of parent
     */
    static void SetParent(QWidget*child, HWND parent);

    inline static HWND _workerw = NULL;
};

#endif // FINDDEKTOPHWND_H

cpp file

#include "finddektophwnd.h"
#include<QWidget>
FindDektopHwnd::FindDektopHwnd()
{<!-- -->

}

BOOL CALLBACK FindDektopHwnd::EnumWindowsProc(_In_ HWND tophandle, _In_ LPARAM topparamhandle)
{<!-- -->
    HWND defview = FindWindowExW(tophandle, 0, L"SHELLDLL_DefView", NULL);
    if (defview != NULL)
    {<!-- -->
        _workerw = FindWindowExW(0, tophandle, L"WorkerW", 0);
    }
    return true;
}//Callback function for traversing handles

HWND FindDektopHwnd::GetDesktopHandle()
{<!-- -->
    ULONG_PTR result;
    HWND windowHandle = FindWindowW(L"Progman", NULL);
    SendMessageTimeout(windowHandle, 0x052c, 0, 0, SMTO_NORMAL, 0x3e8, (PDWORD_PTR) &result);
    EnumWindows(EnumWindowsProc, (LPARAM)NULL);
    ShowWindow(_workerw, SW_HIDE);
    return windowHandle;
}

void FindDektopHwnd::SetParent(QWidget *child, HWND parent)
{<!-- -->
    HWND dekstopHwnd = parent;
    if(parent == nullptr)
    {<!-- -->
        //Get the window handle of the desktop
        dekstopHwnd = FindDektopHwnd::GetDesktopHandle();
    }

    //Set dekstopHwnd as the parent object
    ::SetParent((HWND)child->winId(),(HWND)dekstopHwnd);
}


Underneath are some trivial processing events

Alas, the rest of the code will not be shown one by one, all of them are in the attachment. If you need it, you can mention it yourself