Непиксельный закругленный угол для окна верхнего уровня - PullRequest
4 голосов
/ 30 сентября 2010

Я хочу установить закругленные углы на QDialog. Поскольку это окно верхнего уровня, border-radius не работает, поэтому я должен сделать это:

QRegion EnterPinDialog::roundedRect(const QRect& rect, int r)
{
    QRegion region;

    // middle and borders
    region += rect.adjusted(r, 0, -r, 0);
    region += rect.adjusted(0, r, 0, -r);

    // top left
    QRect corner(rect.topLeft(), QSize(r*2, r*2));
    region += QRegion(corner, QRegion::Ellipse);

    // top right
    corner.moveTopRight(rect.topRight());
    region += QRegion(corner, QRegion::Ellipse);

    // bottom left
    corner.moveBottomLeft(rect.bottomLeft());
    region += QRegion(corner, QRegion::Ellipse);

    // bottom right
    corner.moveBottomRight(rect.bottomRight());
    region += QRegion(corner, QRegion::Ellipse);

    return region;
}

и я называю это так:

this->setMask(roundedRect(this->rect(), 8));

Это работает, но проблема в том, что углы пикселизированы.

Есть ли способ получить его без этих пикселизированных углов? Если да, то как?

Ответы [ 3 ]

1 голос
/ 04 января 2012

setAttribute (Qt.WA_TranslucentBackground, True) * Показанный метод здесь также работает ... Просто установите этот атрибут в окне верхнего уровня, и Нарисуйте форму вашего окна, используя QPainterPath в paintEvent () переопределении метода.

Вот некоторый (python) код, который может помочь вам построить или нарисовать QPainterPath для прямоугольника с закругленными углами.

def drawPartiallyRoundedRect(painter,x,y,w,h, 
                             radiusTR, radiusBR, radiusBL, radiusTL,
                             doFill,fillColor,
                             doLine=False,lineColor=None,lineWidth=1,
                             antiAlias=True):


    w2 = int(w/2.0)
    h2 = int(h/2.0)


    if (doLine):
        x += lineWidth/2.0
        y += lineWidth/2.0
        w -= lineWidth
        h -= lineWidth


    T = y
    L = x
    R = x + w
    B = y + h

    # clamp values to fit within rect
    if (radiusTR > w2):
        radiusTR = w2
    if (radiusTR > h2):
        radiusTR = h2

    if (radiusTL > w2):
        radiusTL = w2
    if (radiusTL > h2):
        radiusTL = h2

    if (radiusBL > w2):
        radiusBL = w2
    if (radiusBL > h2):
        radiusBL = h2

    if (radiusBR > w2):
        radiusBR = w2
    if (radiusBR > h2):
        radiusBR = h2

    diamTR  = radiusTR + radiusTR
    diamBR  = radiusBR + radiusBR
    diamBL  = radiusBL + radiusBL
    diamTL  = radiusTL + radiusTL

    p = QPainterPath()
    if (radiusTR > 0.0):
        p.moveTo(R, T + radiusTR);
        p.arcTo(R-diamTR, T, diamTR, diamTR, 0.0, 90.0)  # TR
    else:
        p.moveTo(R,T)

    if (radiusTL > 0.0):
        p.arcTo(L, T, diamTL, diamTL, 90.0, 90.0)  # TL
    else:
        p.lineTo(L,T)

    if (radiusBL > 0.0):
        p.arcTo(L, B-diamBL, diamBL, diamBL, 180.0, 90.0);  # BL
    else:
        p.lineTo(L,B)

    if (radiusBR > 0.0):
        p.arcTo(R-diamBR, B-diamBR, diamBR, diamBR, 270.0, 90.0);  # BR
    else:
        p.lineTo(R,B)

    p.closeSubpath();

    if (antiAlias):
        painter.setRenderHint(QPainter.Antialiasing,True)
    else:
        painter.setRenderHint(QPainter.Antialiasing,False)

    if (doFill and fillColor):
        painter.setBrush( fillColor )
    elif ( doFill ): # pass doFill and None for fillColor to use current brush
        pass
    else:
        painter.setBrush( Qt.NoBrush )

    if ((lineWidth != 0.0) and doLine and lineColor):
        pen = QPen( lineColor, lineWidth,
                    Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin )
        painter.setPen( pen )
    else:
        painter.setPen( Qt.NoPen )

    painter.drawPath( p )
1 голос
/ 26 марта 2014

Вроде поздно на эту вечеринку, но, возможно, это поможет кому-то еще.Это показывает, как создать менее точечную маску, рисуя поверх нового QBitmap (он все еще не является сглаженным, потому что растровое изображение имеет только 2 цвета, но кривая намного более гладкая, чем прямое использование QPainterPath).

В моем случае я хотел замаскировать форму виджета, которая находится в главном окне (как центральный виджет).Есть 4 панели инструментов вокруг 4 краев, и я хотел, чтобы центральный вид имел закругленные границы и позволял фону основного окна просвечивать.Это не удалось сделать с помощью CSS, как предполагает Харальд, поскольку содержимое виджета фактически не обрезалось до скругленной границы.

// MainView is simply a QWidget subclass.
void MainView::resizeEvent(QResizeEvent *event)
{
    QBitmap bmp(size());
    bmp.clear();
    QPainter painter(&bmp);
    painter.setRenderHint(QPainter::Antialiasing, true);
    painter.setPen(QColor(Qt::black));
    painter.setBrush(QColor(Qt::black));
    painter.drawRoundedRect(geometry(), 20.0f, 20.0f, Qt::AbsoluteSize);
    setMask(bmp);
}

Он находится в resizeEvent, потому что ему нужно знать текущий размер виджета (используя size() и geometry()).Вот более короткая альтернатива оригинальному сообщению (я думаю), но закругленные края становятся пикселизированными.

void MainView::resizeEvent(QResizeEvent *event)
{
    QPainterPath path;
    path.addRoundedRect(geometry(), 20.0f, 20.0f, Qt::AbsoluteSize);
    QRegion region = QRegion(path.toFillPolygon().toPolygon());
    setMask(region);
}
0 голосов
/ 30 сентября 2010

В зависимости от того, как вы хотите, чтобы диалоговое окно выглядело так, как вы можете полностью перекомпилировать даже окна верхнего уровня через css, они придерживаются блочной модели, см. Всю документацию таблицы стилей .

border: 2px; border-radius 2px;

Даст вам границу шириной 2 пикселя с радиусом 2 пикселя.

В целом, вы должны быть в состоянии справиться с большинством потребностей пользовательского интерфейса с помощью таблиц стилей

...