问题描述
我有一个可拖动的 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 小部件中不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!