本篇介绍用如何QPainter()画出一个可以显示混合流体流速的Y形管控件。
Y形管由abci、edcf 以及cihgf三部分组成,内部的颜色由流体的流速决定。各个部分均使用逻辑坐标系绘制。
代码如下:
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 版本。
本文分享自 Python可视化编程机器学习OpenCV 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有