You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Qt/C++实现Windows 11桌面图标与壁纸间绘制窗口的问题

在Windows桌面图标与壁纸之间绘制Qt窗口的问题

问题描述

我尝试使用Qt和C++在Windows桌面的图标与壁纸之间绘制一个窗口,使其成为壁纸的一部分。编写了简化版程序,创建了一个处于非活动状态、始终在后台且不捕获输入的窗口,尺寸与位置匹配第一个屏幕:

#include <QApplication>
#include <QScreen>
#include <QWindow>
#include <Windows.h>
#include <QPainter>
#include <QMainWindow>

class MainWindow : public QMainWindow {
        Q_OBJECT
    public:
        MainWindow(QRect geometry, QWidget* parent = nullptr): QMainWindow(parent) {
            setGeometry(geometry);
            setWindowFlags(
                Qt::FramelessWindowHint |
                Qt::WindowTransparentForInput |
                Qt::WindowStaysOnBottomHint
            );
            HWND hWnd = (HWND)winId();
            LONG_PTR exStyle = GetWindowLongPtr(hWnd, GWL_EXSTYLE);
            SetWindowLongPtr(hWnd, GWL_EXSTYLE, exStyle | WS_EX_NOACTIVATE);
        }
        ~MainWindow(){}

    protected:
        void paintEvent(QPaintEvent*) {
            QPainter painter(this);
            painter.fillRect(geometry(), QColor(0, 50, 120));
        }
};

int main(int argc, char* argv[]) {
    QApplication a(argc, argv);
    MainWindow w(a.screens().at(0)->geometry());
    w.show();
    return a.exec();
}

但问题是,尽管该窗口位于所有窗口下方且允许输入穿透(包括桌面右键点击),它仍显示在桌面图标上方。

尝试的解决方案

参考相关资料后,我写出了以下获取壁纸HWND并关联Qt窗口的代码:

// 两个函数来自参考资料
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
    HWND p = FindWindowEx(hwnd, NULL, L"SHELLDLL_DefView", NULL);
    HWND* ret = (HWND*)lParam;

    if (p)
    {
        // 获取当前窗口之后的WorkerW窗口
        *ret = FindWindowEx(NULL, hwnd, L"WorkerW", NULL);
    }
    return true;
}

HWND get_wallpaper_window()
{
    // 获取Progman窗口
    HWND progman = FindWindow(L"ProgMan", NULL);
    // 向Progman发送0x052C消息,使其在桌面图标后生成WorkerW窗口(已存在则无操作)
    SendMessageTimeout(progman, 0x052C, 0, 0, SMTO_NORMAL, 1000, nullptr);
    // 枚举所有窗口,找到包含SHELLDLL_DefView子窗口的窗口,然后获取其下一个WorkerW兄弟窗口
    HWND wallpaper_hwnd = nullptr;
    EnumWindows(EnumWindowsProc, (LPARAM)&wallpaper_hwnd);
    // 返回目标窗口句柄
    return wallpaper_hwnd;
}

// 我的代码
int main(int argc, char *argv[]) {
    QApplication a(argc, argv);

    HWND wallpaper_hwnd = get_wallpaper_window();
    QWindow* wallpaper_window = QWindow::fromWinId((WId)wallpaper_hwnd);
    QWidget* wallpaper_widget = QWidget::createWindowContainer(wallpaper_window);

    MainWindow w(a.screens().at(0)->geometry(), wallpaper_widget);
    w.show();
    return a.exec();
}

但程序无视觉效果,窗口不显示但未崩溃,我怀疑错误使用了get_wallpaper_window返回的HWND。

补充信息

  • wallpaper_window的几何参数(x, y, width, height)为1200, 720, 160, 160
  • wallpaper_widget的几何参数为0, 0, 640, 480
  • 我的显示器几何参数为0, 0, 1600, 2560
  • 未关联壁纸作为父窗口的第一版代码中,点击窗口时桌面图标会短暂显示在窗口上方

后续发现

相关内容显示,我想要的实现方式可能不可行,应该子类化ListView以拦截其WM_ERASEBKGND和WM_PAINT消息,这可能无法使用Qt实现,我将研究具体方法。


内容的提问来源于stack exchange,提问作者evamiaou

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 16:49:55