5

次の動作でQGraphicsViewを作成しようとしています。

  • コントロールキーを押しながら左マウスを押した状態で、ビューをScrollHandDragモードに設定して、ユーザーがパンできるようにする必要があります。

  • ScrollHandDragモードの場合、次の質問のように、アイテムを選択/移動できないようにする必要があります。QGraphicsViewのScrollHandDragモードで、シーン上のQGraphicsItemの移動を停止するにはどうすればよいですか。

  • コントロールキーを押したまま左マウスをクリックしてからコントロールキーを離すと、マウスを離すまでビューはScrollHandDragモードのままになるか、コントロールキーが押されているときにこのモードのままになります。マウスが離されます。

私には、これはかなり簡単なはずだと思います。リンクされた質問のロジックと、追加の要件に対応するいくつかの追加ロジックを実装しました。ただし、これにより、次の2つのショートッパーが発生するようです。

  • mousePressEventで、マウスの下のアイテムに移動可能で選択可能なフラグがないように設定し、基本クラスを呼び出してから、フラグを再適用すると、アイテムが「凍結」されます。これを解決する唯一の方法は、アイテムの外側でコントロール+クリック、リリースコントロール+リリースクリックを数回行うことのようです。また、この状態になると、アイテムを移動できなくなります(ただし、アイテムは選択できます)。

  • ビューをダブルクリックすると、mousePressEventが発生し、その後に2つのmouseReleaseEventsが続きます。これは私の論理を壊します。

それで、QGraphicsViewのScrollHandDragモードのロジックでアイテムがフリーズする問題を解決する方法を知りたいのですが、シーンでのQGraphicsItemの移動を停止する方法は?が使用され、奇妙なダブルクリックマウスイベントに対処する方法-それらをオフにする方法はありますか?

これが私のコードです(これは私のHello World Pythonでもあるので、Pythonのひどい間違いをした場合は、私に知らせてください):

#! /usr/bin/env python
# -*- coding: utf-8 -*-

import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *

class MyMainWindow(QMainWindow):
    def __init__(self):
        super(MyMainWindow, self).__init__()
        self.initUI()

    def initUI(self):
        self.setWindowTitle("Test")
        self.gv = MyGraphicsView()
        self.setCentralWidget(self.gv)
        self.setGeometry(170, 130, 450, 250)

class MyGraphicsView(QGraphicsView):
    def __init__(self):
        super(MyGraphicsView, self).__init__()
        self.setup()

    def setup(self):
        self.m_MouseIsDown = False
        self.m_ControlKeyDown = False
        self.setDragMode(QGraphicsView.RubberBandDrag)

    def mouseMoveEvent(self,  event):
       # print "mouseMoveEvent: " + str(event.pos().x()) + "," + str(event.pos().y())
        super(MyGraphicsView,  self).mouseMoveEvent(event);

    def mousePressEvent(self,  event):
        print "mousePressEvent"

        itemUnderMouse = self.itemAt(event.pos())
        if  itemUnderMouse is not None:
            bHadMovableFlagSet = itemUnderMouse.flags() & QGraphicsItem.ItemIsMovable
            bWasSelected = itemUnderMouse.isSelected()            
            bHadSelectableFlagSet = itemUnderMouse.flags() & QGraphicsItem.ItemIsSelectable
            if bHadMovableFlagSet:
                print "has ItemIsMovable"
            else:
                print "hasn't ItemIsMovable"
            if bHadSelectableFlagSet:
                print "has ItemIsSelectable"
            else:
                print "hasn't ItemIsSelectable"
            if bWasSelected:
                print "isSelected true"
            else:
                print "isSelected false"
            itemUnderMouse.setSelected(False)

        if event.button() == Qt.LeftButton:
            print "mousePressEvent: left button is now down"
            self.m_MouseIsDown = True

        if self.dragMode() == QGraphicsView.ScrollHandDrag and event.button() == Qt.LeftButton:
            print "mousePressEvent: left button down and ScrollHandDrag set"
            self.PreventItemsFromMovingOrBeingSelectedWhenPannning(event)
            return

        print "mousePressEvent: pass through"
        super(MyGraphicsView,  self).mousePressEvent(event)

    def mouseReleaseEvent(self,  event):
        print "mouseReleaseEvent"
        if event.button() == Qt.LeftButton:
            print "mouseReleaseEvent - left button is now up"
            self.m_MouseIsDown = False
            if self.dragMode() == QGraphicsView.ScrollHandDrag and self.m_ControlKeyDown == False:
                print "mouseReleaseEvent - left button up, in ScrollHandDrag mode and control key is not pressed, change to RubberBandDrag"
                self.setDragMode(QGraphicsView.RubberBandDrag)

        super(MyGraphicsView,  self).mouseReleaseEvent(event)

    def keyPressEvent(self,  event):
        if event.key() == Qt.Key_Control:
            print "control key down"
            self.m_ControlKeyDown = True

        # ignore if mouse already down since we don't want to suddenly change to pan mode if an item is being moved
        if event.key() == Qt.Key_Control and self.dragMode() != QGraphicsView.ScrollHandDrag and self.m_MouseIsDown == False:
            print "keyPressEvent - control key down, mouse isn't down and drag mode is not ScrollHandDrag, change to ScrollHandDrag"
            self.setDragMode(QGraphicsView.ScrollHandDrag)
        super(MyGraphicsView,  self).keyPressEvent(event)

    def keyReleaseEvent(self,  event):
        if event.key() == Qt.Key_Control:
            print "control key up"
            self.m_ControlKeyDown = False

        if event.key() == Qt.Key_Control and self.dragMode() == QGraphicsView.ScrollHandDrag and self.m_MouseIsDown == False:
            print "keyReleaseEvent - control key up and drag mode is ScrollHandDrag, mouse is not pressed, change to RubberBandDrag"
            self.setDragMode(QGraphicsView.RubberBandDrag)
        super(MyGraphicsView,  self).keyReleaseEvent(event)

    def wheelEvent(self,  event):
        factor = 1.2;
        if event.delta() < 0:
            factor = 1.0 / factor
        self.scale(factor, factor)

    def PreventItemsFromMovingOrBeingSelectedWhenPannning(self,  mouseEvent):
        itemUnderMouse = self.itemAt(mouseEvent.pos())
        if  itemUnderMouse is not None:
            print "preventing item from moving"
            bHadMovableFlagSet = itemUnderMouse.flags() & QGraphicsItem.ItemIsMovable
            itemUnderMouse.setFlag(QGraphicsItem.ItemIsMovable,  False)

            bWasSelected = itemUnderMouse.isSelected()

            bHadSelectableFlagSet = itemUnderMouse.flags() & QGraphicsItem.ItemIsSelectable
            itemUnderMouse.setFlag(QGraphicsItem.ItemIsSelectable,  False)

            super(MyGraphicsView,  self).mousePressEvent(mouseEvent)

            if bHadMovableFlagSet:
                print "set ItemIsMovable"
                itemUnderMouse.setFlag(QGraphicsItem.ItemIsMovable,  True)
            if bHadSelectableFlagSet:
                print "set ItemIsSelectable"
                itemUnderMouse.setFlag(QGraphicsItem.ItemIsSelectable,  True)
            if bWasSelected:
                print "setSelected True"
                itemUnderMouse.setSelected(True)

        else:
             print "no item under mouse - pass through"
             super(MyGraphicsView,  self).mousePressEvent(mouseEvent)

