QGraphicsView双击事件和ScrollHandDrag模式项目问题

pau*_*ulm 4 qt qt4 pyqt pyqt4 python-2.7

我正在尝试使用以下行为创建QGraphicsView:

  • 当按住控制键并且鼠标左键停止时,视图应设置为ScrollHandDrag模式以允许用户平移.

  • 在ScrollHandDrag模式下,项目不应该是可选择/可移动的,如下面的问题所示:在QGraphicsView的ScrollHandDrag模式中,如何停止场景中QGraphicsItems的移动?

  • 如果按住控制键,则单击鼠标左键,然后释放控制键,然后视图应保持ScrollHandDrag模式直到释放鼠标,或者如果控制键在此时停止,则将保持此模式鼠标被释放.

对我来说,这听起来应该是相当简单的.我已经从链接的问题中实现了逻辑,并为我的额外需求提供了一些额外的逻辑.然而,这似乎导致以下两个showstoppers:

  • 在mousePressEvent中,将鼠标下的项设置为不具有可移动和可选择的标志,调用基类,然后重新应用标志会使项目变为"冻结".解决这个问题的唯一方法似乎是控件+点击,释放控制+释放在项目外单击几次.此外,当它进入此状态时,不能移动任何项目(尽管仍然可以选择它们).

  • 双击视图会导致mousePressEvent,然后是两个mouseReleaseEvents!这打破了我的逻辑.

所以我想知道如何在QGraphicsView的In ScrollHandDrag模式中解决物品被冻结的问题,如何停止QGraphicsItems在场景中的移动?使用,以及如何处理奇怪的双击鼠标事件 - 是否有办法将其关闭?

这是我的代码(这也是我的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()
Run Code Online (Sandbox Code Playgroud)

Ava*_*ris 5

如果mouse*Event在平移时没有调用s中的基本实现,则项目选择不会成为问题.但是,现在需要重新实现内置的平移功能.幸运的是,实现它并不困难.

在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)
Run Code Online (Sandbox Code Playgroud)

  • 我可以通过在ScrollHandDrag模式下设置QGraphicsView不是交互式来解决可移动/可选项的问题.setInteractive(真); (C++) (2认同)