Python matplotlib事件侦听器在PyQT小部件中不起作用
我有一个可拖动的matplotlib对象库,我正试图通过PyQt5 GUI利用它。对象在独立matplotlib图形窗口中正常工作,但当图形嵌入到QT小部件中时不工作。当我尝试在QT小部件中拖动补丁时,两个图都正确呈现,并且没有错误消息 对象MCVE:Python matplotlib事件侦听器在PyQT小部件中不起作用,python,python-3.x,matplotlib,pyqt,pyqt5,Python,Python 3.x,Matplotlib,Pyqt,Pyqt5,我有一个可拖动的matplotlib对象库,我正试图通过PyQt5 GUI利用它。对象在独立matplotlib图形窗口中正常工作,但当图形嵌入到QT小部件中时不工作。当我尝试在QT小部件中拖动补丁时,两个图都正确呈现,并且没有错误消息 对象MCVE: import matplotlib.patches as patches class _DragObj: def __init__(self, ax): self.parentcanvas = ax.figure.can
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)
我遗漏了什么?结果表明,问题不在于拖动事件,而在于正在垃圾收集的
minidrag.DragRectangle
实例(而画布仍在其原始位置显示矩形)
作为修复,您可以将矩形设置为实例变量:
self.rect = minidrag.DragRectangle(ax, (0, 0), 2, 1)
(使用Python2.7和PyQt4进行测试。)您是否尝试过为所有嵌入
QWidget
s实现def dragEnterEvent(self,event):event.acceptProposeAction()
?否则,事件无法传播到嵌入式小部件。顺便说一句,您可能需要对dropEvent
执行相同的操作。请参阅。因为默认情况下会忽略AFAIK拖动事件。可能设置就足够了(至少默认情况下对应的属性为False
;请参阅)。您可能还想阅读,以了解有关如何在Qt中进行拖放的更多信息(当涉及到更具体的主题时,pyqt引用有时有点稀疏)。它不是拖放。建议的解决方案都不起作用。是的,您是对的,拖动只发生在matplotlib图中,因此qt不应该在这里进行干扰。哦,这很烦人:)