Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/286.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python matplotlib事件侦听器在PyQT小部件中不起作用_Python_Python 3.x_Matplotlib_Pyqt_Pyqt5 - Fatal编程技术网

Python matplotlib事件侦听器在PyQT小部件中不起作用

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

我有一个可拖动的matplotlib对象库,我正试图通过PyQt5 GUI利用它。对象在独立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)


我遗漏了什么?

结果表明,问题不在于拖动事件,而在于正在垃圾收集的
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不应该在这里进行干扰。哦,这很烦人:)