本篇介绍用如何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): returnself.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 != 0else 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 != 0else 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编程 pyqt matplotlib,建议关注公众号查看原文。如若侵权请联系qter@qter.org。 ---------------------------------------------------------------------------------------------------------------------- |