前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >PyQt 自定义窗口部件(三)

PyQt 自定义窗口部件(三)

作者头像
用户6021899
发布2019-08-14 16:40:40
5560
发布2019-08-14 16:40:40
举报

本篇介绍用如何QPainter()画出一个可以显示混合流体流速的Y形管控件。

Y形管由abci、edcf 以及cihgf三部分组成,内部的颜色由流体的流速决定。各个部分均使用逻辑坐标系绘制。

代码如下:

代码语言:javascript
复制
from PyQt5.QtWidgets import (QApplication,QFrame, QLabel,QSizePolicy, QSpinBox, QWidget)
from PyQt5.QtGui import QColor,QPainter,QFontMetricsF,QBrush,QLinearGradient,QPolygon,QPolygonF
from PyQt5.QtCore import QPointF, QSize, Qt,pyqtSignal

class YPipeWidget(QWidget):
    signal_valuechanged = pyqtSignal(int,int)
    def __init__(self, leftFlow=0, rightFlow=0, maxFlow=100, parent=None):
        super(YPipeWidget, self).__init__(parent)
        
        self.leftSpinBox = QSpinBox(self)
        self.leftSpinBox.setRange(0, maxFlow)
        self.leftSpinBox.setValue(leftFlow)
        self.leftSpinBox.setSuffix(" l/s")#设置后缀
        self.leftSpinBox.setAlignment(Qt.AlignRight|Qt.AlignVCenter)
        self.leftSpinBox.valueChanged.connect(self.valueChanged)
        
        self.rightSpinBox = QSpinBox(self)
        self.rightSpinBox.setRange(0, maxFlow)
        self.rightSpinBox.setValue(rightFlow)
        self.rightSpinBox.setSuffix(" l/s")#设置后缀
        self.rightSpinBox.setAlignment(Qt.AlignRight|Qt.AlignVCenter)
        self.rightSpinBox.valueChanged.connect(self.valueChanged)
        self.label = QLabel(self)
        self.label.setFrameStyle(QFrame.StyledPanel|QFrame.Sunken)
        self.label.setAlignment(Qt.AlignCenter)
        fm = QFontMetricsF(self.font())
        self.label.setMinimumWidth(fm.width(" 999 l/s "))
        self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding))#横向竖向均可放大
        self.setMinimumSize(self.minimumSizeHint())
        self.valueChanged()

    def valueChanged(self):
        a = self.leftSpinBox.value()
        b = self.rightSpinBox.value()
        self.label.setText("{0} l/s".format(a + b))
        self.signal_valuechanged.emit(a,b)
        self.update()

    def values(self):
        return self.leftSpinBox.value(), self.rightSpinBox.value()
    def minimumSizeHint(self):
        return QSize(self.leftSpinBox.width() * 3,self.leftSpinBox.height() * 5)
    def resizeEvent(self, event=None):
        fm = QFontMetricsF(self.font())
        x = (self.width() - self.label.width()) / 2
        y = self.height() - (fm.height() * 1.5)
        self.label.move(x, y)
        y = self.height() / 60.0
        x = (self.width() / 4.0) - self.leftSpinBox.width()
        self.leftSpinBox.move(x, y)
        x = self.width() - (self.width() / 4.0)
        self.rightSpinBox.move(x, y)
    def paintEvent(self, event=None):
        LogicalSize = 100.0
        
        def logicalFromPhysical(length, side):
            return (length / side) * LogicalSize
        
        fm = QFontMetricsF(self.font())
        ymargin = ((LogicalSize / 30.0) +logicalFromPhysical(self.leftSpinBox.height(),self.height()))
        ymax = (LogicalSize - logicalFromPhysical(fm.height() * 2, self.height()))
        width = LogicalSize / 4.0
        #设置Y形管 9 个角点的坐标
        cx, cy = LogicalSize / 2.0, LogicalSize / 3.0
        ax, ay = cx - (2 * width), ymargin
        bx, by = cx - width, ay
        dx, dy = cx + width, ay
        ex, ey = cx + (2 * width), ymargin
        fx, fy = cx + (width / 2), cx + (LogicalSize / 24.0)
        gx, gy = fx, ymax
        hx, hy = cx - (width / 2), ymax
        ix, iy = hx, fy
        painter = QPainter(self)# 创建QPainter实例,注意self!
        painter.setRenderHint(QPainter.Antialiasing)#抗锯齿
        side = min(self.width(), self.height())
        #设置绘图“视口”(使用物理坐标系),参数(整形)分别为左上角的x和y,以及视口的宽和高
        painter.setViewport((self.width() - side) / 2, (self.height() - side) / 2, side, side)
        #设置绘图“窗口”(使用逻辑坐标系),参数(整形)分别为左上角的x和y,以及“窗口”的宽和高
        #之后逻辑坐标系 (Qpainter自动会将逻辑坐标按比例映射到物理坐标)
        painter.setWindow(0, 0, LogicalSize, LogicalSize)
        
        painter.setPen(Qt.NoPen) #无线条
        gradient = QLinearGradient(QPointF(0, 0),QPointF(0, 100))#线性梯度
        gradient.setColorAt(0, Qt.white)
        a = self.leftSpinBox.value()
        gradient.setColorAt(1, (Qt.red if a != 0 else Qt.white)) #流速非零时,左边流体为红色
        painter.setBrush(QBrush(gradient)) #画刷
        #绘制左边多边形(4边形)
        painter.drawPolygon(QPolygonF([QPointF(ax, ay), QPointF(bx, by), QPointF(cx, cy), QPointF(ix, iy)]))
        gradient = QLinearGradient(QPointF(0, 0), QPointF(0, 100))
        gradient.setColorAt(0, Qt.white)
        b = self.rightSpinBox.value()
        gradient.setColorAt(1, (Qt.blue if b != 0 else Qt.white)) #流速非零时,右边流体为蓝色
        painter.setBrush(QBrush(gradient))
        #绘制右边多边形(4边形)
        painter.drawPolygon(QPolygonF([QPointF(cx, cy), QPointF(dx, dy),QPointF(ex, ey),QPointF(fx, fy)]))
        #计算混合流体的颜色
        if (a + b) == 0:
            color = QColor(Qt.white)
        else:
            ashare = (a / (a + b)) * 255.0
            bshare = 255.0 - ashare
            color = QColor(ashare, 0, bshare)
        gradient = QLinearGradient(QPointF(0, 0), QPointF(0, 100))
        gradient.setColorAt(0, Qt.white)
        gradient.setColorAt(1, color)
        painter.setBrush(QBrush(gradient))
        
        #绘制下部多边形(5边形)
        painter.drawPolygon(QPolygonF([QPointF(cx, cy),QPointF(fx, fy),QPointF(gx, gy), QPointF(hx, hy),QPointF(ix, iy)]))
        #绘制Y形管边界(黑色粗实线)
        painter.setPen(Qt.black)
        painter.drawPolyline(QPolygonF([QPointF(ax, ay), QPointF(ix, iy),QPointF(hx, hy)]))
        painter.drawPolyline(QPolygonF([QPointF(gx, gy), QPointF(fx, fy), QPointF(ex, ey)]))
        painter.drawPolyline(QPolygonF([QPointF(bx, by), QPointF(cx, cy), QPointF(dx, dy)]))

if __name__ == "__main__":
    import sys
    def valueChanged(a, b):
        print(a, b)
    app = QApplication(sys.argv)
    form = YPipeWidget()
    form.signal_valuechanged.connect(valueChanged)
    form.setWindowTitle("YPipe")
    form.move(0, 0)
    form.show()
    form.resize(400, 400)
    app.exec_()

本篇的例子来自《Python Qt Gui 快速编程 ----PyQt 编程指南》,原文是PyQt4的,现已改为PyQt5 版本。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-05-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python可视化编程机器学习OpenCV 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档