使用Qt画一个带边框的填充圆角矩形

33

我想用特定的颜色填充整个带有圆角(四个角的边框半径相同)的矩形,并使用单独的边框颜色(假设边框宽度为1像素)。

根据我的观察,Qt提供了三种方法——fillRectdrawRectdrawRoundedRect。我已经尝试过它们,但它们不符合我的要求。没有像fillRoundedRect这样的方法。这意味着我可以绘制一个圆角矩形,但它不会被我想要的颜色填充。

我该怎么做呢?另外,我读到由于一些别名问题,角经常被渲染为不平等。如何设置所有四个角都相等?painter.setRenderHint(QPainter::Antialiasing)就足够了吗?还是我还需要做其他操作?


我并不是Qt方面的专家,但我非常确定我已经看到过这个问题出现了很多次 :-P ... - πάντα ῥεῖ
1
只有一个回答,我已经看过它。我仍然会提问,因为它没有解决边界问题和可能出现的角落不平整的问题。 - SexyBeast
另外,如果您在参考此问题 - https://dev59.com/QG_Xa4cB1Zd3GeqP0WFs,它也没有解释如何填充矩形颜色。 - SexyBeast
2个回答

77

您可以创建一个QPainterPath,将圆角矩形添加到其中,然后填充和描边:

QPainter p(this);
p.setRenderHint(QPainter::Antialiasing);
QPainterPath path;
path.addRoundedRect(QRectF(10, 10, 100, 50), 10, 10);
QPen pen(Qt::black, 10);
p.setPen(pen);
p.fillPath(path, Qt::red);
p.drawPath(path);

请注意,即使开启了抗锯齿功能,在低DPI的桌面显示器上,1像素边框可能永远不会真正好看,在高DPI的移动设备上几乎看不见。

图片描述

如果您将矩形创建为 QRectF(9.5, 9.5, 100, 50),它将使用1像素抗锯齿边框效果更佳,因为它会“吸附”在正确的像素上:

图片描述


运行得非常好!但是,我需要一个细边框,比如1像素宽度。当我改变宽度时,边框在角落处看起来有点粗糙和锯齿状。即使使用了抗锯齿技术也无济于事。有什么解决办法吗? - SexyBeast
@hkBattousai - 如果你在小部件上绘画,则在其绘画事件中,如果你在另一个绘画设备上绘画,那是无关紧要的。 - dtech

2
上面的答案(来自@dtech)非常好,但有时会出现在roundedRect周围不均匀的边框。使用QPainter.strokePath()而不是QPainter.drawPath()可以解决这个问题。
下面是一个重新实现了paintEventQPushButton的python实现:
# I use PySide6, but whatever library should work.
from PySide6.QtWidgets import QPushButton
from PySide6.QtGui import QPainter, QPainterPath, QBrush, QPen
from PySide6.QtCore import Qt, QRectF

class RoundedButton(QPushButton):
    def __init__(self, text, bordersize, outlineColor, fillColor):
        super(RoundedButton, self).__init__()
        self.bordersize = bordersize
        self.outlineColor = outlineColor
        self.fillColor = fillColor
        self.setText(text)

    def paintEvent(self, event):
        # Create the painter
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        # Create the path
        path = QPainterPath()
        # Set painter colors to given values.
        pen = QPen(self.outlineColor, self.bordersize)
        painter.setPen(pen)
        brush = QBrush(self.fillColor)
        painter.setBrush(brush)

        rect = QRectF(event.rect())
        # Slighly shrink dimensions to account for bordersize.
        rect.adjust(self.bordersize/2, self.bordersize/2, -self.bordersize/2, -self.bordersize/2)

        # Add the rect to path.
        path.addRoundedRect(rect, 10, 10)
        painter.setClipPath(path)

        # Fill shape, draw the border and center the text.
        painter.fillPath(path, painter.brush())
        painter.strokePath(path, painter.pen())
        painter.drawText(rect, Qt.AlignCenter, self.text())

1
此问题专门标记为 C++ 问题。请避免添加其他语言的答案,因为这会给答案增加噪音并可能导致未来读者混淆。 - Hoppeduppeanut
6
Qt这个案例比较特殊,因为它有许多语言的绑定,但是Python的活动很多,所以举个例子会有很大帮助。这不是关于C++本身,而是关于Qt技术的问题。 - eyllanesc
@eyllanesc 我会记住这个,当我回答其他Qt问题的时候。 - Umbral Reaper
@UmbralReaper 将 rect = QRectF( ... 更改为 rect.adjust(bordersize/2, bordersize/2, -bordersize, -bordersize) - eyllanesc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接