1)问题动机和使用场景

最近做一个项目,需要的功能是使用鼠标添加节点(鼠标点击的位置即节点坐标),同时点坐标添加之后还能可视化的动态显示出来。

2)问题解决过程

在平常python作图中,我常用的工具是matplotlib。但它好像不能实现我需要的功能,感觉matplotlib完全是依靠数据驱动(即提供数据即能画图),可是没法实现使用者与图形的双向交互(即使用者通过鼠标点击就可以生成新的点)。一番搜索之后,发现pyqt貌似可以满足我的需求,并且还能找到一些相关的代码。说干就干,我借鉴网上的代码,再结合自己的需求,最终实现了我需要的功能。

3)需求框架和思路

我的需求主要是分为以下几个部分:

1)给定节点坐标,即可以以散点图的形式显示出来,这个pyqtgraph库实现,关键步骤代码如下。
# 创建 PlotWidget 对象
self.pw = pg.PlotWidget()
# 获取绘制散点图对象
self.scatter = self.pw.plot(pen=None, symbol='o')
# 给点x,y坐标,绘制散点图
self.scatter.setData(self.x, self.y)
2)节点数目或者坐标变动后,位置可以实时更新。
# 启动定时器,每隔100ms通知刷新一次数据
self.timer = QtCore.QTimer()
self.timer.timeout.connect(self.updateData)
self.timer.start(100)
3)鼠标左击作图界面,添加新的点。这个部分是最困扰我的,之前都没有用过pyqt,所以也不不知道怎么样捕捉鼠标单击信号,更不清楚提取对应的位置坐标。在实际做的时候,我也把这部分分为了两步:a)捕捉鼠标单击信号,主要代码如下:
# 捕捉鼠标单击事件
self.scatter.scene().sigMouseClicked.connect(self.mouse_clicked)
# 捕捉到单击事件后,需要做的动作,在mouse_clicked函数里完成
def mouse_clicked(self,event):
    self.x.append(self.new_point_x)
    self.y.append(self.new_point_y)
b)获取鼠标在单击时对应在图形位置的坐标,在这里我遇到了一个坑。 照理sigMouseClicked返回值是一个event,里面就包含了单击时刻的坐标,但是这个坐标不准确,跟实际的位置有些出入。经过测试,反而是通过鼠标移动事件提取的坐标是准确无误的。
# 捕捉鼠标移动事件
self.scatter.scene().sigMouseMoved.connect(self.mouseover)
# 捕捉到单击事件后,需要做的动作,在mouseover函数里完成,主要是提取点的坐标
def mouseover(self,pos):
    # 参数pos 是像素坐标,需要 转化为  刻度坐标
    act_pos = self.scatter.mapFromScene(pos)
    if type(act_pos) != QtCore.QPointF:
        return
    # print("over_1:",act_pos.x(), act_pos.y())
    self.new_point_x = act_pos.x()
    self.new_point_y = act_pos.y()

4)总结

以上就是解决我需求的全部思路。全部完整的代码如下,复制后直接可以用:

# 捕捉鼠标移动事件
self.scatter.scene().sigMouseMoved.connect(self.mouseover)
# 捕捉到单击事件后,需要做的动作,在mouseover函数里完成,主要是提取点的坐标
from PySide2 import QtGui, QtWidgets, QtCore
# from pyqtgraph.Qt import  QtCore
import pyqtgraph as pg
import sys
from random import randint
import numpy as np

FieldRadius = 100

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('pyqtgraph作图')
        # 创建 PlotWidget 对象
        self.pw = pg.PlotWidget()
        # 设置图表标题
        self.pw.setTitle("节点分布图",
                         color='008080',
                         size='12pt')
        # 设置上下左右的label
        self.pw.setLabel("left","纵坐标")
        self.pw.setLabel("bottom","横坐标")

        self.pw.setXRange(min=0,  # 最小值
                          max=FieldRadius)  # 最大值
        # 设置Y轴 刻度 范围
        self.pw.setYRange(min=0,  # 最小值
                          max=FieldRadius)  # 最大值
        # 显示表格线
        self.pw.showGrid(x=True, y=True)
        # 背景色改为白色
        self.pw.setBackground('w')
        # 居中显示 PlotWidget
        self.setCentralWidget(self.pw)

        # 实时显示应该获取 PlotDataItem对象, 调用其setData方法,
        # 这样只重新plot该曲线,性能更高
        self.scatter = self.pw.plot(pen=None, symbol='o')

        self.i = 0
        self.x = [] # x轴的值
        self.new_point_x = 0
        self.y = [] # y轴的值
        self.new_point_y = 0

        self.setMouseTracking(False)
        self.scatter.scene().sigMouseMoved.connect(self.mouseover)
        self.scatter.scene().sigMouseClicked.connect(self.mouse_clicked)

        # 启动定时器,每隔1秒通知刷新一次数据
        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self.updateData)
        self.timer.start(100)

    def updateData(self):
        self.scatter.setData(self.x, self.y)

    # 鼠标移动事件,用于获取精确坐标(好像鼠标单击的坐标不准确)
    def mouseover(self,pos):
        # 参数pos 是像素坐标,需要 转化为  刻度坐标
        act_pos = self.scatter.mapFromScene(pos)
        if type(act_pos) != QtCore.QPointF:
            return
        # print("over_1:",act_pos.x(), act_pos.y())
        self.new_point_x = act_pos.x()
        self.new_point_y = act_pos.y()

    # 鼠标单击事件,用于鼠标单击后事件的处理,包括:
    # 1)添加新坐标
    def mouse_clicked(self,event):

        self.x.append(self.new_point_x)
        self.y.append(self.new_point_y)
        # print("my position is:",self.xx,self.yy)

if __name__ == '__main__':
    app = QtWidgets.QApplication()
    main = MainWindow()
    main.show()
    app.exec_()

我的实验结果:

python selenium获取鼠标坐标 python获取鼠标位置_后端