I am just beginner and I try to make a simple Qt6 widget with blurring behind for Windows 10-11 OS. I know that Qt6 doesn't provide this from the box and I need to use the Windows API for that.
Unfortunately, I don't know the Windows API, but I found a working code with the effect I needed:
Win32 API:
#include <windows.h>
TCHAR szClassName[] = TEXT("Window");
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_PAINT:
{
PAINTSTRUCT ps;
const HDC hdc = BeginPaint(hWnd, &ps);
SetTextColor(hdc, RGB(255, 255, 255));
SetBkMode(hdc, TRANSPARENT);
TextOut(hdc, 10, 10, TEXT("Hello, world!"), 13);
EndPaint(hWnd, &ps);
}
break;
case WM_NCHITTEST:
wParam = DefWindowProc(hWnd, msg, wParam, lParam);
if (wParam == HTCLIENT)
return HTCAPTION;
else
return wParam;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
return 0;
}
void SetWindowBlur(HWND hWnd)
{
const HINSTANCE hModule = LoadLibrary(TEXT("user32.dll"));
if (hModule)
{
struct ACCENTPOLICY
{
int nAccentState;
int nFlags;
int nColor;
int nAnimationId;
};
struct WINCOMPATTRDATA
{
int nAttribute;
PVOID pData;
ULONG ulDataSize;
};
typedef BOOL(WINAPI* pSetWindowCompositionAttribute)(HWND, WINCOMPATTRDATA*);
const pSetWindowCompositionAttribute SetWindowCompositionAttribute = (pSetWindowCompositionAttribute)GetProcAddress(hModule, "SetWindowCompositionAttribute");
if (SetWindowCompositionAttribute)
{
ACCENTPOLICY policy = { 3, 0, 0, 0 };
WINCOMPATTRDATA data = { 19, &policy, sizeof(ACCENTPOLICY) };
SetWindowCompositionAttribute(hWnd, &data);
}
FreeLibrary(hModule);
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInst, LPSTR pCmdLine, int nCmdShow)
{
MSG msg;
WNDCLASS wndclass = {
0,
WndProc,
0,
0,
hInstance,
0,
LoadCursor(0, IDC_ARROW),
(HBRUSH)GetStockObject(BLACK_BRUSH),
0,
szClassName
};
RegisterClass(&wndclass);
HWND hWnd = CreateWindow(
szClassName,
TEXT("Window"),
WS_POPUPWINDOW,
0,
0,
640,
480,
0,
0,
hInstance,
0
);
SetWindowBlur(hWnd);
ShowWindow(hWnd, SW_SHOWDEFAULT);
UpdateWindow(hWnd);
while (GetMessage(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
In Qt6 I have a frameless semi-transparent widget with an overridden painterEvent where all the painting happens. The main question is: how can I draw the blur effect from win32 API in the painterEvent? Just in case, here is a simplified Qt6 code:
#include <QtWidgets/QMainWindow>
#include <QPainter>
#include <qapplication.h>
class Qt6WinAPI_Test : public QWidget
{
Q_OBJECT
public:
Qt6WinAPI_Test(QWidget *parent = nullptr)
{
setWindowFlag(Qt::FramelessWindowHint);
setAttribute(Qt::WA_TranslucentBackground);
}
~Qt6WinAPI_Test(){}
protected:
void paintEvent(QPaintEvent* event) override
{
QPainter painter(this);
painter.fillRect(this->rect(), QColor(255, 255, 255, 150));
painter.end();
}
};
Thanks to @IInspectable for the hint, maybe it will be useful for someone:
#include <QPainter>
#include <QWidget>
#include <qapplication.h>
#include <windows.h>
class Qt6WinAPI_Test : public QWidget
{
Q_OBJECT
public:
Qt6WinAPI_Test(QWidget *parent = nullptr)
{
this->resize(640, 480);
setWindowFlags(Qt::FramelessWindowHint);
setAttribute(Qt::WA_TranslucentBackground);
}
~Qt6WinAPI_Test(){}
protected:
void paintEvent(QPaintEvent* event) override
{
QPainter painter(this);
painter.fillRect(this->rect(), QColor(0, 0, 0, 1));
}
bool nativeEvent(const QByteArray& eventType, void* message, qintptr* result) override
{
static bool firtsCall{true};
MSG * msg = reinterpret_cast<MSG*>(message);
if(firtsCall)
{
SetWindowBlur(msg->hwnd);
firstCall = false;
}
return false;
}
private:
void SetWindowBlur(HWND hWnd)
{
const HINSTANCE hModule = LoadLibrary(TEXT("user32.dll"));
if (hModule)
{
struct ACCENTPOLICY
{
int nAccentState;
int nFlags;
int nColor;
int nAnimationId;
};
struct WINCOMPATTRDATA
{
int nAttribute;
PVOID pData;
ULONG ulDataSize;
};
typedef BOOL(WINAPI* pSetWindowCompositionAttribute)(HWND, WINCOMPATTRDATA*);
const pSetWindowCompositionAttribute SetWindowCompositionAttribute = (pSetWindowCompositionAttribute)GetProcAddress(hModule, "SetWindowCompositionAttribute");
if (SetWindowCompositionAttribute)
{
ACCENTPOLICY policy = { 3, 0, 0, 0 };
WINCOMPATTRDATA data = { 19, &policy, sizeof(ACCENTPOLICY) };
SetWindowCompositionAttribute(hWnd, &data);
}
FreeLibrary(hModule);
}
}
};