2016-11-18 15 views
1

私はpyqt4で写真ビューアを適応しようとしています(私はこのサイトの別の質問からコードを得ました)。デフォルトでは、マウスホイールがズームし、マウスの左ボタンを使用してイメージをパン/ドラッグします(正確に何を呼び出すべきか分かりません)。画像を左クリックしたときにピクセル情報を取得する機能を追加したいので、「パン」モードから「ピクセル情報」モードに切り替えるためのボタンがあります。これを行う私の試みは以下の通りですが、意図したとおりに動作していません。pyqt4 QGraphicsView.mousePressEventを無効にするにはどうすればよいですか?

最初のGUIボタンでイメージをロードしてイメージを拡大すると、イメージをパン/ドラッグしないと、2番目のGUIボタンをクリックするとパン/ドラッグが無効になり、イメージは、クリックしたピクセルのピクセル情報を提供します。これは私が期待したものです。

ただし、最初に画像を拡大/縮小してドラッグすると、2番目のGUIボタンをクリックするとパン/ドラッグが無効にならず、ピクセル情報が印刷されなくなります。

ズーム後の画像をドラッグすると、パン/ドラッグ方式でロックされていて、それを変更できないようなことが何らかの理由でわかりません。誰も私になぜ教えてもらえますか?

from PyQt4 import QtCore, QtGui 

class PhotoViewer(QtGui.QGraphicsView): 
    def __init__(self, parent): 
     super(PhotoViewer, self).__init__(parent) 
     self._zoom = 0 
     self._scene = QtGui.QGraphicsScene(self) 
     self._photo = QtGui.QGraphicsPixmapItem() 
     self._scene.addItem(self._photo) 
     self.setScene(self._scene) 
     self.setTransformationAnchor(QtGui.QGraphicsView.AnchorUnderMouse) 
     self.setResizeAnchor(QtGui.QGraphicsView.AnchorUnderMouse) 
     self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) 
     self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) 
     self.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(30, 30, 30))) 
     self.setFrameShape(QtGui.QFrame.NoFrame) 

    def fitInView(self): 
     rect = QtCore.QRectF(self._photo.pixmap().rect()) 
     if not rect.isNull(): 
      unity = self.transform().mapRect(QtCore.QRectF(0, 0, 1, 1)) 
      self.scale(1/unity.width(), 1/unity.height()) 
      viewrect = self.viewport().rect() 
      scenerect = self.transform().mapRect(rect) 
      factor = min(viewrect.width()/scenerect.width(), 
         viewrect.height()/scenerect.height()) 
      self.scale(factor, factor) 
      self.centerOn(rect.center()) 
      self._zoom = 0 

    def setPhoto(self, pixmap=None): 
     self._zoom = 0 
     if pixmap and not pixmap.isNull(): 
      self.setDragMode(QtGui.QGraphicsView.ScrollHandDrag) 
      self._photo.setPixmap(pixmap) 
      self.fitInView() 
     else: 
      self.setDragMode(QtGui.QGraphicsView.NoDrag) 
      self._photo.setPixmap(QtGui.QPixmap()) 

    def wheelEvent(self, event): 
     if not self._photo.pixmap().isNull(): 
      if event.delta() > 0: 
       factor = 1.25 
       self._zoom += 1 
      else: 
       factor = 0.8 
       self._zoom -= 1 
      if self._zoom > 0: 
       self.scale(factor, factor) 
      elif self._zoom == 0: 
       self.fitInView() 
      else: 
       self._zoom = 0 

    def printPixInfo(self,event): 
     print event.pos() 

