我正在尝试创建具有以下行为的 QGraphicsView:
当按住 control 键并按下鼠标左键时,应将视图设置为 ScrollHandDrag 模式以允许用户平移。
在 ScrollHandDrag 模式下,项目不应该是可选择/可移动的,如这里的问题:在 QGraphicsView 的 ScrollHandDrag 模式中,如何停止 QGraphicsItems 在场景中的移动?
如果按住控制键,单击鼠标左键,然后释放控制键,则视图应保持在 ScrollHandDrag 模式,直到释放鼠标,或者如果当时按下控制键,则将保持此模式鼠标被释放。
对我来说,这听起来应该相当简单。我已经实现了来自链接问题的逻辑,以及一些额外的逻辑来满足我的额外要求。然而,这似乎会导致以下两个问题:
在 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()