class MyGraphicsScene(QGraphicsScene):
    def __init__(self,  parent):
        super(MyGraphicsScene,  self).__init__()

def main():
    a = QApplication(sys.argv)
    w = MyMainWindow()
    w.show()

    scene = MyGraphicsScene(w)
    w.gv.setScene(scene)

    rect = scene.addRect( 10,  10,  40,  40)
    rect.setFlag( QGraphicsItem.ItemIsSelectable )
    rect.setFlag( QGraphicsItem.ItemIsMovable )

    rect = scene.addRect( 40,  40,  40,  40)
    rect.setFlag( QGraphicsItem.ItemIsSelectable )
    rect.setFlag( QGraphicsItem.ItemIsMovable )

    sys.exit(a.exec_()) 

if __name__ == '__main__':
    main()
4

1 に答える 1

5

パン中に基本実装をmouse*Eventsで呼び出さない場合、アイテムの選択は問題になりません。ただし、これには、組み込みのパン機能を再実装する必要があります。幸いなことに、それを実装するのは難しくありません。

IRC(#pyqt @ freenode)で何度か繰り返した後、これが最終的な実装です。

  • キーを長押しするとCTRL、パンが可能になります。マウスを押している間、CTRLキーを離すとパンモードが維持されます。
  • マウスを押すだけでラバー選択がアクティブになります
  • すべてのアクションはで制御されますLeft-Button
class MyGraphicsView(QGraphicsView):
    def __init__(self):
        super(MyGraphicsView, self).__init__()
        self.setDragMode(QGraphicsView.RubberBandDrag)
        self._isPanning = False
        self._mousePressed = False

    def mousePressEvent(self,  event):
        if event.button() == Qt.LeftButton:
            self._mousePressed = True
            if self._isPanning:
                self.setCursor(Qt.ClosedHandCursor)
                self._dragPos = event.pos()
                event.accept()
            else:
                super(MyGraphicsView, self).mousePressEvent(event)

    def mouseMoveEvent(self, event):
        if self._mousePressed and self._isPanning:
            newPos = event.pos()
            diff = newPos - self._dragPos
            self._dragPos = newPos
            self.horizontalScrollBar().setValue(self.horizontalScrollBar().value() - diff.x())
            self.verticalScrollBar().setValue(self.verticalScrollBar().value() - diff.y())
            event.accept()
        else:
            super(MyGraphicsView, self).mouseMoveEvent(event)

    def mouseReleaseEvent(self, event):
        if event.button() == Qt.LeftButton:
            if event.modifiers() & Qt.ControlModifier:
                self.setCursor(Qt.OpenHandCursor)
            else:
                self._isPanning = False
                self.setCursor(Qt.ArrowCursor)
            self._mousePressed = False
        super(MyGraphicsView, self).mouseReleaseEvent(event)

    def mouseDoubleClickEvent(self, event): pass

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Control and not self._mousePressed:
            self._isPanning = True
            self.setCursor(Qt.OpenHandCursor)
        else:
            super(MyGraphicsView, self).keyPressEvent(event)

    def keyReleaseEvent(self, event):
        if event.key() == Qt.Key_Control:
            if not self._mousePressed:
                self._isPanning = False
                self.setCursor(Qt.ArrowCursor)
        else:
            super(MyGraphicsView, self).keyPressEvent(event)


    def wheelEvent(self,  event):
        factor = 1.2;
        if event.delta() < 0:
            factor = 1.0 / factor
        self.scale(factor, factor)
于 2013-02-23T17:18:01.727 に答える