Qt round rectangle, why corners are different?

10,903

Solution 1

It looks like you're not using anti-aliasing (i.e. the QPainter::Antialiasing render hint). This is a Qt quirk that occurs without it. From what I've seen/heard, the Qt devs aren't terribly concerned with fixing this (most people want anti-aliasing anyway).

The work-around (besides just using anti-aliasing) is to draw the rect yourself with QPainter::drawLine() and QPainter::drawArc(). You might have to play with numbers until it looks right -- straight calculations tend to come out a pixel or two off. Also, you might find that even with this method the lower right corner is never exactly the same as the other corners.

If you're feeling mildly ambitious, you could try fixing this and submitting a patch to Qt.

Update: Arc drawing results changed in Qt 5. In my experience, it's a big improvement.

Solution 2

I know this is an old problem but for Qt5 users calling setRenderHint(QPainter::Qt4CompatiblePainting); on the QPainter seems to solve the problem.

Edit:

I found a solution for generating a perfect rounded rectangle together with border color and it looks the same as the rounded rectangles used by QPushButton's border for example. This is how I implemented the paintEvent to achieve this:

void MyButtonGroup::paintEvent(QPaintEvent * e)
{
    int borderSize = 5;
    QColor borderColor = Qt::red;
    QColor backgroundColor = Qt::blue;
    int borderRadius = 3;

    QPen pen;
    pen.setWidth(borderSize);
    pen.setColor(borderColor);

    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.setPen(pen);

    QRectF rect(rect().x() + borderSize / 2,
                rect().y() + borderSize / 2,
                rect().width() - borderSize,
                rect().height() - borderSize);


    if(borderSize % 2 == 0)
    {
        painter.drawRoundedRect(rect,
                                borderSize,
                                borderSize);
    }
    else
    {
        painter.drawRoundedRect(rect.translated(0.5, 0.5),
                                borderRadius,
                                borderRadius);
    }

    QBrush brush(backgroundColor);
    pen.setBrush(brush);
    painter.setBrush(brush);

    if(borderSize % 2 == 0)
    {
        painter.drawRoundedRect(rect,
                                borderRadius,
                                borderRadius);
    }
    else
    {
        painter.drawRoundedRect(rect.translated(0.5, 0.5),
                                borderRadius,
                                borderRadius);
    }

    QWidget::paintEvent(e);
}

I'm posting this because I found it a bit hard to achieve this result:

enter image description here

Solution 3

Try adding half a pixel offset (e.g.: rect.translated(0.5,0.5) ):

QRectF rect(0,0,48,11);
painter.setRenderHint(QPainter::Antialiasing,false);
painter.drawRoundedRect( rect.translated(0.5,0.5), 2.0, 2.0 );

I suppose this has to do with the coordinate system placing an integer value between two pixels.

If you draw with antialiasing and use a pen of 1 pixel width then drawing at exact integer coordinates results in lines of 2 pixel width instead. Only with this 0.5 pixel offset you'll get lines that are exactly 1 pixel wide.

QRectF rect(0,0,48,11);
painter.setRenderHint(QPainter::Antialiasing,true);
painter.setBrush(Qt::NoBrush);
painter.setPen( Qt::white );
painter.drawRoundedRect( rect.translated(0.5,0.5), 2.0,2.0 );

Solution 4

Best way do draw RoundRect is Path. http://developer.nokia.com/community/wiki/Qt_rounded_rect_widget

void fillRoundRect(QPainter& painter, QRect r, int radius)
{
    painter.setRenderHint(QPainter::Antialiasing,true);

    QPainterPath rounded_rect;
    rounded_rect.addRoundRect(r, radius, radius);
    painter.setClipPath(rounded_rect);

    painter.fillPath(rounded_rect,painter.brush());     
    painter.drawPath(rounded_rect);     
}
Share:
10,903
Thomas Vincent
Author by

Thomas Vincent

Updated on June 27, 2022

Comments

  • Thomas Vincent
    Thomas Vincent almost 2 years

    I try to draw a round rectangle with drawRoundedRect method directly in a QPixmap (no render engine involve here exept pure Qt one ...), I double check the size of the rectangle versus the size of my pixmap :

    Pixmap : QSize(50, 73) 
    Rectangle: QRect(0,0 48x11) 
    

    See plenty of space ...

    EDIT: some code

    pixmap = QPixmap(50,73); //example size that match my case
    QRectF rect(0,0,48,11);
    
    QPainter painter(&pixmap);
    painter.setRenderHint(QPainter::TextAntialiasing);
    painter.setWorldMatrixEnabled(false);
    painter.setPen(QPen()); //no pen
    painter.setBrush(QBrush(color));
    painter.drawRoundedRect(rect, 2.0, 2.0);
    
    • I disabled world transformation ...
    • I set set transformation to unity ...
    • I tried several radius (1.0,2.0,3.0,4.0) ...
    • I change pen width, brush color ...

    But it always ends with a rectamgle with 4 diferent corners ! Like that :

    Radius = 3.0 in x and y

    I directly ouptut the pixmap to a file to be sure I wasn't scraping it during the display ... same shape.

    Anyone know about Qt round rectangle with small radius ? I saw somthing about it a long time ago but I don't remenber how to deal with it !

  • Thomas Vincent
    Thomas Vincent almost 13 years
    I played with antialising other way to draw stuff (drwa path, arc ...). Antialiasing with such small stuff make it worth ! And my best shot was addind ~0.5 every where quessing where rouding can produce weird behavior ... So I will accept the play with numbers method !
  • S B
    S B almost 11 years
    Had the same problem. Using QPainter p(this); p.setRenderHint(QPainter::Antialiasing); p.setRenderHint(QPainter::HighQualityAntialiasing); did the trick for me.