2013-02-22 422 views
4

我试图创建一个具有以下行为的QGraphicsView:的QGraphicsView双击事件和ScrollHandDrag模式项目问题

  • 当控制键被和鼠标左键向下,认为应设置以ScrollHandDrag模式允许用户平移。

  • 当ScrollHandDrag模式,项目不应该选择/移动,如问题在这里:In ScrollHandDrag mode of QGraphicsView, How to stop movement of QGraphicsItems on scene?

  • 如果控制键举行,鼠标左键被点击,然后控制键被释放,那么视图应该保持在ScrollHandDrag模式,直到鼠标被释放,或者如果在释放鼠标时控制键被关闭,它将保持在这种模式下。

对我来说这听起来应该是相当简单的。我已经实现了链接问题的逻辑,还有一些额外的逻辑来满足我的额外需求。然而,这似乎会导致以下两个搅局者:

  • 在mousePressEvent,设置鼠标下的项目不具有可移动的和可选的标志,调用基类,然后重新应用标志导致项目变成“冻结”。解决这个问题的唯一方法似乎是在项目之外单击几次控制+单击,释放控制+释放。同样,当它进入这种状态时,没有物品可以移动(尽管它们仍然可以被选择)。

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

所以我想知道我怎么能解决这个项目的问题变得冻结当使用从In ScrollHandDrag mode of QGraphicsView, How to stop movement of QGraphicsItems on scene?逻辑,以及如何处理与陌生的鼠标双击事件 - 有没有办法把他们离开?

这里是我的代码(这也几乎是我的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() 

回答

5

如果不调用基在平移时执行mouse*Event,项目选择不会成为问题。但是,现在需要重新实现内置的平移功能。幸运的是,实现它并不难。

经过一番反复的IRC(#pyqt @ freenode上),这是最终的实现:

  • 按住CTRL 关键使平移。当鼠标按下时,释放按键CTRL键保持平移模式。
  • 只需按下鼠标激活橡胶选择
  • 所有动作与左键控制
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) 
+2

我可以通过设置的QGraphicsView没有互动,而在ScrollHandDrag模式修复具有可以移动/可选项目的问题。 setInteractive(真); (C++) – FSaccilotto 2013-04-22 15:01:53