Qt round rectangle, why corners are different?
Asked Answered
S

6

7

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 !

Stormy answered 28/6, 2011 at 13:51 Comment(0)
D
15

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.

Dogcatcher answered 28/6, 2011 at 14:53 Comment(2)
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 !Stormy
Had the same problem. Using QPainter p(this); p.setRenderHint(QPainter::Antialiasing); p.setRenderHint(QPainter::HighQualityAntialiasing); did the trick for me.Centroid
F
6

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

Flogging answered 22/9, 2014 at 18:32 Comment(0)
A
4

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 );
Ammonate answered 8/8, 2013 at 12:2 Comment(0)
S
2

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);     
}
Sulfonmethane answered 26/9, 2014 at 11:20 Comment(0)
F
0

try to play with render hints 1) disable antiAliasing; 2) enable SmoothPixmapTransform

but still no guarantee that it will help.

Fassold answered 28/6, 2011 at 14:30 Comment(0)
A
0

I have tried all tips from answers here but nothing works for me. But based on these code snippets I have found following solution:

As default set m_pPainter->setRenderHint(QPainter::Qt4CompatiblePainting, true) and only for rounded rectangles with width%2==0 disable it.

QRect rect = ConvertRectangle(rectangle);

int nPenWidth = m_pPainter->pen().width();
if ( nPenWidth % 2 == 0 )
    m_pPainter->setRenderHint(QPainter::Qt4CompatiblePainting, false);

m_pPainter->drawRoundedRect(rect, dbRadiusX, dbRadiusY);

if ( nPenWidth % 2 == 0 )
    m_pPainter->setRenderHint(QPainter::Qt4CompatiblePainting, true);
Aristocratic answered 3/12, 2014 at 13:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.