PyQt5 异形按钮

image.png

代码:


class UIButton(QWidget):
    btn_width = 20
    btn_height = 20
    top_margin = 10
    side_margin = 10

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # self.pix = QBitmap("./Resources/Images/back.png")
        # print(self.pix.size())
        # self.resize(self.pix.size())
        self.setFixedSize(300, 300)
        self.outerPieRadius = 100

        self.mouseCenterView = False
        self.mouseBottomView = False
        self.mouseRightView = False
        self.mouseTopView = False
        self.mouseLeftView = False

        self.mouseOuterCream = False
        self.outerChampagnePercent = 90

        self.setMouseTracking(True)  # 设置鼠标自动跟踪


    def drawOuterPie(self, painter):
        """
        绘制右侧按钮
        :param painter:
        :return:
        """
        painter.save()
        # 以下绘图保存至painter的坐标系统
        # 设置标志位,判断鼠标是否进入该区域。如果进入该区域,则半径扩大
        if self.mouseRightView:
            radius1 = self.outerPieRadius + 4
        else:
            radius1 = self.outerPieRadius

        # 绘制大扇形

        rect = QtCore.QRectF(-radius1/2, -radius1/2, radius1, radius1)  # 该扇形饼圆所在的region
        pathOuterChampagnePie = QtGui.QPainterPath()  # 新建QPainterPath对象
        pathOuterChampagnePie.arcMoveTo(rect, -45)  # 画弧线的起点角度,从0°开始
        pathOuterChampagnePie.arcTo(rect, -45, 90)  # 扇形饼圆弧度为self.outerChampagnePercent * 360
        pathOuterChampagnePie.lineTo(0, 0)  # 画直线
        pathOuterChampagnePie.closeSubpath()  # 使该路径闭合
        pathOuterChampagnePie.addText(radius1 / 2 - 18, 5, painter.font(), "+X")
       
        # painter.restore()
        # 以下同理绘制小扇形
        radius = 50
        rect1 = QtCore.QRectF(-radius/2, -radius/2, radius, radius)
        pathMidPie = QtGui.QPainterPath()
        pathMidPie.arcMoveTo(rect1, -45)
        pathMidPie.arcTo(rect1, -45, 90)
        pathMidPie.lineTo(0, 0)
        pathMidPie.closeSubpath()

        # 大扇形减去小扇形,得到扇形饼圆
        self.rightBtnView = pathOuterChampagnePie.subtracted(pathMidPie)
        painter.setPen(Qt.NoPen)  # 边框线条无色
        painter.setBrush(Qt.gray)
        painter.drawPath(self.rightBtnView)
        #
        painter.restore()  # 恢复坐标系

    def drawOuterCircle(self, painter):
        """
            绘制顶部按钮
             :param painter:
             :return:
             """
        painter.save()
        # 以下绘图保存至painter的坐标系统
        # 设置标志位,判断鼠标是否进入该区域。如果进入该区域,则半径扩大
        if self.mouseTopView:
            radius1 = self.outerPieRadius + 4
        else:
            radius1 = self.outerPieRadius

        # 绘制大扇形

        rect = QtCore.QRectF(-radius1 / 2, -radius1 / 2, radius1, radius1)  # 该扇形饼圆所在的region
        pathOuterChampagnePie = QtGui.QPainterPath()  # 新建QPainterPath对象
        pathOuterChampagnePie.arcMoveTo(rect, 45)  # 画弧线的起点角度,从0°开始
        pathOuterChampagnePie.arcTo(rect, 45, 90)  # 扇形饼圆弧度为self.outerChampagnePercent * 360
        pathOuterChampagnePie.lineTo(0, 0)  # 画直线
        pathOuterChampagnePie.closeSubpath()  # 使该路径闭合
        pathOuterChampagnePie.addText(-8, -radius1 / 2 + 15, painter.font(), "+Y")
 
        # painter.restore()
        # 以下同理绘制小扇形
        radius = 50
        rect1 = QtCore.QRectF(-radius / 2, -radius / 2, radius, radius)
        pathMidPie = QtGui.QPainterPath()
        pathMidPie.arcMoveTo(rect1, 45)
        pathMidPie.arcTo(rect1, 45, 90)
        pathMidPie.lineTo(0, 0)
        pathMidPie.closeSubpath()

        # 大扇形减去小扇形,得到扇形饼圆
        self.topBtnView = pathOuterChampagnePie.subtracted(pathMidPie)
        painter.setPen(Qt.NoPen)  # 边框线条无色
        painter.setBrush(Qt.yellow)
        painter.drawPath(self.topBtnView)
        #
        painter.restore()  # 恢复坐标系

    def drawInnerPie(self, painter):
        """
             绘制左侧按钮
             :param painter:
             :return:
             """
        painter.save()
        # 以下绘图保存至painter的坐标系统
        # 设置标志位,判断鼠标是否进入该区域。如果进入该区域,则半径扩大
        if self.mouseLeftView:
            radius1 = self.outerPieRadius + 4
        else:
            radius1 = self.outerPieRadius

        # 绘制大扇形

        rect = QtCore.QRectF(-radius1 / 2, -radius1 / 2, radius1, radius1)  # 该扇形饼圆所在的region
        pathOuterChampagnePie = QtGui.QPainterPath()  # 新建QPainterPath对象
        pathOuterChampagnePie.arcMoveTo(rect, 135)  # 画弧线的起点角度,从0°开始
        pathOuterChampagnePie.arcTo(rect, 135, 90)  # 扇形饼圆弧度为self.outerChampagnePercent * 360
        pathOuterChampagnePie.lineTo(0, 0)  # 画直线
        pathOuterChampagnePie.closeSubpath()  # 使该路径闭合
        pathOuterChampagnePie.addText(-radius1 / 2 + 5, 5, painter.font(), "-X")
      
        # 以下同理绘制小扇形
        radius = 50
        rect1 = QtCore.QRectF(-radius / 2, -radius / 2, radius, radius)
        pathMidPie = QtGui.QPainterPath()
        pathMidPie.arcMoveTo(rect1, 135)
        pathMidPie.arcTo(rect1, 135, 90)
        pathMidPie.lineTo(0, 0)
        pathMidPie.closeSubpath()

        # 大扇形减去小扇形,得到扇形饼圆
        self.leftBtnView = pathOuterChampagnePie.subtracted(pathMidPie)
        painter.setPen(Qt.NoPen)  # 边框线条无色
        painter.setBrush(Qt.darkGreen)  # 填充颜色
        painter.drawPath(self.leftBtnView)
        #
        painter.restore()  # 恢复坐标系

    def drawBottom(self, painter):
        """
             绘制底部按钮
             :param painter:
             :return:
             """
        painter.save()
        # 以下绘图保存至painter的坐标系统
        # 设置标志位,判断鼠标是否进入该区域。如果进入该区域,则半径扩大
        if self.mouseBottomView:
            radius1 = self.outerPieRadius + 4
        else:
            radius1 = self.outerPieRadius

        # 绘制大扇形

        rect = QtCore.QRectF(-radius1 / 2, -radius1 / 2, radius1, radius1)  # 该扇形饼圆所在的region
        pathOuterChampagnePie = QtGui.QPainterPath()  # 新建QPainterPath对象
        pathOuterChampagnePie.arcMoveTo(rect, 225)  # 画弧线的起点角度,从0°开始
        pathOuterChampagnePie.arcTo(rect, 225, 90)  # 扇形饼圆弧度为self.outerChampagnePercent * 360
        pathOuterChampagnePie.lineTo(0, 0)  # 画直线
        pathOuterChampagnePie.closeSubpath()  # 使该路径闭合
        pathOuterChampagnePie.addText(-8, radius1/2-5, painter.font(), "-Y")

        # 以下同理绘制小扇形
        radius = 50
        rect1 = QtCore.QRectF(-radius / 2, -radius / 2, radius, radius)
        pathMidPie = QtGui.QPainterPath()
        pathMidPie.arcMoveTo(rect1, 225)
        pathMidPie.arcTo(rect1, 225, 90)
        pathMidPie.lineTo(0, 0)
        pathMidPie.closeSubpath()

        # 大扇形减去小扇形,得到扇形饼圆
        self.bottomBtnView = pathOuterChampagnePie.subtracted(pathMidPie)
        painter.setPen(Qt.NoPen)  # 边框线条无色
        painter.setBrush(Qt.blue)
        painter.drawPath(self.bottomBtnView)
        #
        painter.restore()  # 恢复坐标系

    def drawMidCircle(self, painter):
        """
        中间按钮
        :param painter:
        :return:
        """
        if self.mouseCenterView:
            radius = 40 + 4
        else:
            radius = 40
        painter.save()
        painter.setPen(Qt.NoPen)
        painter.setBrush(Qt.red)
        path = QtGui.QPainterPath()
        path.addEllipse(-radius/2, -radius/2, radius, radius)
        path.addText(-10, 5, painter.font(), "home")
        painter.drawPath(path)
        self.centerBtnView = path
        # painter.drawEllipse(-radius/2, -radius/2, radius, radius)
        painter.restore()
        font = QFont()

    def paintEvent(self, event):
        # 绘制准备工作, 启用反锯齿
        painter = QtGui.QPainter(self)
        painter.setRenderHints(QtGui.QPainter.Antialiasing | QtGui.QPainter.TextAntialiasing)

        # 平移坐标中心,等比例缩放
        width = self.width()
        height = self.height()
        side = min(width, height)
        painter.translate(width / 2, height / 2)  # 坐标中心移至窗口中心位置
        painter.scale(side / 200.0, side / 200.0)  # 坐标刻度缩放为原来的(side/200)倍

        # 画圆
        self.drawOuterCircle(painter)  # 绘制顶部按钮
        self.drawMidCircle(painter)  # 绘制中间按钮
        self.drawOuterPie(painter)  # 绘制右侧按钮
        self.drawInnerPie(painter)  # 绘制左侧按钮
        self.drawBottom(painter)  # 绘制底部按钮
        # self.drawLegend(painter)  # 绘制图例
        # self.drawTitle(painter)  # 绘制左上角文字

    def mouseMoveEvent(self, event):
        print('鼠标移动')
        print(event.pos)
        # 坐标系转换,和之前painter转换坐标系相对应
        width = self.width()
        height = self.height()
        side = min(width, height)
        enterPoint = QtCore.QPoint((event.pos().x() - width / 2) / side * 200.0,
                                   (event.pos().y() - height / 2) / side * 200.0)

        # 判断鼠标是否进入,并置标志位
        if self.centerBtnView.contains(enterPoint):
            self.mouseCenterView = True
        else:
            self.mouseCenterView = False

        if self.bottomBtnView.contains(enterPoint):
            self.mouseBottomView = True
        else:
            self.mouseBottomView = False

        if self.rightBtnView.contains(enterPoint):
            self.mouseRightView = True
        else:
            self.mouseRightView = False

        if self.topBtnView.contains(enterPoint):
            self.mouseTopView = True
        else:
            self.mouseTopView = False

        if self.leftBtnView.contains(enterPoint):
            self.mouseLeftView = True
        else:
            self.mouseLeftView = False

        self.update()  # 重绘

    def mousePressEvent(self, a0: QtGui.QMouseEvent) -> None:
        width = self.width()
        height = self.height()
        side = min(width, height)
        enterPoint = QtCore.QPoint((a0.pos().x() - width / 2) / side * 200.0,
                                   (a0.pos().y() - height / 2) / side * 200.0)
        # 判断鼠标是否进入,并置标志位
        if self.centerBtnView.contains(enterPoint):
            print("centerBtnView")

        if self.bottomBtnView.contains(enterPoint):
            print("bottomBtnView")

        if self.rightBtnView.contains(enterPoint):
            print('rightBtnView')

        if self.topBtnView.contains(enterPoint):
            print('topBtnView')

        if self.leftBtnView.contains(enterPoint):
            print('leftBtnView')
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,108评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,699评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,812评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,236评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,583评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,739评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,957评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,704评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,447评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,643评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,133评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,486评论 3 256
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,151评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,889评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,782评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,681评论 2 272

推荐阅读更多精彩内容