matplotlib事件监听器在PyQT小部件中没有功能

时间:2017-03-07 13:53:03

标签: python python-3.x matplotlib pyqt pyqt5

我有一个可拖动的matplotlib对象库,我正在尝试使用PyQt5 GUI。对象'event listeners在独立的matplotlib图窗口中正常运行,但在图形嵌入QT窗口小部件时不起作用。两个图都正确呈现,当我尝试在QT小部件中拖动修补程序时没有错误消息。

对象MCVE:

import matplotlib.patches as patches

class _DragObj:
    def __init__(self, ax):
        self.parentcanvas = ax.figure.canvas
        self.parentax = ax

        self.clickpress = self.parentcanvas.mpl_connect('button_press_event', self.on_click)
        self.clicked = False

    def on_click(self, event):
        if event.inaxes != self.parentax: return

        self.mousemotion = self.parentcanvas.mpl_connect('motion_notify_event', self.on_motion)
        self.clickrelease = self.parentcanvas.mpl_connect('button_release_event', self.on_release)

        self.clickx = event.xdata  
        self.clicky = event.ydata

        self.clicked = True

    def on_release(self, event):
        self.clicked = False
        self.disconnect()

    def disconnect(self):
        self.parentcanvas.mpl_disconnect(self.mousemotion)
        self.parentcanvas.mpl_disconnect(self.clickrelease)
        self.parentcanvas.draw()

    def stopdrag(self):
        self.myobj.set_url('')
        self.parentcanvas.mpl_disconnect(self.clickpress)

class _DragPatch(_DragObj):
    def __init__(self, ax, xy):
        super().__init__(ax)

        self.oldxy = xy

    def on_motion(self, event):
        if not self.clicked: return
        if event.inaxes != self.parentax: return

        oldx, oldy = self.oldxy
        dx = event.xdata - self.clickx
        dy = event.ydata - self.clicky
        newxy = [oldx + dx, oldy + dy]
        self.myobj.xy = newxy

        self.parentcanvas.draw()

    def on_release(self, event):
        self.clicked = False
        self.oldxy = self.myobj.xy

        self.disconnect()

class DragRectangle(_DragPatch):
    def __init__(self, ax, xy, width, height, angle=0.0, **kwargs):
        self.myobj = patches.Rectangle(xy, width, height, angle, **kwargs)
        ax.add_artist(self.myobj)

        super().__init__(ax, xy)

功能正常的matplotlib示例:

import minidrag
import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(111)
rect = minidrag.DragRectangle(ax, (0, 0), 2, 1)

ax.set_xlim(-5, 5)
ax.set_ylim(-5, 5)

plt.show()

非功能性PyQT示例:

import sys
from PyQt5 import QtWidgets as QtW
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
import minidrag

class windowGUI(QtW.QDialog):
    def __init__(self):
        super().__init__()

        # Set up figure
        width_px = 800
        height_px = 600

        rect = QtW.QDesktopWidget().availableGeometry()
        screenrez = (rect.width(), rect.height())
        left_px = (screenrez[0] - width_px)/2
        top_px = (screenrez[1] - height_px)/2
        self.setGeometry(left_px, top_px, width_px, height_px)
        self.canvas = PlotCanvas()

        layout = QtW.QVBoxLayout()
        layout.addWidget(NavigationToolbar(self.canvas, self))
        layout.addWidget(self.canvas)
        self.setLayout(layout)

class PlotCanvas(FigureCanvas):
    def __init__(self):
        fig = Figure(frameon=False)
        super().__init__(fig)
        super().setSizePolicy(QtW.QSizePolicy.Expanding, QtW.QSizePolicy.Expanding)
        super().updateGeometry()

        ax = fig.add_subplot(111)
        rect = minidrag.DragRectangle(ax, (0, 0), 2, 1)

        ax.set_xlim(-5, 5)
        ax.set_ylim(-5, 5)

app = QtW.QApplication(sys.argv)
window = windowGUI()
window.show()
sys.exit(app.exec_())

我正在使用Python 3.6.0,matplotlib(2.0.0)和PyQt5(5.8)

我错过了什么?

1 个答案:

答案 0 :(得分:4)

原来问题不是拖拽事件,而是你的minidrag.DragRectangle实例被垃圾收集(而画布仍然在原始位置显示矩形)。

作为修复,您可以将矩形设置为实例变量:

self.rect = minidrag.DragRectangle(ax, (0, 0), 2, 1)

(使用Python2.7和PyQt4测试。)