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. QPainterPath::addRoundedRect with 4 different radii?
Forum Updated to NodeBB v4.3 + New Features

QPainterPath::addRoundedRect with 4 different radii?

Scheduled Pinned Locked Moved Solved General and Desktop
4 Posts 2 Posters 887 Views 1 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.
  • E Offline
    E Offline
    Ewan Green
    wrote on last edited by
    #1

    I was looking at the documentation for QPainterPath::addRoundedRect(), expecting one of the overloads to take 4 radius parameters (one for top left, another for top right, another for bottom left, another for bottom right). I was surprised to see that they only take 2 parameters, X radius and Y radius -- how can I add a rounded rectangle with corner radii that aren't in pairs?

    Ewan Green

    1 Reply Last reply
    0
    • E Offline
      E Offline
      Ewan Green
      wrote on last edited by Ewan Green
      #2

      This implementation suits my purposes just fine.
      inset can be replaced with 0s or omitted for the subtraction; I included it because it was convenient for my implementation since I'm using this to draw rounded rectangles with borders (the normal QPainter way w/ pen and brush overlaps the two which is bad when translucency is present)

        const int w = width();
        const int h = height();
      
        auto drawRoundedRect = [this, w, h](QPainterPath &p, const BorderRadius &r,
                                            int inset) {
          // clang-format off
          p.arcMoveTo(
                  inset,                      inset,                      inset,          r.topLeft,      0);
      
          p.arcTo(inset,                      inset,                      r.topLeft,      r.topLeft,      180,    -90);
          p.arcTo(w - r.topRight - inset,     inset,                      r.topRight,     r.topRight,     90,     -90);
          p.arcTo(w - r.bottomRight - inset,  h - r.bottomRight - inset,  r.bottomRight,  r.bottomRight,  0,      -90);
          p.arcTo(inset,                      h - r.bottomLeft - inset,   r.bottomLeft,   r.bottomLeft,   270,    -90);
          p.arcTo(inset,                      inset,                      r.topLeft,      r.topLeft,      180,    0);
          // clang-format on
        };
      
      

      I used a BorderRadius struct, as follows. Includes convenience overloads and operators, would work with just the radius members

      struct BorderRadius {
        template <typename T>
        explicit BorderRadius(T a) {
          topLeft = a;
          topRight = a;
          bottomLeft = a;
          bottomRight = a;
        }
        template <typename T>
        explicit BorderRadius(T top, T bottom) {
          topLeft = top;
          topRight = top;
          bottomLeft = bottom;
          bottomRight = bottom;
        }
        template <typename T>
        explicit BorderRadius(T topLeft, T topRight, T bottomLeft, T bottomRight) {
          this->topLeft = topLeft;
          this->topRight = topRight;
          this->bottomLeft = bottomLeft;
          this->bottomRight = bottomRight;
        }
      
        bool operator==(BorderRadius x) {
          return this->topLeft == x.topLeft && this->topRight == x.topRight &&
                 this->bottomLeft == x.bottomLeft &&
                 this->bottomRight == x.bottomRight;
        }
      
        template <typename T>
        bool operator==(T x) {
          return topLeft == x && topRight == x && bottomLeft == x && bottomRight == x;
        }
      
        float topLeft = 0, topRight = 0, bottomLeft = 0, bottomRight = 0;
      };
      

      When invoking like this, it yields the following screenshot

      
        // Default values provided for clarity
        QPainter p(this);
        
        QColor m_border_brush = Qt::red;
        m_border_brush.setAlphaF(0.5);
        QColor m_background_brush = Qt::blue;
        m_border_brush.setAlphaF(0.5);
      
        BorderRadius m_border_outer_radius(10, 20, 30, 40);
        int m_border_thickness = 4;
      
        BorderRadius m_border_inner_radius(
            m_border_outer_radius.topLeft - m_border_thickness,
            m_border_outer_radius.topRight - m_border_thickness,
            m_border_outer_radius.bottomLeft - m_border_thickness,
            m_border_outer_radius.bottomRight - m_border_thickness);
        // End defaults
      
        QPainterPath path, path2;
        
        drawRoundedRect(path, m_border_outer_radius, 0);
        drawRoundedRect(path2, m_border_inner_radius, m_border_thickness);
      
        p.setCompositionMode(QPainter::CompositionMode_Xor); // For demonstration; overlap would be made very apparent
        
        p.setPen(Qt::NoPen);
        p.setBrush(m_border_brush);
        p.drawPath(path.subtracted(path2));
        p.setBrush(m_background_brush);
        p.drawPath(path2.intersected(path));
      

      65e87b7a-4751-47c9-9389-d8f220025486-image.png

      Ewan Green

      1 Reply Last reply
      0
      • A Offline
        A Offline
        alvazz
        wrote on last edited by
        #3

        can you show the full source code?

        1 Reply Last reply
        0
        • A Offline
          A Offline
          alvazz
          wrote on last edited by
          #4
            const int w = width();
            const int h = height();
          
            auto drawRoundedRect = [this, w, h](QPainterPath &p, const BorderRadius &r,
                                                int inset) {
              // clang-format off
              p.arcMoveTo(
                      inset,                      inset,                      inset,          r.topLeft,      0);
          
              p.arcTo(inset,                      inset,                      r.topLeft,      r.topLeft,      180,    -90);
              p.arcTo(w - r.topRight - inset,     inset,                      r.topRight,     r.topRight,     90,     -90);
              p.arcTo(w - r.bottomRight - inset,  h - r.bottomRight - inset,  r.bottomRight,  r.bottomRight,  0,      -90);
              p.arcTo(inset,                      h - r.bottomLeft - inset,   r.bottomLeft,   r.bottomLeft,   270,    -90);
              p.arcTo(inset,                      inset,                      r.topLeft,      r.topLeft,      180,    0);
              // clang-format on
            };
          
          
          

          Where should this code be placed? How should it be used?

          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