PyQt5自定义组件之飞机水平仪

PyQt5自定义组件之飞机水平仪

效果如下图:

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *


class GaugePlane(QWidget):
    def __init__(self, parent=None):
        super(GaugePlane, self).__init__(parent)
        self.initUI()

    def initUI(self):
        self.borderOutColorStart = Qt.black
        self.borderOutColorEnd = QColor(23, 149, 166)

        self.borderInColorStart = QColor(50, 50, 50)
        self.borderInColorEnd = QColor(220, 220, 220)


        self.bgColor = QColor(41, 127, 184)
        self.planeColor = QColor("#d68070")
        self.glassColor = QColor(250, 250, 250)
        self.scaleColor = QColor(255, 255, 255)
        self.lineColor = QColor(255, 255, 255)
        self.textColor = QColor(255, 255, 255)
        self.pointerColor = QColor(255, 107, 107)
        self.handleColor = QColor("grey")

        self.degValue = 0  # 倾斜角
        self.rollValue = 0  # 俯仰角

        self.resize(400, 400)

        self.time = QTimer()
        self.time.start(1000)
        self.time.timeout.connect(self.tsetDegValue)

    def paintEvent(self, QPaintEvent):
        width = self.width()
        height = self.height()
        side = min(width, height)

        # 绘制准备工作, 启用反锯齿, 平移坐标轴中心, 等比例缩放
        painter = QPainter(self)
        painter.setRenderHints(QPainter.Antialiasing | QPainter.TextAntialiasing)
        painter.translate(width / 2, height / 2)
        painter.scale(side / 200.0, side / 200.0)

        # 绘制外边框
        self.drawBorderOut(painter)
        # 绘制内边框
        self.drawBorderIn(painter)
        # 绘制背景
        self.drawBg(painter)
        # 绘制姿势仪背景
        self.drawPlane(painter)
        # 绘制玻璃遮罩层
        self.drawGlass(painter)
        # 绘制刻度尺
        self.drawScale(painter)
        # 绘制线条
        self.drawLine(painter)
        # 绘制指针
        self.drawPointer(painter)
        # 绘制手柄
        self.drawHandle(painter)

    def tsetDegValue(self):
        import random
        dev = random.randint(-30, 30)
        roll = random.randint(-30, 30)
        self.setRollValue(roll)
        self.setDegValue(dev)

    def drawBorderOut(self, painter):
        radius = 99
        painter.save()
        painter.setPen(Qt.NoPen)

        borderGradient = QLinearGradient(0, -radius, 0, radius)
        borderGradient.setColorAt(0, self.borderOutColorStart)
        borderGradient.setColorAt(1, self.borderOutColorEnd)
        painter.setBrush(borderGradient)
        painter.drawEllipse(-radius, -radius, radius * 2, radius * 2)
        painter.restore()

    def drawBorderIn(self, painter):
        radius = 93
        painter.save()
        painter.setPen(Qt.NoPen)
        borderGradient = QLinearGradient(0, -radius, 0, radius)
        borderGradient.setColorAt(0, self.borderInColorStart)
        borderGradient.setColorAt(1, self.borderInColorEnd)
        painter.setBrush(borderGradient)
        painter.drawEllipse(-radius, -radius, radius * 2, radius * 2)
        painter.restore()

    def drawBg(self, painter):
        radius = 90
        painter.save()
        painter.setPen(Qt.NoPen)

        borderGradient = QLinearGradient(0, -radius, 0, radius)
        self.bgColor.setAlpha(255)
        borderGradient.setColorAt(0, self.bgColor)
        self.bgColor.setAlpha(150)
        borderGradient.setColorAt(1, self.bgColor)
        painter.setBrush(borderGradient)
        painter.drawEllipse(-radius, -radius, radius * 2, radius * 2)
        painter.restore()

    def drawPlane(self, painter):
        radius = 90
        painter.save()
        painter.rotate(self.degValue)
        painter.setPen(Qt.NoPen)
        painter.setBrush(self.planeColor)
        rect = QRect(-radius, -radius, radius * 2, radius * 2)

        if not painter:
            painter.drawPie(rect, 0, -16 * 180)
        else:
            offset = -(self.rollValue * radius / 60)
            startAngle = 180 + offset
            endAngle = offset
            span = endAngle + startAngle
            painter.drawChord(rect, -16 * startAngle, 16 * span)
        painter.restore()

    def drawGlass(self, painter):
        radius = 80
        painter.save()
        painter.setPen(Qt.NoPen)
        # 饼圆1为整个圆形区域
        pieRect1 = QRect(-radius, -radius, radius * 2, radius * 2)
        # 饼圆2位饼圆1区域的中间部分的四分之一
        pieRect2 = QRect(-radius, -radius / 4, radius * 2, radius / 4 * 2)
        # 颜色线性渐变, 颜色透明度产生立体感
        linearGradient = QLinearGradient(pieRect1.topLeft(), pieRect1.bottomRight())
        self.glassColor.setAlpha(30)
        linearGradient.setColorAt(0.1, self.glassColor)
        self.glassColor.setAlpha(100)
        linearGradient.setColorAt(0.5, self.glassColor)
        # 绘制两个饼圆
        painter.setBrush(linearGradient)
        painter.drawPie(pieRect1, 0, 16 * 180)
        painter.drawPie(pieRect2, 0, -16 * 180)
        painter.restore()

    def drawScale(self, painter):
        radius = 88
        painter.save()
        # 设置画笔颜色
        pen = QPen()
        pen.setColor(self.scaleColor)
        pen.setWidthF(4)
        pen.setCapStyle(Qt.RoundCap)
        painter.setPen(pen)
        # 线条长度
        len = 8
        # 左侧平行线
        painter.rotate(90)
        painter.drawLine(0, radius - len, 0, radius)
        # 逐个绘制大刻度
        for i in range(6):
            painter.rotate(30)
            painter.drawLine(0, radius - len, 0, radius)

        # 回到小刻度,重新设置画笔宽度
        pen.setWidthF(2)
        painter.setPen(pen)
        painter.rotate(-120)
        # 逐个绘制小刻度
        for i in range(5):
            painter.rotate(10)
            painter.drawLine(0, radius - len, 0, radius)
        painter.restore()

    def drawLine(self, painter):
        radius = 95
        painter.save()
        width = self.width()
        height = self.height()
        side = min(width, height)

        # 重置坐标系
        painter.resetTransform()
        painter.translate(width / 2, height / 2 + self.rollValue)
        painter.scale(side / 200.0, side / 200.0)

        painter.rotate(self.degValue)

        # 设置画笔颜色
        pen = QPen()
        pen.setColor(self.lineColor)
        pen.setWidthF(2)
        pen.setCapStyle(Qt.RoundCap)
        painter.setPen(pen)

        # 设置画笔字体
        font = QFont()
        font.setPixelSize(10)
        font.setBold(True)
        painter.setFont(font)

        # 依次绘制水平距离线条及值

        i = -30
        while i <= 30:
            if i == 0:
                # 中心点不用绘制
                i += 10
                continue
            value = qAbs(i)

            # 绘制横向水平线条

            pt1 = QPointF(-radius * value / 100, radius / 70 * i)

            pt2 = QPointF(-pt1.x(), pt1.y())
            painter.drawLine(pt1, pt2)

            # 根据字体大小计算绘制文字的区域
            # strValue = QString.number(value)
            strValue = str(value).replace(".0", "")
            fm = painter.fontMetrics()
            textRect = QRectF(QPointF(QPoint(0, 0)), QSizeF(fm.size(Qt.AlignCenter, strValue)))
            textRect.moveCenter(pt1 - QPointF(radius / 10, 0))
            painter.drawText(textRect, Qt.AlignCenter, strValue)

            textRect.moveCenter(pt2 + QPointF(radius / 10, 0))
            painter.drawText(textRect, Qt.AlignCenter, strValue)
            i += 10
        painter.restore()

    def drawPointer(self, painter):
        radius = 70
        painter.save()
        painter.rotate(self.degValue + 90)
        painter.setPen(Qt.NoPen)
        # 指针长度
        len = 10
        # 三角形坐标
        pts = QPolygon()
        pts.setPoints(-radius, 0, -radius + len, -len / 2, -radius + len, len / 2)
        painter.setBrush(self.pointerColor)
        painter.drawConvexPolygon(pts)
        painter.restore()

    def drawHandle(self, painter):
        painter.save()
        pen = QPen()
        pen.setColor(self.handleColor)
        pen.setWidthF(4)
        pen.setCapStyle(Qt.RoundCap)
        pen.setJoinStyle(Qt.MiterJoin)
        painter.setPen(pen)
        painter.setBrush(self.handleColor)
        # 绘制弧形
        arcRadius = 15
        rect = QRect(-arcRadius, -arcRadius, arcRadius * 2, arcRadius * 2)
        painter.drawArc(rect, 0, -16 * 180)
        # 绘制中心圆
        centerRadius = 2
        rect = QRect(-centerRadius, -centerRadius, centerRadius * 2, centerRadius * 2)
        painter.drawEllipse(rect)

        # 绘制左侧右侧横向水平线条
        len = 30
        pt1 = QPoint(-len, 0)
        pt2 = QPoint(-arcRadius, 0)
        painter.drawLine(pt1, pt2)

        pt1 = QPoint(len, 0)
        pt2 = QPoint(arcRadius, 0)
        painter.drawLine(pt1, pt2)

        # 绘制纵向垂直线条
        pt1 = QPoint(0, len / 2)
        pt2 = QPoint(0, 80)
        painter.drawLine(pt1, pt2)

        # 绘制底部梯形
        p1 = QPoint(-30, 82)
        p2 = QPoint(-20, 60)
        p3 = QPoint(20, 60)
        p4 = QPoint(30, 82)
        pts = QPolygon([p1, p2, p3, p4])

        # pts << p1 << p2 << p3 << p4
        # pts.setPoints()
        painter.drawConvexPolygon(pts)
        # 绘制底部填充圆弧
        radius = 32
        rect = QRect(-radius, 77, radius * 2, 13)
        painter.setPen(Qt.NoPen)
        painter.drawPie(rect, 0, -16 * 180)
        painter.restore()

    def getBorderOutColorStart(self):
        return self.borderOutColorStart

    def getBorderOutColorEnd(self):
        return self.borderOutColorEnd

    def getBorderInColorStart(self):
        return self.borderInColorStart

    def getBorderInColorEnd(self):
        return self.borderInColorEnd

    def getBgColor(self):
        return self.bgColor

    def getPlaneColor(self):
        return self.planeColor

    def getGlassColor(self):
        return self.glassColor

    def getScaleColor(self):
        return self.scaleColor

    def getLineColor(self):
        return self.lineColor

    def getTextColor(self):
        return self.textColor

    def getPointerColor(self):
        return self.pointerColor

    def getHandleColor(self):
        return self.handleColor

    def getDegValue(self):
        return self.degValue

    def getRollValue(self):
        return self.rollValue

    def sizeHint(self):
        return QSize(200, 200)

    def minimumSizeHint(self):
        return QSize(50, 50)

    def setBorderOutColorStart(self, borderOutColorStart):
        if (self.borderOutColorStart != borderOutColorStart):
            self.borderOutColorStart = borderOutColorStart
            self.update()

    def setBorderOutColorEnd(self, borderOutColorEnd):
        if (self.borderOutColorEnd != borderOutColorEnd):
            self.borderOutColorEnd = borderOutColorEnd
            self.update()

    def setBorderInColorStart(self, borderInColorStart):
        if (self.borderInColorStart != borderInColorStart):
            self.borderInColorStart = borderInColorStart
            self.update()

    def setBorderInColorEnd(self, borderInColorEnd):
        if (self.borderInColorEnd != borderInColorEnd):
            self.borderInColorEnd = borderInColorEnd
            self.update()

    def setBgColor(self, bgColor):
        if (self.bgColor != bgColor):
            self.bgColor = bgColor
            self.update()

    def setPlaneColor(self, planeColor):
        if (self.planeColor != planeColor):
            self.planeColor = planeColor
            self.update()

    def setGlassColor(self, glassColor):
        if (self.glassColor != glassColor):
            self.glassColor = glassColor
            self.update()

    def setScaleColor(self, scaleColor):
        if (self.scaleColor != scaleColor):
            self.scaleColor = scaleColor
            self.update()

    def setLineColor(self, lineColor):
        if (self.lineColor != lineColor):
            self.lineColor = lineColor
            self.update()

    def setTextColor(self, textColor):
        if (self.textColor != textColor):
            self.textColor = textColor
            self.update()

    def setPointerColor(self, pointerColor):
        if (self.pointerColor != pointerColor):
            self.pointerColor = pointerColor
            self.update()

    def setHandleColor(self, handleColor):
        if (self.handleColor != handleColor):
            self.handleColor = handleColor
            self.update()

    def setDegValue(self, degValue):
        if (self.degValue != degValue and degValue >= -180 and degValue <= 180):
            self.degValue = degValue
            self.update()

    def setRollValue(self, rollValue):
        if (self.rollValue != rollValue and rollValue >= -100 and rollValue <= 100):
            self.rollValue = rollValue
            self.update()


import sys

if __name__ == '__main__':
    app = QApplication(sys.argv)
    mainWindow = GaugePlane()
    mainWindow.show()
    sys.exit(app.exec_())
posted @ 2020-04-09 15:32  怀心抱素  阅读(1084)  评论(0编辑  收藏  举报