顶级窗口的非像素化圆角

时间:2010-09-30 09:24:44

标签: qt pyqt rounded-corners pyside qdialog

我想在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 个答案:

答案 0 :(得分:1)

显示 here setAttribute(Qt.WA_TranslucentBackground,True)方法也有效...只需在顶级窗口设置此属性,使用 paintEvent()方法覆盖中的QPainterPath绘制窗口的形状。

以下是一些 (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 :(得分:1)

有点迟到这个派对,但也许它会帮助别人。这显示了如何通过在新的QBitmap上绘制来创建一个像素化较少的蒙版(它仍然没有真正抗锯齿,因为位图只有2种颜色,但曲线比直接使用QPainterPath要平滑得多)。

在我的情况下,我想掩盖放置在主窗口内的窗口小部件形状(作为中央窗口小部件)。 4个边缘周围有4个工具栏,我希望中心视图有圆角边框,让主窗口背景显示出来。正如Harald建议的那样,这不是通过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);
}

答案 2 :(得分:-1)

根据您希望对话框看起来如何,您可以通过css完全重新设置窗口,它们遵循框模型,请参阅整个stylesheet文档。

border: 2px; border-radius 2px;

将为您提供2px宽的边框,半径为2px。

我一般你应该能够通过样式表来处理你的大部分ui定制需求