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 can I implement a style sheet rounded border in a paintEvent?

How can I implement a style sheet rounded border in a paintEvent?

Scheduled Pinned Locked Moved Solved General and Desktop
9 Posts 4 Posters 307 Views
  • 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.
  • L Offline
    L Offline
    l3u_
    wrote on 20 Mar 2025, 16:41 last edited by l3u_
    #1

    Hi all,

    I'm working on a custom QPushButton. Currently, I set a style sheet:

    setStyleSheet(QStringLiteral("QPushButton { border: 1px solid palette(highlight); "
                                               "border-radius: 4px; }"));
    

    which makes the button appear e.g. like so:
    1.png

    Now, I want to do this exactly in a custom paintEvent. I tried the following:

    painter.setPen(QPen(palette().color(QPalette::Highlight), 1));
    painter.drawRoundedRect(rect().adjusted(0, 0, -1, -1), 4, 4);
    

    which gives me
    2.png

    The corners are not rounded in the same way, and they are not smooth like in the style sheet version. So I tried to enable anti-aliasing:

    painter.setRenderHint(QPainter::Antialiasing, true);
    

    which then causes the button to be rendered like this:
    3.png

    still very different from the style sheet version.

    So: How can I get the exact same result like when setting a style sheet?

    Thanks for all help in advance!

    1 Reply Last reply
    0
    • L Offline
      L Offline
      l3u_
      wrote on 25 Mar 2025, 12:22 last edited by
      #9

      It actually can be achieved way easier. Shamelessly stolen from Breeze's drawFocusFrame method and a lot simplified:

      void PopupButton::paintEvent(QPaintEvent *)
      {
          static const int margin = 1;
          static const int radius = 5;
      
          QPainterPath painterPath;
          painterPath.setFillRule(Qt::OddEvenFill);
          painterPath.addRoundedRect(rect().adjusted(margin, margin, -margin, -margin), radius, radius);
          painterPath.addRoundedRect(rect(), radius + margin, radius + margin);
      
          QPainter painter(this);
          painter.setRenderHint(QPainter::Antialiasing);
          painter.fillPath(painterPath, palette().color(QPalette::Highlight));
      }
      

      Result:

      1.png

      Of course lacks the text, hover indicator and all that – but the border looks fine.

      1 Reply Last reply
      0
      • S Offline
        S Offline
        SGaist
        Lifetime Qt Champion
        wrote on 20 Mar 2025, 20:21 last edited by
        #2

        Hi,

        The most simple would be to read the style sheet's QStyle implementation in Qt's source code.

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        1 Reply Last reply
        1
        • L Offline
          L Offline
          l3u_
          wrote on 20 Mar 2025, 22:41 last edited by
          #3

          I tried to do so, but it doesn't seem to be too easy to figure out what all happens under the hood :-(

          B 1 Reply Last reply 21 Mar 2025, 01:51
          0
          • L l3u_
            20 Mar 2025, 22:41

            I tried to do so, but it doesn't seem to be too easy to figure out what all happens under the hood :-(

            B Offline
            B Offline
            Bonnie
            wrote on 21 Mar 2025, 01:51 last edited by Bonnie
            #4

            @l3u_ It is in QRenderRule::drawBorder of Src/qtbase/src/widgets/styles/qstylesheetstyle.cpp and qDrawBorder of Src/qtbase/src/gui/painting/qcssutil.cpp.
            From the qDrawBorder source you can see that the edges and corners are drawn separately.
            An easier way is to call this function directly, but this need to add the private header module to your project.
            If you are using qmake, just add QT += gui-private to pro file. If using cmake you can google :).
            Then in the code

            #include <private/qcssutil_p.h>
            
            void Form::paintEvent(QPaintEvent *)
            {
                QPainter painter(this);
                painter.setRenderHint(QPainter::Antialiasing, true);
                const QVector<QCss::BorderStyle> styles(4, QCss::BorderStyle_Solid);
                const QVector<int> borders(4, 1);
                const QVector<QBrush> colors(4, palette().color(QPalette::Highlight));
                const QVector<QSize> radii(4, {4, 4});
                qDrawBorder(&painter, rect().adjusted(0, 0, -1, -1), styles.data(), borders.data(), colors.data(), radii.data());
            }
            
            1 Reply Last reply
            3
            • L Offline
              L Offline
              l3u_
              wrote on 24 Mar 2025, 11:58 last edited by
              #5

              I don't really want to include private headers … everything will break once they change something about this. This is really hard to get right.

              I'm just wondering why the drawRoundedRect result looks so odd in comparison …

              B 1 Reply Last reply 24 Mar 2025, 12:30
              0
              • C Offline
                C Offline
                Christian Ehrlicher
                Lifetime Qt Champion
                wrote on 24 Mar 2025, 12:29 last edited by
                #6

                Simply look in the code of this function. It's open source...

                Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                Visit the Qt Academy at https://academy.qt.io/catalog

                1 Reply Last reply
                0
                • L l3u_
                  24 Mar 2025, 11:58

                  I don't really want to include private headers … everything will break once they change something about this. This is really hard to get right.

                  I'm just wondering why the drawRoundedRect result looks so odd in comparison …

                  B Offline
                  B Offline
                  Bonnie
                  wrote on 24 Mar 2025, 12:30 last edited by
                  #7

                  @l3u_ Then you already know where the source code is. You can check by yourself.

                  P.S. I won't worry much about the private header.
                  First, the APIs in this header file haven't been changed from Qt5.0 till current Qt6.9.
                  Second, even the public headers have also been changed a lot, so what if the private header changes .

                  1 Reply Last reply
                  0
                  • L Offline
                    L Offline
                    l3u_
                    wrote on 24 Mar 2025, 20:43 last edited by l3u_
                    #8

                    Yeah, of course. I only somehow would have expected to simply get the same result by using QPainer::drawRoundedRect …

                    However thanks a lot for showing me the location of the code that does the work!

                    1 Reply Last reply
                    0
                    • L Offline
                      L Offline
                      l3u_
                      wrote on 25 Mar 2025, 12:22 last edited by
                      #9

                      It actually can be achieved way easier. Shamelessly stolen from Breeze's drawFocusFrame method and a lot simplified:

                      void PopupButton::paintEvent(QPaintEvent *)
                      {
                          static const int margin = 1;
                          static const int radius = 5;
                      
                          QPainterPath painterPath;
                          painterPath.setFillRule(Qt::OddEvenFill);
                          painterPath.addRoundedRect(rect().adjusted(margin, margin, -margin, -margin), radius, radius);
                          painterPath.addRoundedRect(rect(), radius + margin, radius + margin);
                      
                          QPainter painter(this);
                          painter.setRenderHint(QPainter::Antialiasing);
                          painter.fillPath(painterPath, palette().color(QPalette::Highlight));
                      }
                      

                      Result:

                      1.png

                      Of course lacks the text, hover indicator and all that – but the border looks fine.

                      1 Reply Last reply
                      0
                      • L l3u_ has marked this topic as solved on 25 Mar 2025, 17:37

                      5/9

                      24 Mar 2025, 11:58

                      • Login

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