matplotlib 事件侦听器在 PyQT 小部件中不起作用 [英] matplotlib Event Listeners Not Funcitoning In PyQT Widget

查看:51
本文介绍了matplotlib 事件侦听器在 PyQT 小部件中不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个可拖动的 matplotlib 对象库,我正尝试将其与 PyQt5 GUI 一起使用.对象的 事件侦听器 在独立的 matplotlib 图形窗口中正常运行,但在图形显示时不起作用嵌入在 QT 小部件中.当我尝试在 QT 小部件中拖动补丁时,两个图都正确呈现并且没有错误消息.

I have a library of draggable matplotlib objects that I'm trying to utilize with a PyQt5 GUI. The objects' event listeners function correctly in a standalone matplotlib figure window but do not function when the figure is embedded in a QT widget. Both plots render correctly and there are no error messages when I try to drag the patch in the QT widget.

对象 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 示例:

The functioning matplotlib example:

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 示例:

The nonfunctional PyQT example:

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)

I'm using Python 3.6.0, matplotlib (2.0.0), and PyQt5 (5.8)

我错过了什么?

推荐答案

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

Turns out that the problem are not drag events but instead your minidrag.DragRectangle instance just being garbage collected (while the canvas remains showing the rectangle at its original position).

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

As a fix you can set the rectangle as an instance variable:

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

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

(Tested with Python2.7 and PyQt4.)

这篇关于matplotlib 事件侦听器在 PyQT 小部件中不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