如何在Windows 10上实现类似于Fluent Design指南的模糊半透明QML窗口?

4

我想在Windows 10中使用QML创建一个半透明模糊的窗口,类似于Fluent设计指南(示例)。我知道可以创建透明窗口:

Window{
    visible: true
    color: "transparent"
}

但是这并没有达到我想要的模糊效果。我知道可以使用QtGraphicalEffects中的FastBlur来模糊窗口内的元素,但我想要模糊整个窗口本身。 有没有方法可以实现这一点? 我也尝试使用QtWinExtras模块并调用QtWin::enableBlurBehindWindow,但这也不起作用:

    QObject *root = engine.rootObjects()[0];
    QQuickWindow *window = qobject_cast<QQuickWindow *>(root);
    if (!window) {
        qFatal("Error: Your root item has to be a window.");
        return -1;
    }
    QtWin::enableBlurBehindWindow(window);

也许这个链接可以帮助你解决问题:https://forum.qt.io/topic/51055/enableblurbehindwindow-not-working/3 - BrutalWizard
那似乎适用于QWidgets和QWindows。 - reckless
这是您期望的吗?(它可以更模糊或更透明) - BrutalWizard
不是的,我认为你所做的是将窗口设置为透明,并在其上应用了一个带有渐变的半透明矩形。我正在寻找微软所称的“亚克力材质”。 - reckless
1个回答

5

好的,我找到了一个比我想象中更容易的解决方案。官方微软没有提供API来实现我所需要的功能。我偶然看到了这个帖子,然后发现了这个。从那里,我根据我的需求修改了代码,创建了一个包含以下内容的头文件:

#ifndef STRUCTS_H
#define STRUCTS_H
#include <windef.h>
#pragma once

typedef enum _WINDOWCOMPOSITIONATTRIB
{
    WCA_UNDEFINED = 0,
    WCA_NCRENDERING_ENABLED = 1,
    WCA_NCRENDERING_POLICY = 2,
    WCA_TRANSITIONS_FORCEDISABLED = 3,
    WCA_ALLOW_NCPAINT = 4,
    WCA_CAPTION_BUTTON_BOUNDS = 5,
    WCA_NONCLIENT_RTL_LAYOUT = 6,
    WCA_FORCE_ICONIC_REPRESENTATION = 7,
    WCA_EXTENDED_FRAME_BOUNDS = 8,
    WCA_HAS_ICONIC_BITMAP = 9,
    WCA_THEME_ATTRIBUTES = 10,
    WCA_NCRENDERING_EXILED = 11,
    WCA_NCADORNMENTINFO = 12,
    WCA_EXCLUDED_FROM_LIVEPREVIEW = 13,
    WCA_VIDEO_OVERLAY_ACTIVE = 14,
    WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15,
    WCA_DISALLOW_PEEK = 16,
    WCA_CLOAK = 17,
    WCA_CLOAKED = 18,
    WCA_ACCENT_POLICY = 19,
    WCA_FREEZE_REPRESENTATION = 20,
    WCA_EVER_UNCLOAKED = 21,
    WCA_VISUAL_OWNER = 22,
    WCA_HOLOGRAPHIC = 23,
    WCA_EXCLUDED_FROM_DDA = 24,
    WCA_PASSIVEUPDATEMODE = 25,
    WCA_LAST = 26
} WINDOWCOMPOSITIONATTRIB;

typedef struct _WINDOWCOMPOSITIONATTRIBDATA
{
    WINDOWCOMPOSITIONATTRIB Attrib;
    PVOID pvData;
    SIZE_T cbData;
} WINDOWCOMPOSITIONATTRIBDATA;

typedef enum _ACCENT_STATE
{
    ACCENT_DISABLED = 0,
    ACCENT_ENABLE_GRADIENT = 1,
    ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
    ACCENT_ENABLE_BLURBEHIND = 3,
    ACCENT_ENABLE_ACRYLICBLURBEHIND = 4, // RS4 1803
    ACCENT_ENABLE_HOSTBACKDROP = 5, // RS5 1809
    ACCENT_INVALID_STATE = 6
} ACCENT_STATE;

typedef struct _ACCENT_POLICY
{
    ACCENT_STATE AccentState;
    DWORD AccentFlags;
    DWORD GradientColor;
    DWORD AnimationId;
} ACCENT_POLICY;

typedef BOOL (WINAPI *pfnGetWindowCompositionAttribute)(HWND, WINDOWCOMPOSITIONATTRIBDATA*);

typedef BOOL (WINAPI *pfnSetWindowCompositionAttribute)(HWND, WINDOWCOMPOSITIONATTRIBDATA*);
#endif // STRUCTS_H

然后在我的main.cpp文件中:

#ifdef Q_OS_WIN
#include <QQuickWindow>
#include <windows.h>
#include <WinUser.h>
#include "structs.h" // my header file
#endif

#ifdef Q_OS_WIN
    QObject *root = engine.rootObjects()[0];
    QQuickWindow *window = qobject_cast<QQuickWindow *>(root);
    if (!window) {
        qFatal("Error: Your root item has to be a window.");
        return -1;
    }
    HWND hwnd = (HWND)window->winId();
    HMODULE hUser = GetModuleHandle(L"user32.dll");
    if (hUser)
    {
        pfnSetWindowCompositionAttribute setWindowCompositionAttribute = (pfnSetWindowCompositionAttribute)GetProcAddress(hUser, "SetWindowCompositionAttribute");
        if (setWindowCompositionAttribute)
        {
            ACCENT_POLICY accent = { ACCENT_ENABLE_BLURBEHIND, 0, 0, 0 };
            WINDOWCOMPOSITIONATTRIBDATA data;
            data.Attrib = WCA_ACCENT_POLICY;
            data.pvData = &accent;
            data.cbData = sizeof(accent);
            setWindowCompositionAttribute(hwnd, &data);
        }
    }
#endif

这使我所寻找的"Acrylic Material"效果得以实现(在QML中,您需要将窗口颜色设置为"transparent")。

实际上,我认为这是“玻璃”材料,而不是“丙烯酸”材料,因为您没有使用ACCENT_ENABLE_ACRYLICBLURBEHIND,而是使用了ACCENT_ENABLE_BLURBEHIND。 - Simon Mourier
@SimonMourier,尽管你说得没错,使用ACCENT_ACRYLICBLURBEHIND会带来显著的性能劣势。在这种情况下,我们更倾向于使用BLURBEHIND - Peter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接