Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Qt round rectangle, why corners are different?

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 !

like image 232
Thomas Vincent Avatar asked Jun 28 '11 13:06

Thomas Vincent


3 Answers

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.

like image 192
Steve S Avatar answered Oct 02 '22 09:10

Steve S


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

like image 32
Jacob Krieg Avatar answered Oct 02 '22 08:10

Jacob Krieg


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 );
like image 40
Joachim Avatar answered Oct 02 '22 08:10

Joachim