2017-03-07 5 views
3

나는 PyQt5 GUI에서 활용하려고하는 draggable matplotlib 객체 라이브러리를 가지고 있습니다. 객체 'event listeners은 독립형 matplotlib Figure 창에서 올바르게 작동하지만 그림이 QT 위젯에 포함되어있을 때는 작동하지 않습니다. QT 위젯에서 패치를 드래그하려고하면 두 플롯이 올바르게 렌더링되고 오류 메시지가 표시되지 않습니다.matplotlib PyQT 위젯에서 Funcitoning하지 않는 이벤트 리스너

객체 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_()) 

내가 파이썬 3.6.0를 사용하고,하기 matplotlib (2.0 .0), PyQt5 (5.8)

무엇이 누락 되었습니까?

+0

당신이 구현하는 시도 되세요'데프 dragEnterEvent (자체 이벤트) event.acceptProposedAction()'모든 _embedding_'QWidget'에 대해? 그렇지 않으면 이벤트가 내장 된 위젯에 전파 될 수 없습니다. Btw 당신은'dropEvent'에 대해서도 똑같이해야 할 수도 있습니다. [QWidget.dragEnterEvent] (http://pyqt.sourceforge.net/Docs/PyQt4/qwidget.html#dragEnterEvent)를 참조하십시오. –

+0

나는 내가 이해할 지 모르겠다. matplotlib의 표준 이벤트 기능 (마우스 오버 좌표 디스플레이, 패닝/확대/축소 등)은 위젯의 이벤트를 재정의 할 필요없이 올바르게 작동합니다. 왜 다른가? – excaza

+0

AFAIK 끌기 이벤트는 기본적으로 무시되므로 아마도 [setAcceptDrops (True)'] (http://pyqt.sourceforge.net/Docs/PyQt4/qwidget.html#setAcceptDrops)를 설정하는 것만으로 충분할 것입니다 (최소한 해당 속성은 기본적으로'False'입니다; C++ 문서] (http://doc.qt.io/qt-5/qwidget.html#acceptDrops-prop)). 드래그 앤 드롭이 Qt 내에서 어떻게 작동하는지에 대한 더 자세한 정보는 [C++ drag & drop docs] (http://doc.qt.io/qt-5/dnd.html)에서도 읽을 수 있습니다 (pyqt 참조는 때때로 더 구체적인 주제에 관해서는 약간 희소 함). –

답변

4

끌기 이벤트가 아니라 캔버스가 직사각형을 원래 위치에 유지하면서 가비지 수집중인 minidrag.DragRectangle 인스턴스 만 문제가된다는 것을 알 수 있습니다. 당신이 인스턴스 변수로 사각형 설정할 수 있습니다 수정으로

:

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

(. Python2.7 및 PyQt4와 테스트가)

+0

아, 그건 짜증나. :) – excaza