Qt круглый прямоугольник, почему углы разные?

Я пытаюсь нарисовать круглый прямоугольник с помощью метода drawRoundedRect непосредственно в QPixmap (здесь не задействован движок рендеринга, кроме чистого Qt...), я дважды проверяю размер прямоугольника по сравнению с размером моего растрового изображения:

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

Видишь много места...

РЕДАКТИРОВАТЬ: некоторый код

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);
  • Я отключил трансформацию мира...
  • Я установил преобразование множества в единицу...
  • Пробовал несколько радиусов (1.0,2.0,3.0,4.0)...
  • Меняю ширину пера, цвет кисти...

Но он всегда заканчивается прямоугольником с 4 разными углами! Как это :

Радиус = 3,0 по x и y

Я напрямую вывожу растровое изображение в файл, чтобы быть уверенным, что не очищаю его во время отображения... та же форма.

Кто-нибудь знает о круглом прямоугольнике Qt с малым радиусом? Давно что-то видел об этом, но не помню, как с этим бороться!


person Thomas Vincent    schedule 28.06.2011    source источник


Ответы (6)


Похоже, вы не используете сглаживание (т. е. подсказку рендеринга QPainter::Antialiasing). Это причуда Qt, которая происходит без него. Судя по тому, что я видел/слышал, разработчики Qt не сильно озабочены исправлением этого (большинство людей все равно хотят сглаживания).

Обходной путь (кроме использования сглаживания) заключается в том, чтобы нарисовать прямоугольник самостоятельно с помощью QPainter::drawLine() и QPainter::drawArc(). Возможно, вам придется играть с числами, пока они не будут выглядеть правильно — прямые вычисления, как правило, дают ошибку на один или два пикселя. Кроме того, вы можете обнаружить, что даже при использовании этого метода правый нижний угол никогда не будет в точности таким же, как другие углы.

Если вы чувствуете себя немного амбициозным, вы можете попробовать исправить это и отправить патч в Qt.

Обновление: результаты рисования дуг изменились в Qt 5. По моему опыту, это большое улучшение.

person Steve S    schedule 28.06.2011
comment
Я играл со сглаживанием другим способом рисования (drwa path, arc...). Сглаживание с такими мелочами того стоит! И мой лучший шанс был добавить ~ 0,5 каждый раз, когда поиск, где rouding может привести к странному поведению ... Так что я приму метод игра с числами! - person Thomas Vincent; 28.06.2011
comment
Была такая же проблема. Использование QPainter p(this); p.setRenderHint(QPainter::Antialiasing); p.setRenderHint(QPainter::HighQualityAntialiasing); помогло мне. - person S B; 13.08.2013

Я знаю, что это старая проблема, но для Qt5 пользователей вызов setRenderHint(QPainter::Qt4CompatiblePainting); на QPainter кажется решает проблему.

Изменить:

Я нашел решение для создания идеального прямоугольника со скругленными углами вместе с цветом границы, и он выглядит так же, как прямоугольники со скругленными углами, используемые, например, границей QPushButton. Вот как я реализовал paintEvent для достижения этой цели:

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);
}

Я публикую это, потому что мне было немного сложно достичь этого результата:

введите здесь описание изображения

person Jacob Krieg    schedule 22.09.2014

Попробуйте добавить смещение в половину пикселя (например: 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 );

Я предполагаю, что это связано с системой координат, помещающей целочисленное значение между двумя пикселями.

Если вы рисуете со сглаживанием и используете перо шириной 1 пиксель, то рисование с точными целочисленными координатами вместо этого приводит к линиям шириной 2 пикселя. Только с этим смещением в 0,5 пикселя вы получите линии шириной ровно 1 пиксель.

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 );
person Joachim    schedule 08.08.2013

Лучший способ нарисовать RoundRect - это 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);     
}
person Dmitry Labadin    schedule 26.09.2014

попробуй поиграться с рендер хинтами 1) отключи сглаживание; 2) включить SmoothPixmapTransform

но все равно нет гарантии, что поможет.

person Raiv    schedule 28.06.2011

Я перепробовал все советы из ответов здесь, но у меня ничего не работает. Но на основе этих фрагментов кода я нашел следующее решение:

По умолчанию установлено m_pPainter->setRenderHint(QPainter::Qt4CompatiblePainting, true) и только для прямоугольников со скругленными углами шириной%2==0 отключите его.

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);
person Ludek Vodicka    schedule 03.12.2014