Qt Custom CheckBox,关于PaintEvent的帮助

Qt Custom CheckBox, help about PaintEvent

我正在尝试创建自定义复选框。我正在使用 paintEvent 函数来创建我的特殊复选框。 它的设计:

Qt 上的结果:

首先要加上圆角,线条的交接处要有更平滑的过渡。 我需要更专业的解决方案。这很漂亮。 谢谢! 代码:

import sys, os, time
from PySide6 import QtCore, QtWidgets, QtGui
from PySide6.QtWidgets import *
from PySide6.QtCore import *
from PySide6.QtGui import *
    
class ECheckBoxData(object):
    Radius = 10
    AnimationTime = 600  # ms
    FontSize, FontSpacing = 16, 0
    Color = {
        "CORNER": QColor(239, 239, 239),
        "BASE_BACKGROUND": QColor(255, 125, 51),
        "BASE_FOREGROUND": QColor(255, 152, 91),

        "BASE_HOVER_BACKGROUND" :QColor(255, 152, 91),
        "BASE_HOVER_FOREGROUND": QColor(247, 247, 250),

    }
    TextElide = Qt.ElideMiddle
    CheckWidth, CheckHeight = 128, 128    


class ECheckBox(QCheckBox):
    CheckBoxData = ECheckBoxData()
   
    def __init__(self, CheckBoxData=ECheckBoxData()):
        super(ECheckBox, self).__init__(None)
        self.CheckBoxData = CheckBoxData
            
        self.myfont = QFont("Times New Roman", 16, weight=QFont.Bold)
        self.myfont.setWordSpacing(self.CheckBoxData.FontSpacing)
        self.myfont.setStyleHint(QFont.Monospace)
        self.myfontMetrics = QFontMetrics(self.myfont)
        # font.setStyleHint(QFont.Times, QFont.PreferAntialias)
        self.setFont(self.myfont)
        self.setFixedHeight(self.CheckBoxData.CheckHeight+2)
        self.setMinimumWidth(self.CheckBoxData.CheckWidth+8)
       
    def paintEvent(self, event: QPaintEvent):
        pt = QPainter(self)
        pt.setRenderHints(QPainter.Antialiasing | QPainter.TextAntialiasing )
        border = QPainterPath()
        pt.setBrush(self.CheckBoxData.Color["BASE_BACKGROUND"])
        pt.setPen(QPen(self.CheckBoxData.Color["CORNER"],5))
        border.addRoundedRect(QRectF(2,2,self.CheckBoxData.CheckWidth-2, self.CheckBoxData.CheckHeight-2),self.CheckBoxData.Radius, self.CheckBoxData.Radius)

        pt.drawPath(border)
        pt.setClipPath(border)

        pt.setPen(QPen(Qt.white,self.CheckBoxData.CheckWidth/10))
        pt.setBrush(Qt.white)
        path2 = QPainterPath()
        arrow_width, arrow_height = self.width()/4, self.height()/ (66/8)
        center_width, center_height = int(self.width()/2), int(self.height()/2)

        #path2.moveTo((self.width() - arrow_width * 2) / 2, (center_height + 2))
        #path2.lineTo(QPoint((self.width() - arrow_width) / 2 + 2, (center_height) + arrow_height + 1))
        #path2.lineTo(QPoint((self.width()-arrow_width), (center_height)-arrow_height))
        path2.addPolygon(QPolygonF([
            QPoint((self.width()-arrow_width*2)/2, (center_height+2)), QPoint((self.width()-arrow_width)/2+2, (center_height)+arrow_height+1)
        ]))
        path2.addPolygon(QPolygonF([QPoint((self.width()-arrow_width)/2+2, (center_height)+arrow_height+1), QPoint((self.width()-arrow_width-12), (center_height)-arrow_height)]))
        
        pt.drawPath(path2)
          


if __name__ == "__main__":
    app = QApplication(sys.argv)
    wind = QMainWindow()
    wind.setStyleSheet("QMainWindow{background-color:rgb(247,247,250)}")
    wind.resize(221, 150)
    wid = QWidget()
    lay = QHBoxLayout(wid)
    lay.setAlignment(Qt.AlignCenter)    
    Data = ECheckBoxData()
    e = ECheckBox(Data)
    e.setChecked(True)    
    lay.addWidget(e)
    wind.setCentralWidget(wid)
    wind.show()
    sys.exit(app.exec())

为了创建平滑和弯曲的轮廓,您需要正确设置 QPen cap and join 样式。

用多边形画轮廓显然不是一个有效的解决方案,因为轮廓会用笔画出来,但你需要的是一个路径来画使用 笔和首选的帽和连接样式。

此外,为了能够在不同尺寸下绘制出好的图标,您不应依赖固定尺寸(即使计算正确),而应使用当前尺寸作为参考。

    def paintEvent(self, event: QPaintEvent):
        pt = QPainter(self)
        pt.setRenderHints(QPainter.Antialiasing | QPainter.TextAntialiasing)

        size = min(self.width(), self.height())
        border = max(1, size / 32)
        rect = QRectF(0, 0, size - border, size - border)
        # move the square to the *exact* center using a QRectF based on the
        # current widget; note: it is very important that you get the center
        # using a QRectF, because the center of QRect is always in integer
        # values, and will almost always be imprecise at small sizes
        rect.moveCenter(QRectF(self.rect()).center())

        borderPath = QPainterPath()
        # with RelativeSize we can specify the radius as 30% of half the size
        borderPath.addRoundedRect(rect, 30, 30, Qt.RelativeSize)

        pt.setBrush(self.CheckBoxData.Color["BASE_BACKGROUND"])
        pt.setPen(QPen(self.CheckBoxData.Color["CORNER"], border * 2.5))
        pt.drawPath(borderPath)

        pt.setPen(QPen(Qt.white, size * .125, 
            cap=Qt.RoundCap, join=Qt.RoundJoin))
        arrow_path = QPainterPath()
        arrow_path.moveTo(size * .25, size * .5)
        arrow_path.lineTo(size * .40, size * .65)
        arrow_path.lineTo(size * .7, size * .325)
        pt.drawPath(arrow_path.translated(rect.topLeft()))