PySide6复杂C/S系统开发
目录
0.了解
之前写了一篇“PySimpleGUI复杂C/S系统开发”博客(由于pysimplegui更改了协议,因此不再推荐,并且pypi上也撤销了4.60.5,国内源还有。用了pyside6后yyds),里面介绍了几款python的GUI,但是漏掉了wxpython,它也很不错。wxpython是wxwidgets(c++)的python接口,支持跨平台,并且由于底层是c++其性能也很强。另外wxpython或wxwidgets的UI设计器也是有的,叫wxFormBuilder。
不过多介绍PyQt系列,它与PySide系列功能99%的都相同,但是协议不一样,PySide6在不重新编译的前提下,可直接商用,而pyqt不行,并且pyside6是QT官方python API库。
如果想实现酷炫的界面,推荐web(b/s)系统;如果必须要用c/s系统且用pyside6时,那么也可以实现酷炫的界面,了解qss(不推荐),qt官方好像在推qml(个人不推荐),qtwidgets官方更新比较少了,因为其界面一般,但是功能稳定强悍。
个人需求:普通界面,实现复杂功能、要求性能强且用python时,推荐PySide6!!!
1.前提
PySide6官方文档链接,不太喜欢很多人推荐的zeal的qt文档,明明有qt py api的文档。
可以去B站看看pyside6的教程视频,一开始都推荐手写代码,看了1天后,明白个大概,随用随搜随学吧。
qt-designer,在安装的PySide6包路径下有designer.exe,网上一堆vscode配置qtdesigner的教程,个人还是喜欢直接双击用。另外将ui文件转成py文件或者cpp文件,在py下采用命令:
pyside6-uic xxx.ui -o xxx.py,即可,然后推荐继承类的写法再进行功能开发。
2.qtdesigner使用
①了解信号与槽的机制
②了解垂直、水平、栅格布局,了解容器(可以跟随窗口大小变化),了解弹簧,其它的组件随用随搜,官网文档都有,看一下。
另外gpt等大模型生成一些代码,稍微复杂点都得需要改。
3.实际代码(继承QGraphicsview修改)
基于QGraphicsview,重写几个事件函数(鼠标按下、释放、平移、滚轮、重画),以实现显示图像,矩形框的绘制,选择平移删除,以及十字标线的显示!!!ImageView参考的一篇博客。
from PySide6.QtWidgets import QGraphicsView, QGraphicsScene, QGraphicsItem
from PySide6.QtCore import Qt, QRectF, QPointF, QSize, QSizeF
from PySide6.QtGui import QPen, QColor, QBrush, QPainter
class ImageView(QGraphicsView):
# 增加1个parent 以实现源码中的init parent参数,将graphicsview放到groupbox等容器中
def __init__(self, parent):
super().__init__(parent=parent)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn) # 隐藏横向滚动条 开启
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) # 隐藏纵向滚动条
# self.setDragMode(QtWidgets.QGraphicsView.ScrollHandDrag) # 启用拖动
self.setDragMode(QGraphicsView.NoDrag) # 禁用拖动
self.setMouseTracking(True)
self.data = []
self.flag = False
self.start_pos = None
self.current_rect = None
self.cross_marking_line = None
def wheelEvent(self, event):
if not self.scene():
return
if len(self.scene().items()) == 0:
return
curPoint = event.position() # QPointF
scenePos = self.mapToScene(curPoint.toPoint())
viewWidth = self.viewport().width()
viewHeight = self.viewport().height()
hScale = curPoint.x() / viewWidth
vScale = curPoint.y() / viewHeight
wheelDeltaValue = event.angleDelta().y() # 120
scaleFactor = self.transform().m11() # 等比例缩放 所以只需要m11 x轴缩放比例
if (scaleFactor < 0.05 and wheelDeltaValue < 0) or (scaleFactor > 50 and wheelDeltaValue > 0):
return
if wheelDeltaValue > 0:
self.scale(1.2, 1.2)
else:
self.scale(1.0 / 1.2, 1.0 / 1.2)
viewPoint = self.transform().map(scenePos)
self.horizontalScrollBar().setValue(int(viewPoint.x() - viewWidth * hScale))
self.verticalScrollBar().setValue(int(viewPoint.y() - viewHeight * vScale))
self.update()
def mousePressEvent(self, event):
if self.flag and event.button() == Qt.RightButton and self.scene():
self.start_pos = event.position()
if event.button() == Qt.LeftButton:
self.setDragMode(QGraphicsView.ScrollHandDrag)
super().mousePressEvent(event)
def mouseReleaseEvent(self, event):
if self.flag and event.button() == Qt.RightButton:
self.flag = False
if self.current_rect:
self.current_rect = None
self.start_pos = None
if event.button() == Qt.LeftButton:
self.setDragMode(QGraphicsView.NoDrag)
super().mouseReleaseEvent(event)
def mouseMoveEvent(self, event):
# 标记十字标线
self.cross_marking_line = event.position()#.toPoint()
self.viewport().update() # 不可直接用self.update 不起作用
if self.flag and event.buttons() == Qt.RightButton and self.scene():
scene_start_pos = self.mapToScene(self.start_pos.toPoint())
scene_end_pos = self.mapToScene(event.position().toPoint())
if scene_start_pos.x() < scene_end_pos.x() and scene_start_pos.y() < scene_end_pos.y():
rect = QRectF(scene_start_pos, scene_end_pos) # view scene之间需要坐标系转换
if self.current_rect:
self.scene().removeItem(self.current_rect)
self.current_rect = self.scene().addRect(rect, pen=QPen(Qt.red, 1))
self.current_rect.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsMovable, True) # 设置可选中 平移
self.current_rect.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsSelectable, True)
# self.current_rect.setFlag(QGraphicsItem.GraphicsItemFlag.ItemSendsGeometryChanges, True)
# self.current_rect.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsFocusable, True)
self.update()
else:
if self.current_rect:
self.scene().removeItem(self.current_rect)
self.current_rect = None
super().mouseMoveEvent(event)
def paintEvent(self, event):
super().paintEvent(event)
if self.flag and self.scene():
painter = QPainter(self.viewport())
pen = QPen(Qt.red, 2)
painter.setPen(pen)
painter.drawLine(0, self.cross_marking_line.y(), self.viewport().width(), self.cross_marking_line.y())
painter.drawLine(self.cross_marking_line.x(), 0, self.cross_marking_line.x(), self.viewport().height())
主函数部分代码,Ui_MainWindow是ui转成py类