How to round the corners of a frameless QWidget, when also applying acrylic effects?
-
Hello everyone! I like to make a dock in Qt for Windows. I have the general idea of how to do it, and I would first like to focus on making the window look pretty. Now I would like to provide the user with an option to change the corner radius of the dock, and also allow for Acrylic or Mica (introduced in W11.) Basically, I want to achieve custom border radii on a frameless window with acrylic.
Now, I attempted some stuff:
- Set stylesheet with border radius property.
// inside the constructor setStyleSheet("border-radius: 32px;");
- Add a custom mask
Dock::Dock(QWidget *parent):QWidget(parent) { // after other methods are called. roundZeCorners(); } void Dock::roundZeCorners(int radius) { QPainterPath path; path.addRoundedRect(rect(), radius, radius); setMask(QRegion(path.toFillPolygon().toPolygon())); } void Dock::paintEvent(QPaintEvent *event) { QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); QPainterPath path; path.addRoundedRect(rect(), border_radius, border_radius); painter.setClipPath(path); painter.fillPath(path, Qt::transparent); }
These are the only two solutions I came across to make custom window as described, but neither work. The stylesheet was obvious, because I read that qwidget not support styling border radius, and besides, it is top level window.
Here is how I apply my window effects:
#ifdef Q_OS_WIN void Dock::applyWindowEffect(uint tint_color) { const HINSTANCE hModule = LoadLibraryA("user32.dll"); if (hModule) { struct ACCENTPOLICY { int nAccentState; int nFlags; DWORD nColor; int nAnimationId; }; struct WINCOMPATTRDATA { int nAttribute; PVOID pData; ULONG ulDataSize; }; typedef BOOL(WINAPI* pSetWindowCompositionAttribute)(HWND, WINCOMPATTRDATA*); const auto SetWindowCompositionAttribute = (pSetWindowCompositionAttribute)GetProcAddress(hModule, "SetWindowCompositionAttribute"); if (SetWindowCompositionAttribute) { ACCENTPOLICY policy = { 4, 0, tint_color, 0 }; // 4 = ACCENT_ENABLE_ACRYLICBLURBEHIND WINCOMPATTRDATA data = { 19, &policy, sizeof(ACCENTPOLICY) }; // 19 = WCA_ACCENT_POLICY SetWindowCompositionAttribute((HWND)winId(), &data); } FreeLibrary(hModule); } } #endif
How would I add the rounded corners? Sorry if this is a stupid post.
-
Hello everyone! I like to make a dock in Qt for Windows. I have the general idea of how to do it, and I would first like to focus on making the window look pretty. Now I would like to provide the user with an option to change the corner radius of the dock, and also allow for Acrylic or Mica (introduced in W11.) Basically, I want to achieve custom border radii on a frameless window with acrylic.
Now, I attempted some stuff:
- Set stylesheet with border radius property.
// inside the constructor setStyleSheet("border-radius: 32px;");
- Add a custom mask
Dock::Dock(QWidget *parent):QWidget(parent) { // after other methods are called. roundZeCorners(); } void Dock::roundZeCorners(int radius) { QPainterPath path; path.addRoundedRect(rect(), radius, radius); setMask(QRegion(path.toFillPolygon().toPolygon())); } void Dock::paintEvent(QPaintEvent *event) { QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); QPainterPath path; path.addRoundedRect(rect(), border_radius, border_radius); painter.setClipPath(path); painter.fillPath(path, Qt::transparent); }
These are the only two solutions I came across to make custom window as described, but neither work. The stylesheet was obvious, because I read that qwidget not support styling border radius, and besides, it is top level window.
Here is how I apply my window effects:
#ifdef Q_OS_WIN void Dock::applyWindowEffect(uint tint_color) { const HINSTANCE hModule = LoadLibraryA("user32.dll"); if (hModule) { struct ACCENTPOLICY { int nAccentState; int nFlags; DWORD nColor; int nAnimationId; }; struct WINCOMPATTRDATA { int nAttribute; PVOID pData; ULONG ulDataSize; }; typedef BOOL(WINAPI* pSetWindowCompositionAttribute)(HWND, WINCOMPATTRDATA*); const auto SetWindowCompositionAttribute = (pSetWindowCompositionAttribute)GetProcAddress(hModule, "SetWindowCompositionAttribute"); if (SetWindowCompositionAttribute) { ACCENTPOLICY policy = { 4, 0, tint_color, 0 }; // 4 = ACCENT_ENABLE_ACRYLICBLURBEHIND WINCOMPATTRDATA data = { 19, &policy, sizeof(ACCENTPOLICY) }; // 19 = WCA_ACCENT_POLICY SetWindowCompositionAttribute((HWND)winId(), &data); } FreeLibrary(hModule); } } #endif
How would I add the rounded corners? Sorry if this is a stupid post.
@grainyblob
Why doesaddRoundedRect
not work? What's the desired and actual outcome?
Have you tried to draw it directly withQPainter::drawRoundedRect()
?
Maybe also set an explicit brush, just for testing. -
Please try to call 'setMask' to round borders in 'resizeEvent' and 'changeEvent -> QEvent::WindowStateChange event' too.
-
@grainyblob
Why doesaddRoundedRect
not work? What's the desired and actual outcome?
Have you tried to draw it directly withQPainter::drawRoundedRect()
?
Maybe also set an explicit brush, just for testing.@Axel-Spoerl
The desired outcome was to make a acrylic window with a custom border radius. (See attached image). Once I add a roundedRect to the path I set a mask from the path. Now in a normal QWidget, it will round the corners, but my guess is that because of the DWM code I'm using, it's overriding the composition and displaying a rect.
see above for desired result ↑Once again, sorry if my explaination of my issue is bad, I really struggle to explain things most of the time.
Edit: I forgot to ask, what do you mean by "explicit brush"?
-
@Axel-Spoerl
The desired outcome was to make a acrylic window with a custom border radius. (See attached image). Once I add a roundedRect to the path I set a mask from the path. Now in a normal QWidget, it will round the corners, but my guess is that because of the DWM code I'm using, it's overriding the composition and displaying a rect.
see above for desired result ↑Once again, sorry if my explaination of my issue is bad, I really struggle to explain things most of the time.
Edit: I forgot to ask, what do you mean by "explicit brush"?
@grainyblob said in How to round the corners of a frameless QWidget, when also applying acrylic effects?:
I forgot to ask, what do you mean by "explicit brush"?
Your own QBrush instance which you pass to the painter. https://doc.qt.io/qt-6/qbrush.html
-
Please try to call 'setMask' to round borders in 'resizeEvent' and 'changeEvent -> QEvent::WindowStateChange event' too.
@Vitalii777
have tried to callsetMask()
in all events, none of them caused any change. -
@grainyblob said in How to round the corners of a frameless QWidget, when also applying acrylic effects?:
I forgot to ask, what do you mean by "explicit brush"?
Your own QBrush instance which you pass to the painter. https://doc.qt.io/qt-6/qbrush.html
Yes in that case, it works. The corners of the window are rounded as expected. It is only with my
applyWindowEffects()
method which fails to round corners in this method.Alternatively, since it might be a DWM level issue, I'm considering trying to replicate what I do with masking but with native DWM API.