Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

setCursor Confusion



  • I have a class derrived from QGraphicsView.

    Here I use setCursor like this:

    void DungeonView::mousePressEvent(QMouseEvent *event)
    {
        if (event->button() == Qt::RightButton) {
            setCursor(Qt::CrossCursor);
        }
        else {
            QGraphicsView::mousePressEvent(event);
        }
    }
    
    void DungeonView::mouseReleaseEvent(QMouseEvent *event)
    { 
        if (cursor() == Qt::CrossCursor) {
            setCursor(Qt::ArrowCursor);
        }
        else {
            QGraphicsView::mouseReleaseEvent(event);
        }
    }
    

    This view contains a widget derrived from QGraphicsWidget.

    Here I do this:

    void Room::mousePressEvent(QGraphicsSceneMouseEvent *event)
    {
        if (event->button() == Qt::MouseButton::LeftButton) {
            setCursor(Qt::ClosedHandCursor);
        }
    }
    
    void Room::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
    {
        if (event->button() == Qt::LeftButton) {
            setCursor(Qt::OpenHandCursor);
        }
    }
    

    My assumption Is what I expect what will happen:

    If i press release the right button DungeonView handles the changes of the Cursor.
    If i press release the left button DungeonView forwards the events to room and it
    handles the changes of the Cursor.

    However if I pressed the left Button I alway see the Cursor of the left button. Event if I use right button again I always see the Cursor from the left button.

    It looks like Room never gives the events to DungeonView back. Why is that so ?


  • Lifetime Qt Champion

    Hi,

    Why don't you call the base class implementation in your Room subclass ?


  • Lifetime Qt Champion



  • I tryed this but still the hand cursors from Room stay.

    void Room::mousePressEvent(QGraphicsSceneMouseEvent *event)
    {
        if (event->button() == Qt::MouseButton::LeftButton) {
            setCursor(Qt::ClosedHandCursor);
        }
        else {
            event->ignore();
            QGraphicsWidget::mousePressEvent(event);
        }
    }
    
    void Room::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
    {
        if (event->button() == Qt::LeftButton) {
            setCursor(Qt::OpenHandCursor);
        }
        else {
            event->ignore();
            QGraphicsWidget::mouseReleaseEvent(event);
        }
    }
    

    how is the correct way use ignore or forward to the parent?


  • Lifetime Qt Champion

    Don't call both.



  • I also tryed to call only one but same behaviour.


  • Lifetime Qt Champion

    Can you provide a minimal compilable example that shows that behaviour ?



  • @sandro4912 said in setCursor Confusion:

    QGraphicsWidget::mouseReleaseEvent(event);

    Sorry for the delay. Here is the minimal example. If you click in the rectangle with right or left it should toggle hand cursor or cross. However if hand cursor was active the cross gets never enabled again.

    #ifndef ROOM_H
    #define ROOM_H
    
    #include <QGraphicsWidget>
    
    class Room : public QGraphicsWidget
    {
        Q_OBJECT
    public:
        explicit Room(QGraphicsItem *parent = nullptr);
    
        QRectF boundingRect() const override;
    
        void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
                   QWidget *widget) override;
    
    protected:
        void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
        void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
    
    };
    
    #endif // ROOM_H
    
    #include "room.h"
    
    #include <QGraphicsSceneMouseEvent>
    #include <QPainter>
    #include <QCursor>
    
    Room::Room(QGraphicsItem *parent)
        :QGraphicsWidget{ parent }
    {
        resize(boundingRect().size());
    }
    
    QRectF Room::boundingRect() const
    {
        return QRectF{QPointF{0, 0}, QPointF{100, 100}};
    }
    
    void Room::paint(QPainter *painter,
                     const QStyleOptionGraphicsItem *option, QWidget *widget)
    {
        painter->drawRect(QRectF{ QPointF{0, 0}, QPointF{100, 100}});
    }
    
    void Room::mousePressEvent(QGraphicsSceneMouseEvent *event)
    {
        if (event->button() == Qt::MouseButton::LeftButton) {
            setCursor(Qt::ClosedHandCursor);
        }
        else {
            event->ignore();
            //QGraphicsWidget::mousePressEvent(event);
        }
    }
    
    void Room::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
    {
        if (event->button() == Qt::LeftButton) {
            setCursor(Qt::OpenHandCursor);
        }
        else {
            event->ignore();
            //QGraphicsWidget::mouseReleaseEvent(event);
        }
    }
    
    #ifndef DUNGEONVIEW_H
    #define DUNGEONVIEW_H
    
    #include <QGraphicsView>
    
    class DungeonView : public QGraphicsView
    {
        Q_OBJECT
    public:
    
    
    protected:
        void mousePressEvent(QMouseEvent *event) override;
        void mouseReleaseEvent(QMouseEvent *event) override;
    };
    
    #endif // DUNGEONVIEW_H
    
    #include "dungeonview.h"
    
    #include <QMouseEvent>
    
    void DungeonView::mousePressEvent(QMouseEvent *event)
    {
        if (event->button() == Qt::RightButton) {
            setCursor(Qt::CrossCursor);
        }
        else {
            QGraphicsView::mousePressEvent(event);
        }
    }
    
    void DungeonView::mouseReleaseEvent(QMouseEvent *event)
    {
        if (cursor() == Qt::CrossCursor) {
             setCursor(Qt::ArrowCursor);
         }
         else {
             QGraphicsView::mouseReleaseEvent(event);
         }
    }
    
    #ifndef DUNGEON_H
    #define DUNGEON_H
    
    #include <QWidget>
    
    class QGraphicsScene;
    class DungeonView;
    class Room;
    
    class Dungeon : public QWidget
    {
        Q_OBJECT
    public:
        explicit Dungeon(QWidget *parent = nullptr);
    
    private:
        QGraphicsScene *mGraphicsScene;
        DungeonView *mDungeonView;
        Room *mRoom;
    };
    
    #endif // DUNGEON_H
    
    #include "dungeon.h"
    
    #include "room.h"
    #include "dungeonview.h"
    
    #include <QVBoxLayout>
    
    Dungeon::Dungeon(QWidget *parent)
        :QWidget{ parent },
          mGraphicsScene{ new QGraphicsScene },
          mDungeonView{ new DungeonView },
          mRoom{ new Room }
    {
        mRoom->setPos(QPoint{200, 200});
        mRoom->show();
    
        mGraphicsScene->addItem(mRoom);
    
        mDungeonView->setScene(mGraphicsScene);
        auto layout = new QVBoxLayout;
        layout->addWidget(mDungeonView);
        setLayout(layout);
    }
    
    #include "dungeon.h"
    
    #include <QApplication>
    
    int main(int argc, char *argv[])
    {
        QApplication app{ argc, argv };
        Dungeon dungeon;
        dungeon.show();
    
        return QApplication::exec();
    }
    

  • Lifetime Qt Champion

    From the QGraphicsItem::mousePressEvent documentation:

    The event is QEvent::ignore()d for items that are neither movable nor selectable.
    

    You have to make your item at least selectable for mouseReleaseEvent to be called.



  • @SGaist said in setCursor Confusion:

    selectable

    I tryed setFlag(QGraphicsWidget::ItemIsSelectable); in the constructor of Room but it still does not work.


  • Lifetime Qt Champion

    What version of Qt are you using ?
    On what OS ?

    Works fine on macOS High Sierra with Qt 5.13.1.



  • @SGaist
    I observed a strange behaviour on Windows.

    1. Right button press on DungeonView shows CrossCursor
    2. Right button release on DungeonView shows ArrowCursor
    3. Left button press on DungeonView shows ClosedHandCursor
    4. Left button release on DungeonView shows OpenHandCursor
    5. Right button press on DungeonView shows ArrowCursor (expect CrossCursor as step1)


  • @SGaist

    I use KDE Neon 5.17 with Qt 5.13.2.

    My behaviour is like this:

    Right button press on DungeonView shows CrossCursor
    Right button release on DungeonView shows ArrowCursor
    Left button press on DungeonView shows ClosedHandCursor
    Left button release on DungeonView shows OpenHandCursor
    Now I only can trigger the HandCursors. The CrossCursor never shows up again.

    I also testet it on Windows 10 which results in the same behaviour.


Log in to reply