PDA

View Full Version : Problems with setCursor in QGraphicsScene/View



lightning2911
25th August 2010, 11:24
In the code sample below I have found a problem with changing cursors.

Basically I have a MyScene with two MyRect items shown with a MyView.

In the view I change "modes" by pressing F1 - F3. To visually represent the modes I want to change the cursor of the view (background) and the items.

If I do not move the mouse cursor over items the cursor of the view changes fine. As soon as I move the cursors over the items, the item cursors change ok but the view cursor does not change or changes wrong.

Is this a bug or am I doing something wrong here?


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

class MyRect(QGraphicsRectItem):

def __init__(self, parent=None, scene=None):
# init parent
super().__init__(parent, scene)

# set flags
self.setFlag(QGraphicsItem.ItemIsSelectable, True)
self.setFlag(QGraphicsItem.ItemIsMovable, True)
self.setFlag(self.ItemSendsGeometryChanges, True)
self.setAcceptHoverEvents(True)

def paint(self, painter, option, widget):
if self.isSelected():
painter.setPen(QPen(Qt.black, 1, Qt.DotLine))
else:
painter.setPen(QPen(Qt.black, 1, Qt.SolidLine))

painter.setBrush(QBrush(Qt.white, Qt.SolidPattern))
painter.drawRect(self.rect())

class MyView(QGraphicsView):

def __init__(self, parent=None):
super().__init__(parent)
self.setMouseTracking(True)
self.scale(1,1)
self.startPos = None

def setSelectMode(self):
print("view setting select mode")
self.scene().setViewMode(MyScene.SELECTMODE)

def setEditMode(self):
print("view setting edit mode")
self.scene().setViewMode(MyScene.EDITMODE)
if len(self.scene().selectedItems()) > 1:
self.scene().clearSelection()

def setDrawMode(self):
print("view setting draw mode")
self.scene().setViewMode(MyScene.DRAWMODE)
self.scene().clearSelection()

def updateItems(self):
print("view updateItems")
m = self.scene().viewMode()

if m == MyScene.SELECTMODE:
print("is select mode")
self.setCursor(Qt.ArrowCursor)
print(self.cursor().shape())
#self.update()
itemCursor = Qt.OpenHandCursor

elif m == MyScene.EDITMODE:
print("is edit mode")
self.setCursor(Qt.ForbiddenCursor)
print(self.cursor().shape())
#self.update()
itemCursor = Qt.PointingHandCursor

elif m == MyScene.DRAWMODE:
print("is draw mode")
self.setCursor(Qt.CrossCursor)
print(self.cursor().shape())
#self.update()
itemCursor = Qt.WaitCursor

items = self.scene().items()

for item in items:
item.setCursor(itemCursor)
#item.update()

def drawBackground(self, painter, rect):
# draw a rect in size of sceneRect

painter.setPen(QPen(Qt.red, 0, Qt.NoPen))
painter.setBrush(QBrush(Qt.lightGray, Qt.SolidPattern))
painter.drawRect(self.scene().sceneRect())

def mousePressEvent(self, mouseEvent):
print("view mousePress")
curPos = mouseEvent.pos()
self.startPos = self.mapToScene(curPos)

if self.scene().viewMode() == MyScene.DRAWMODE:
self.scene().newItem = MyRect(scene=self.scene())
self.scene().newItem.setRect(QRectF(self.startPos, QSizeF(0, 0)))
self.scene().newItem.setSelected(True)

else:
super().mousePressEvent(mouseEvent)

def mouseMoveEvent(self, mouseEvent):
#print("view mouseMove")
curPos = self.mapToScene(mouseEvent.pos())

if self.scene().viewMode() == MyScene.DRAWMODE:
if self.scene().newItem:
newRectF = QRectF(self.startPos, curPos)
if newRectF != self.scene().newItem.rect():
self.scene().newItem.setRect(newRectF.normalized() )

else:
super().mouseMoveEvent(mouseEvent)

def mouseReleaseEvent(self, mouseEvent):
print("view mouseRelease")

if self.scene().newItem:
# delete item if zero height or width
if (self.scene().newItem.rect().width() == 0
or self.scene().newItem.rect().height() == 0):
self.scene().removeItem(self.scene().newItem)
del self.scene().newItem

self.startPos = None
self.scene().newItem = None
super().mouseReleaseEvent(mouseEvent)

def keyPressEvent(self, keyEvent):
if keyEvent.key() == Qt.Key_F1:
self.setSelectMode()
self.updateItems()

elif keyEvent.key() == Qt.Key_F2:
self.setEditMode()
self.updateItems()

elif keyEvent.key() == Qt.Key_F3:
self.setDrawMode()
self.updateItems()

elif keyEvent.key() == Qt.Key_Delete:
if self.scene().viewMode() == MyScene.SELECTMODE:
items = self.scene().selectedItems()
if len(items):
for item in items:
self.scene().removeItem(item)
del item

class MyScene(QGraphicsScene):

SELECTMODE, EDITMODE, DRAWMODE = (0, 1, 2)
validViewModes = [SELECTMODE, EDITMODE, DRAWMODE]

def __init__(self, parent=None):
super().__init__(parent)

self._viewMode = MyScene.SELECTMODE
self.newItem = None

self.setSceneRect(-300, -200, 600, 400)

# add some item
someRect = MyRect(scene=self)
someRect.setRect(QRectF(0, 0, 160, 80))

# add another item
anotherRect = MyRect(scene=self)
anotherRect.setRect(QRectF(-80, -40, 80, 160))

# add own item
#myItem = MyItem(scene=self)

def setViewMode(self, value):
if value != self._viewMode:
if value in MyScene.validViewModes:
self._viewMode = value
else:
raise ValueError("invalid view mode")

def viewMode(self):
return self._viewMode

class MainWindow(QMainWindow):

def __init__(self, parent=None):
# call parent init
super().__init__(parent)

# setup scene object
self.scene = MyScene()

# setup view object
self.view = MyView()

# connect scene to view
self.view.setScene(self.scene)

# create layout
layout = QVBoxLayout()

# add view to layout
layout.addWidget(self.view)

# set the margin of the object in the layout
layout.setContentsMargins(0, 0, 0, 0)

# create the central widget
self.widget = QWidget()

# lay it out
self.widget.setLayout(layout)

# set it to central
self.setCentralWidget(self.widget)

if __name__ == "__main__":

import sys

# setup application object
app = QApplication(sys.argv)

# create (parent) main window
mainWindow = MainWindow()
mainWindow.setWindowTitle("testScene")
mainWindow.show()

# run application object
sys.exit(app.exec_())

lightning2911
25th August 2010, 11:26
btw this is on win7 using Python 3.1, PyQt 4.7.3, Qt 4.6.2

norobro
26th August 2010, 04:49
Found this (http://bugreports.qt.nokia.com/browse/QTBUG-4190) on Qt Bug Tracker. Do a search for setCursor. There seem to be a lot of bugs related to it.

I ginned up a C++ version of your app and tried setting the cursor on the viewport as suggested in the first comment, but it didn't completely work either. And I'm using 4.7.0-beta1. It works okay if the cursor is not over one of the graphicsitems when F1||F2||F3 is pressed and then moved onto an item, but not the other way round. The view always retains its last setting if a button is pressed while the cursor is over an item.

lightning2911
26th August 2010, 12:04
SOLVED it. have to set the view cursors with self.viewport().setCursor instead of self.setCursor() in the updateItems() method of MyView() class.