class Window(QtGui.QWidget): 
    def __init__(self): 
     super(Window, self).__init__() 
     self.viewer = PhotoViewer(self) 
     # 'Load image' button 
     self.btnLoad = QtGui.QToolButton(self) 
     self.btnLoad.setText('Load image') 
     self.btnLoad.clicked.connect(self.loadImage) 
     # Button to change from drag/pan to getting pixel info 
     self.btnPixInfo = QtGui.QToolButton(self) 
     self.btnPixInfo.setText('Enter pixel info mode') 
     self.btnPixInfo.clicked.connect(self.pixInfo) 
     # Arrange layout 
     VBlayout = QtGui.QVBoxLayout(self) 
     VBlayout.addWidget(self.viewer) 
     HBlayout = QtGui.QHBoxLayout() 
     HBlayout.setAlignment(QtCore.Qt.AlignLeft) 
     HBlayout.addWidget(self.btnLoad) 
     HBlayout.addWidget(self.btnPixInfo) 
     VBlayout.addLayout(HBlayout) 

    def loadImage(self): 
     self.viewer.setPhoto(QtGui.QPixmap('pic.jpg')) 

    def pixInfo(self): 
     print 'Now in pixel info mode' 
     self.viewer._photo.mousePressEvent = self.viewer.printPixInfo 

if __name__ == '__main__': 
    import sys 
    app = QtGui.QApplication(sys.argv) 
    window = Window() 
    window.setGeometry(500, 300, 800, 600) 
    window.show() 
    sys.exit(app.exec_()) 

私は成功した構文は、デフォルトのパン/ドラッグ動作に戻って、左クリックマウスを返すために何であるかマウスクリックの方法を、変更した後、私はまた、知っていただきたいと思います。

私はPythonの初心者ですので、私をあまりにも批判しないようにしてください。ありがとう。

答えて

3

mousePressEventを完全にオーバーライドすると、デフォルトの動作(マウスでのパンなど)がすべて失われてしまうという問題があります。写真がクリックされたときに通知するカスタム信号を使用する方が良いでしょう。そして、グラフィックス・ビューがすでにドラッグモードを変更するためのAPIを持っている、あなたはモードを切り替えるためのスロットを追加することができますので、:

class PhotoViewer(QtGui.QGraphicsView): 
    photoClicked = QtCore.pyqtSignal(QtCore.QPoint)  
    ... 

    def toggleDragMode(self): 
     if self.dragMode() == QtGui.QGraphicsView.ScrollHandDrag: 
      self.setDragMode(QtGui.QGraphicsView.NoDrag) 
     elif not self._photo.pixmap().isNull(): 
      self.setDragMode(QtGui.QGraphicsView.ScrollHandDrag) 

    def mousePressEvent(self, event): 
     if self._photo.isUnderMouse(): 
      self.photoClicked.emit(QtCore.QPoint(event.pos())) 
     # keep the default behaviour 
     super(PhotoViewer, self).mousePressEvent(event) 

これら二つの新しいAPIは、あなたが必要な機能を与えるために使用することができます。

class Window(QtGui.QWidget): 
    def __init__(self): 
     ... 
     # add a line-edit to display the position info 
     self.editPixInfo = QtGui.QLineEdit(self) 
     self.editPixInfo.setReadOnly(True) 
     self.viewer.photoClicked.connect(self.photoClicked) 
     ... 
     HBlayout.addWidget(self.editPixInfo) 

    def pixInfo(self): 
     # switch modes 
     self.viewer.toggleDragMode() 

    def photoClicked(self, pos): 
     # handle photo-click signals 
     if self.viewer.dragMode() == QtGui.QGraphicsView.NoDrag: 
      self.editPixInfo.setText('%d, %d' % (pos.x(), pos.y())) 
+1

これはまさに私が欲しかったことです。非常にありがとう、あなたはスターです。私が言及したように、私はPythonの初心者であり、私はまだ物事を行うOOPの全体の方法に慣れています、そして、私はどのクラスメソッドが利用可能であったか知っていたでしょう。 。どのようにして仕事をしたのか(ほとんど)、レッスンに感謝します。しかし、一点をクリアしてください。変更されたmousePressEventメソッドのsuper関数の正確な目的は何ですか? –

+0

@AndrewBirch。これは、デフォルトの動作が維持されるように、基本クラス・メソッドを呼び出します。 – ekhumoro

+1

スーパー関数を呼び出すことによって、mousePressEventコードは、基本クラスメソッドのコードの先頭に追加されるのではなく、基本的に追加されますか?そうですか? –

関連する問題