How to get a blurred translucent QML Window (similar to Fluent Design guidelines) on Windows 10?
Asked Answered
L

1

5

I would like to get a semi-transparent blurred window in QML on Windows 10 similar to the Fluent Design guidelines (example). I know you can make a transparent window:

Window{
    visible: true
    color: "transparent"
}

but this doesn't achieve the blur effect I am looking at. I am also aware that one can blur elements inside the windows using QtGraphicalEffects like FastBlur but I would like to blur the entire window itself. Is there a way to achieve this? I have also tried using the QtWinExtras module and call QtWin::enableBlurBehindWindow but this doesn't work either:

    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);
Lummox answered 23/8, 2019 at 12:5 Comment(4)
Maybe this will help to solve your problemDesertion
That seems to apply to QWidgets and QWindowsLummox
Is this and this, what're you expecting? (It can be more blured or more transparet)Desertion
Not really, I think what you did was make a window transparent and applied a semi transparent rectangle with a gradient on it. I am looking for what Microsoft calls "Acrylic Material"Lummox
L
6

Ok so I found a solution that turned out to be easier than I thought it would be. Officially Microsoft does not provide an API to achieve what I was looking for. I stumbled across this thread and I found this. From there I adapted the code to my needs, I created a header file containing:

#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

And then in my 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

This enables the "Acrylic Material" effect I was looking for (in QML you have to set the window color to "transparent").

Lummox answered 24/8, 2019 at 10:48 Comment(2)
actually, I believe this is "glass" material, not "acrylic" since you're not using ACCENT_ENABLE_ACRYLICBLURBEHIND but ACCENT_ENABLE_BLURBEHINDGoodkin
@SimonMourier While what you're saying is correct. ACCENT_ACRYLICBLURBEHIND has significant performance disadvantages, doing it this way. In this case BLURBEHIND is preferred.Blotch

© 2022 - 2024 — McMap. All rights reserved.