Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How to round the corners of a frameless QWidget, when also applying acrylic effects?

How to round the corners of a frameless QWidget, when also applying acrylic effects?

Scheduled Pinned Locked Moved Unsolved General and Desktop
questionsqwidgetstylecustomplugin
12 Posts 7 Posters 3.0k Views 3 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • V Offline
    V Offline
    Vitalii777
    wrote on last edited by
    #3

    Please try to call 'setMask' to round borders in 'resizeEvent' and 'changeEvent -> QEvent::WindowStateChange event' too.

    G 1 Reply Last reply
    0
    • Axel SpoerlA Axel Spoerl

      @grainyblob
      Why does addRoundedRect not work? What's the desired and actual outcome?
      Have you tried to draw it directly with QPainter::drawRoundedRect()?
      Maybe also set an explicit brush, just for testing.

      G Offline
      G Offline
      grainyblob
      wrote on last edited by grainyblob
      #4

      @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.


      9850f51e-4adb-47c6-a1de-6d2dadc1d57e-{63D78F5E-4D8E-4E42-91E7-AC709EB7B477}.png
      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"?

      jsulmJ O 2 Replies Last reply
      0
      • G grainyblob

        @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.


        9850f51e-4adb-47c6-a1de-6d2dadc1d57e-{63D78F5E-4D8E-4E42-91E7-AC709EB7B477}.png
        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"?

        jsulmJ Offline
        jsulmJ Offline
        jsulm
        Lifetime Qt Champion
        wrote on last edited by
        #5

        @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

        https://forum.qt.io/topic/113070/qt-code-of-conduct

        G 1 Reply Last reply
        0
        • V Vitalii777

          Please try to call 'setMask' to round borders in 'resizeEvent' and 'changeEvent -> QEvent::WindowStateChange event' too.

          G Offline
          G Offline
          grainyblob
          wrote on last edited by
          #6

          @Vitalii777
          have tried to call setMask() in all events, none of them caused any change.

          1 Reply Last reply
          0
          • jsulmJ jsulm

            @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

            G Offline
            G Offline
            grainyblob
            wrote on last edited by
            #7

            @jsulm

            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.

            1 Reply Last reply
            0
            • U Offline
              U Offline
              UmarAli
              wrote on last edited by
              #8

              You can use my logic of making rounded corners QWidget:
              #include "RoundedBox.h"
              #include <QPainter>
              #include <QPainterPath>
              #include <QBitmap>
              #include <QFontMetrics>

              RoundedBox::RoundedBox(const QString &txt, QWidget *parent)
              : QWidget(nullptr), isDarkMode(false), text(txt), useAsToolTip(false)
              {
              setWindowFlags(Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint);
              setAttribute(Qt::WA_TranslucentBackground);
              setAsToolTip(false);
              }

              void RoundedBox::enableDarkMode(bool value)
              {
              isDarkMode = value;
              }

              void RoundedBox::setAsToolTip(bool value) {
              useAsToolTip = value;
              if (useAsToolTip) {
              setWindowFlag(Qt::ToolTip);
              updateSizeForText();
              } else {
              setWindowFlag(Qt::Popup);
              }
              update();
              }

              void RoundedBox::updateSizeForText() {
              resize(sizeHint());
              }

              QSize RoundedBox::sizeHint() const {
              QFont font;
              font.setPointSize(9);
              font.setFamily("Segoe UI");

              QFontMetrics fm(font);
              int MAX_W = 400;
              QSize s = fm.boundingRect(0, 0, MAX_W, 0, Qt::TextWordWrap, text).size();
              return QSize(s.width() + 24, s.height() + 12);
              

              }

              void RoundedBox::paintEvent(QPaintEvent *event)
              {
              Q_UNUSED(event);

              // Rounded mask
              QBitmap bitmap(width(), height());
              bitmap.fill(Qt::color0);
              QPainter maskPainter(&bitmap);
              maskPainter.setRenderHints(QPainter::Antialiasing);
              QPainterPath maskPath;
              maskPath.addRoundedRect(rect(), 6, 6);
              maskPainter.fillPath(maskPath, Qt::color1);
              setMask(bitmap);
              
              // Colors
              QColor BG = isDarkMode ? QColor("#2D2D2D") : QColor("#FFFFFF");
              QColor BR = isDarkMode ? QColor("#4D4D4D") : QColor("#BDBDBD");
              
              QPainter painter(this);
              painter.setRenderHints(QPainter::Antialiasing);
              painter.setBrush(BG);
              QPen pen(BR);
              pen.setWidth(1);
              painter.setPen(pen);
              
              QPainterPath path;
              path.addRoundedRect(rect().adjusted(1.5, 1.5, -1.5, -1.5), 6, 6);
              painter.drawPath(path);
              
              // Text
              if (useAsToolTip) {
                  QFont font;
                  font.setPointSize(9);
                  font.setFamily("Segoe UI");
                  painter.setFont(font);
                  painter.setPen(isDarkMode ? QColor("#F0F0F0") : QColor("#000000"));
                  QRect text_area(12, 0, width() - 24, height());
                  painter.drawText(text_area, Qt::AlignCenter | Qt::TextWordWrap, text);
              }
              

              }

              1 Reply Last reply
              0
              • Axel SpoerlA Offline
                Axel SpoerlA Offline
                Axel Spoerl
                Moderators
                wrote on last edited by
                #9

                Please format your code!

                Software Engineer
                The Qt Company, Oslo

                1 Reply Last reply
                1
                • L Offline
                  L Offline
                  Laffey
                  wrote on last edited by
                  #10

                  I encountered the same problem, and after spending over 6 hours on this, I'm so proud to say that I have a solution! Anyway, there's also an limitation, I'll mention it later.

                  well, in breif, this is it:

                  visualEffect.h:

                  #include <dwmapi.h> // note that you may have to use msvc for this
                  
                  // More friendly names
                  enum EffectType : int {
                      EffectType_Default = DWMSBT_AUTO,
                      EffectType_None = DWMSBT_NONE,
                      EffectType_Mica = DWMSBT_MAINWINDOW,
                      EffectType_Acrylic = DWMSBT_TRANSIENTWINDOW,
                      EffectType_MicaAlt = DWMSBT_TABBEDWINDOW
                  };
                  
                  enum CornerPreference : int {
                      Corner_Default = DWMWCP_DEFAULT,
                      Corner_NoRound = DWMWCP_DONOTROUND,
                      Corner_Round = DWMWCP_ROUND,
                      Corner_RoundSmall = DWMWCP_ROUNDSMALL
                  };
                  
                  bool SetAcrylicEffect(HWND hwnd, EffectType type = EffectType_Mica, CornerPreference corner = Corner_Round);
                  
                  

                  visualEffect.cpp

                  #include "visualEffect.h"
                  
                  bool SetAcrylicEffect(HWND hwnd, EffectType type, CornerPreference corner)
                  {
                      if(!hwnd) return false;
                  
                      HRESULT hr1, hr2;
                  
                      DWM_SYSTEMBACKDROP_TYPE backdrop = static_cast<DWM_SYSTEMBACKDROP_TYPE>(type);
                      hr1 = DwmSetWindowAttribute(hwnd, DWMWA_SYSTEMBACKDROP_TYPE, &backdrop, sizeof(backdrop));
                  
                      // set rounded corner preference
                      if(corner != Corner_Default) {
                          // when it's not default
                          DWM_WINDOW_CORNER_PREFERENCE cp = static_cast<DWM_WINDOW_CORNER_PREFERENCE>(corner);
                          hr2 = DwmSetWindowAttribute(hwnd, DWMWA_WINDOW_CORNER_PREFERENCE, &cp, sizeof(cp));
                      }
                      else {
                          hr2 = S_OK; // regard as success
                      }
                  
                      return SUCCEEDED(hr1) && SUCCEEDED(hr2);
                  }
                  
                  

                  You need to link dwmapi like this in your CMakeLists.txt:

                  target_link_libraries(YourApplication PRIVATE dwmapi)
                  

                  Some important things you need to know:

                  • Corner_Round is fixed 8px radius, and Corner_RoundSmall is fixed 4px. You can not change this, because this is builtin for dwm. There values are usually good enough, so if you really want it you should just set your window to 8px radius.
                  • after using setAttribute(Qt::WA_Translucentbackground), the transparent part for your window is not regarded as the window region, so it acts like non-client area. And if you use the stylesheet or paintEvent on your centralwidget or something, the effect looks broken.

                  So the best approach on Qt, is set another overlay widget at the bottom, and put everything else on top of it.
                  The overlay widget should have something like this:

                  #overlay {
                      background: rgba(255, 255, 255, 2); /*1 makes it not transparent at all, and 0 does not work*/
                  }
                  

                  and this:

                  // something here
                  {
                      ui->setupUi(this);
                  
                      setAttribute(Qt::WA_TranslucentBackground);
                  
                      if(!SetAcrylicEffect((HWND)this->winId(), EffectType_Acrylic, Corner_Round)) {
                          qWarning() << "Failed to launch Acrylic Effect, fallback to default transparency" << GetLastError();
                     }
                  }
                  

                  also this:
                  ed166b7e-6e02-415c-9695-520ce249966a-image.png

                  And you're done!

                  You can find the full version on my github, but the above one should be completely usable already.

                  1 Reply Last reply
                  1
                  • G grainyblob

                    @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.


                    9850f51e-4adb-47c6-a1de-6d2dadc1d57e-{63D78F5E-4D8E-4E42-91E7-AC709EB7B477}.png
                    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"?

                    O Offline
                    O Offline
                    Oscar Jeej
                    wrote on last edited by Oscar Jeej
                    #11

                    @grainyblob Might be a weird question but I am quite new to coding, in the image, how did you get those rounded corners while applying acrylic? because I though corners were limited to 8px on windows 11 due to dwm, but it seems you have gone over this limit, I'm asking because I want to make a program that is similar to macos tahoe 26 spotlight search but for windows 11 using this effect.

                    G 1 Reply Last reply
                    0
                    • O Oscar Jeej

                      @grainyblob Might be a weird question but I am quite new to coding, in the image, how did you get those rounded corners while applying acrylic? because I though corners were limited to 8px on windows 11 due to dwm, but it seems you have gone over this limit, I'm asking because I want to make a program that is similar to macos tahoe 26 spotlight search but for windows 11 using this effect.

                      G Offline
                      G Offline
                      grainyblob
                      wrote last edited by grainyblob
                      #12

                      @Oscar-Jeej

                      That's the neat part... I didn't.
                      This was just a mockup I drew up on figma.
                      Good luck on your endevour though! I'll try out @Laffey solution first and see what I can do.

                      I have to admit i forgot 99% of Qt stuff since i took a hiatus

                      EDIT-- never mind, this implementation also limited to 8px. Im really thinking best option is just to draw my own window using dx11 or something

                      1 Reply Last reply
                      0

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved