问题
I want to set rounded corners on a QDialog. Since it is a top-level window, border-radius doesn't work, so I've to do this :
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;
}
and I call it this way :
this->setMask(roundedRect(this->rect(), 8));
It works, but the problem is that corners are pixelized.
Is there a way to get it without having these pixelized corners ? If yes, how ?
回答1:
The setAttribute( Qt.WA_TranslucentBackground, True) method shown here also works... Simply set this attribute on your top-level window, and paint the shape of your window using a QPainterPath in a paintEvent() method override.
Here's some (python) code that might help you construct, or paint, the QPainterPath for a rectangle with rounded corners.
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 )
回答2:
Kinda late to this party, but maybe it will help someone else. This shows how to create an less pixelated mask by drawing on top of a new QBitmap (it's still not really antialiased because a bitmap has only 2 colors, but the curve is much smoother than using a QPainterPath directly).
In my case I wanted to mask a widget shape which is placed within a main window (as central widget). There are 4 toolbars around the 4 edges, and I wanted the center view to have rounded borders and let the main window background show through. This was not doable via CSS as Harald suggests since the contents of the widget didn't actually clip to the rounded border.
// 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);
}
It's in resizeEvent because it needs to know the current widget size (using size()
and geometry()
). Here's a shorter alternative of the original post (I think), but the rounded edges do get pixelated.
void MainView::resizeEvent(QResizeEvent *event)
{
QPainterPath path;
path.addRoundedRect(geometry(), 20.0f, 20.0f, Qt::AbsoluteSize);
QRegion region = QRegion(path.toFillPolygon().toPolygon());
setMask(region);
}
回答3:
Depending on what you want the dialog to look like you can completely restyle even toplevel windows via css, they adhere to the box model see the whole stylesheet documentation.
border: 2px; border-radius 2px;
Will give you a 2px wide border with a radius of 2px.
I general you should be able to handle most of your ui customisation needs through the stylesheets
来源:https://stackoverflow.com/questions/3829317/non-pixelized-rounded-corner-for-top-level-window