[PyQt] How to make a circular button?

Maurizio Berti maurizio.berti at gmail.com
Tue Mar 3 13:22:11 GMT 2020


You'll have to subclass QPushButton, provide a way to set/change the
radius, and at least override the paintEvent to actually draw the circle
and possibly the sizeHint to report the preferred size of the button (based
on the radius), unless you to set a fixed size when setting the radius.

In the following example I've used two gradients to get a round button with
borders that have a "shadow" effect: it's composed of a conical gradient
with a superimposed radial gradient to "mask" the center of the conical.

class CircleButton(QtWidgets.QPushButton):
    def __init__(self, radius=None, parent=None):
        super().__init__(parent)
        if radius is None:
            radius = self.font().pointSize() * 2
        self.setRadius(radius)

        # use the palette as source for the colors
        palette = self.palette()
        light = palette.color(palette.Light)
        midlight = palette.color(palette.Midlight)
        mid = palette.color(palette.Mid)
        dark = palette.color(palette.Dark)

        # a radial gradient for the "shadow effect" when button is unpressed
        self.backgroundUp = QtGui.QConicalGradient(.5, .5, 135)

self.backgroundUp.setCoordinateMode(self.backgroundUp.ObjectBoundingMode)
        self.backgroundUp.setStops([
            (0.0, light),
            (0.3, dark),
            (0.6, dark),
            (1.0, light),
        ])

        # the same as above, but inverted for pressed state
        self.backgroundDown = QtGui.QConicalGradient(.5, .5, 315)

self.backgroundDown.setCoordinateMode(self.backgroundDown.ObjectBoundingMode)
        self.backgroundDown.setStops(self.backgroundUp.stops())

        # a "mask" for the conical gradient
        self.ringShapeDown = QtGui.QRadialGradient(.5, .5, .5)

self.ringShapeDown.setCoordinateMode(self.ringShapeDown.ObjectBoundingMode)
        self.ringShapeDown.setStops([
            (0.7536231884057971, midlight),
            (0.7960662525879917, QtCore.Qt.transparent),
        ])

        self.ringShapeUp = QtGui.QRadialGradient(.5, .5, .5)

self.ringShapeUp.setCoordinateMode(self.ringShapeUp.ObjectBoundingMode)
        self.ringShapeUp.setStops([
            (0.7536231884057971, mid),
            (0.7960662525879917, QtCore.Qt.transparent),
            (0.9627329192546584, QtCore.Qt.transparent),
        ])

    def getButtonRect(self):
        # just a helper function to avoid repetitions
        size = min(self.width(), self.height()) - 1
        rect = QtCore.QRect(0, 0, size, size)
        rect.moveCenter(self.rect().center())
        return rect

    def mousePressEvent(self, event):
        # ensure that the click happens within the circle
        path = QtGui.QPainterPath()
        path.addEllipse(QtCore.QRectF(self.getButtonRect()))
        if path.contains(event.pos()):
            super().mousePressEvent(event)

    def setRadius(self, radius):
        self.radius = radius
        # notify the layout manager that the size hint has changed
        self.updateGeometry()

    def sizeHint(self):
        return QtCore.QSize(self.radius, self.radius)

    def hasHeightForWidth(self):
        return True

    def heightForWidth(self, width):
        return width

    def paintEvent(self, event):
        qp = QtGui.QPainter(self)
        qp.setRenderHints(qp.Antialiasing)
        qp.translate(.5, .5)
        qp.setPen(QtCore.Qt.NoPen)
        rect = self.getButtonRect()
        if self.isDown() or self.isChecked():
            qp.setBrush(self.backgroundDown)
            qp.drawEllipse(rect)
            qp.setBrush(self.ringShapeDown)
            qp.drawEllipse(rect)
        else:
            qp.setBrush(self.backgroundUp)
            qp.drawEllipse(rect)
            qp.setBrush(self.ringShapeUp)
            qp.drawEllipse(rect)

Il giorno mar 3 mar 2020 alle ore 13:08 Souvik Dutta Chowdhury <
souvik.viksou at outlook.com> ha scritto:

> I want to make a perfect circular button and want to set a custom radius.
> How to do it?
> _______________________________________________
> PyQt mailing list    PyQt at riverbankcomputing.com
> https://www.riverbankcomputing.com/mailman/listinfo/pyqt
>


-- 
È difficile avere una convinzione precisa quando si parla delle ragioni del
cuore. - "Sostiene Pereira", Antonio Tabucchi
http://www.jidesk.net
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20200303/d9e425c4/attachment.htm>


More information about the PyQt mailing list