Thank you Baz! You pointed me to the solution of my problem ... and it was easier than your solution :-)

I did not know of *self.viewport()* in the view class.

Updating the cursor of the view with self.viewport().setCursor() instead of just self.setCursor() did the trick.

On 25.08.2010 20:05, Baz Walter wrote:
On 25/08/10 09:54, Christopher M. Nahler wrote:
I'll take it as an "if all else fails" solution :-) not giving hope up now!

I have changed the item cursors and view cursors to be differnt to see
which one wins as sometimes it looked as if it was working. But it turns
out its the item cursors that wins.

After reading more on cursors I have found that application override
cursor works with a stack. Is this also the case with the "normal" item
cursors? Do I need to unset cursors? I see a reference to a
unsetCursor() function but cannot find details to it.

attempting to get this to work by setting the cursor on the view and/or the items can be quite, um, "challenging". it reminds me of one of those puzzles where you have to roll several ball bearings around at once trying to get them all to land in little holes :)

the main problem seems to be that setting the cursor on any item may reset the cursor on the view, depending on whether the mouse is currently over an item or not (amongst other things).

one way to solve this would be to avoid setting the cursor on the items altogether, and to use mouse/keyboard events on the view to dynamically control the current cursor shape.

here's an implementation that hopefully does what you want:

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 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)

    ### generic method for setting the cursor
    def updateCursor(self):
        m = self.scene().viewMode()
        if m == MyScene.SELECTMODE:
            item = self.itemAt(self.mapFromGlobal(QCursor.pos()))
            if item is None:
                self.viewport().setCursor(Qt.ArrowCursor)
            else:
                self.viewport().setCursor(Qt.OpenHandCursor)
        elif m == MyScene.EDITMODE:
            self.viewport().setCursor(Qt.ForbiddenCursor)
        elif m == MyScene.DRAWMODE:
            self.viewport().setCursor(Qt.CrossCursor)

    def mouseMoveEvent(self, mouseEvent):

        ### dynamically set the cursor
        self.updateCursor()

        if self.scene().viewMode() == MyScene.DRAWMODE:
            if self.scene().newItem:
                curPos = self.mapToScene(mouseEvent.pos())
                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)

        ### the default behaviour may unset the cursor, so reset it here
        self.updateCursor()

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

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

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

        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))

    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_())

_______________________________________________
PyQt mailing list    PyQt@riverbankcomputing.com
http://www.riverbankcomputing.com/mailman/listinfo/pyqt

Reply via email to