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 312 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.
  • l3u_L Offline
    l3u_L Offline
    l3u_
    wrote on 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
    • l3u_L Offline
      l3u_L Offline
      l3u_
      wrote on 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
      • SGaistS Offline
        SGaistS Offline
        SGaist
        Lifetime Qt Champion
        wrote on 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
        • l3u_L Offline
          l3u_L Offline
          l3u_
          wrote on 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
          0
          • l3u_L l3u_

            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 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
            • l3u_L Offline
              l3u_L Offline
              l3u_
              wrote on 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
              0
              • Christian EhrlicherC Offline
                Christian EhrlicherC Offline
                Christian Ehrlicher
                Lifetime Qt Champion
                wrote on 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
                • l3u_L l3u_

                  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 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
                  • l3u_L Offline
                    l3u_L Offline
                    l3u_
                    wrote on 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
                    • l3u_L Offline
                      l3u_L Offline
                      l3u_
                      wrote on 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
                      • l3u_L l3u_ has marked this topic as solved on

                      • Login

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