pyside6使用问题记录(一)

近期在做的任务要把交通路网结构用PySide6可视化,并添加一些选择车道,拖拽车辆之类的交互操作。以下是在应用过程中出现的一些问题和解决方案。

问题1:qgraphicsview画polyline

由于希望界面上的部件都可以交互(点击,拖拽),因此我尝试在QGrahicsView类里画,但发现QGraphicsScene没有可直接调用的画polyline的函数,可行的方法是先画出QPainterPath,再用QGraphicsPath。如下面的程序,drawPolyline函数可输入2D points, color, width,画出这些点的折线段。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class MainWidget(QtWidgets.QGraphicsView)
{
def __init__(self):
super().__init__()
self.initUI()
self.scaleFactor = 1
self.resize(800, 800)

self.scene_map = QtWidgets.QGraphicsScene()
self.scene_map.setSceneRect(0, 0, 700, 700)
self.scene_map.setBackgroundBrush(Qt.white)
self.setScene(self.scene_map)

def drawPolyline(self, points:list[tuple], color:QtGui.QColor, width:int = 1.0):
points = [QPointF(x,y) for x,y in points]
path = QtGui.QPainterPath()
polygon = QtGui.QPolygonF(points)
path.addPolygon(polygon)

pen = QtGui.QPen(color)
pen.setWidth(width)
new_item = QtWidgets.QGraphicsPathItem(path, None)
new_item.setPath(path)
new_item.setPen(pen)
self.scene_map.addItem(new_item)

}

问题2:画出来的polyline不够平滑,有锯齿

用上述方式画出的图如下图左图所示:斜线会有锯齿,只有完全水平或竖直或45度的线才是粗细均匀的。

为了平滑线段,可以给QGraphicsview设置渲染的参数setRenderHint为antialiasing(抗锯齿)。在__init__函数里加入下面一行:

1
self.setRenderHint(QtGui.QPainter.Antialiasing, True)

得到的结果如上面右图所示,可以看到没有锯齿了。

问题3:拖拽时view无法超过scene的大小

设置滚轮放大缩小功能需要重写wheelEvent函数,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def wheelEvent(self, event: QtGui.QWheelEvent) -> None:
if len(self.scene().items()) == 0:
return

curPoint = event.position()
scenePos = self.mapToScene(QPoint(curPoint.x(), curPoint.y()))

viewWidth = self.viewport().width()
viewHeight = self.viewport().height()

hScale = curPoint.x() / viewWidth
vScale = curPoint.y() / viewHeight

wheelDeltaValue = event.angleDelta().y()
self.scaleFactor = self.transform().m11()
if (self.scaleFactor < 0.05 and wheelDeltaValue<0) or (self.scaleFactor>50 and wheelDeltaValue>0):
return

if wheelDeltaValue > 0:
self.scale(1.1, 1.1)
else:
self.scale(1.0/1.1, 1.0/1.1)

viewPoint = self.transform().map(scenePos)
self.horizontalScrollBar().setValue(int(viewPoint.x() - viewWidth * hScale ))
self.verticalScrollBar().setValue(int(viewPoint.y() - viewHeight * vScale ))

self.update()

设置鼠标拖拽功能只需要给QGraphicsView设置setDragMode,在window类初始化时加入

1
self.setDragMode(QtWidgets.QGraphicsView.ScrollHandDrag)

但在显示底图时由于图比较大,我并不想一开始显示全部,而只是显示一部分,如下图(1)。此时我的拖拽功能只在相比原始scene放大时才有用(在图(2)时可以拖拽)。当地图缩小后尽管还未显示地图全貌,但无法拖动(图(3)无法拖动)。

参考这个回答:https://stackoverflow.com/questions/55007339/allow-qgraphicsview-to-move-outside-scene

一个简单粗暴的解决方法是给scene设置足够大的初始大小。在我的例子中我将大小改为:

1
self.scene_map.setSceneRect(0, 0, 2000, 2000)

这样就可以在上图(3)仍然可以拖动。不过修改scene_map的大小后要注意原本点的位置的按照scene_map的大小改变。由于QGraphicsScene默认是中心和QGraphicsView对齐的,如scene_map大小设为(2000,2000),那么此时scene中心点的坐标(1000,1000)会显示在view的中心。


pyside6使用问题记录(一)
https://sisyphus-99.github.io/2023/09/19/pyside6使用问题记录1/
Author
sisyphus
Posted on
September 19, 2023
Licensed under