2017-03-07 40 views
3

私はPyQt5 GUIで利用しようとしているdraggable matplotlibオブジェクトのライブラリを持っています。オブジェクトのevent listenersは、スタンドアロンのmatplotlib Figureウィンドウで正しく機能しますが、FigureがQTウィジェットに埋め込まれている場合は機能しません。両方のプロットが正しくレンダリングされ、QTウィジェットでパッチをドラッグしようとするとエラーメッセージは表示されません。matplotlib PyQTウィジェットでイベントリスナーが機能しない

オブジェクト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_()) 

Iは、Python 3.6.0を使用している、matplotlibの(2.0 .0)、PyQt5(5.8)

私は何が欠けていますか?

+0

あなたは 'デフdragEnterEvent(自己、イベント)を実装しようとしたことがあり:すべての_embedding_ 'QWidget'に対してevent.acceptProposedAction()'?それ以外の場合、イベントは埋め込みウィジェットに伝播できません。 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++のドラッグアンドドロップのドキュメント](http://doc.qt.io/qt-5/dnd.html)を読むこともできます(pyqtの参照は、もっと特定の話題になると少し疎です)。 –

答えて

4

ドラッグイベントではなく、minidrag.DragRectangleインスタンスがガベージコレクションされていることがわかります(キャンバスは元の位置に四角形を表示したままです)。あなたはインスタンス変数として四角形を設定することができます修正として

:(。Python2.7とPyQt4でテスト済み)

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

+0

ああ、それは迷惑だ:) – excaza

関連する問題