Results 1 to 9 of 9

Thread: qgraphicsview cursor setting logic

  1. #1
    Join Date
    Nov 2009
    Location
    San Antonio, TX
    Posts
    69
    Thanked 1 Time in 1 Post
    Qt products
    Qt4 Qt Jambi
    Platforms
    Unix/X11 Windows

    Default qgraphicsview cursor setting logic

    I am having an issue with QGraphicsView wrt setting the cursor when working with a QGraphicsItem. The basic setup is this, I set an initial cursor (CrossCursor=2) for the viewport of the view. I use a contextMenu (thru customContextMenuRequested) to allow a selection ("Extract Item") for creating an extraction qgraphicsitem that i can move around. When this item is created I change the viewport cursor to another cursor (ForbiddenCursor=14) and I set a specific cursor (SizeAllCursor=9) for the item. I also clear the contextMenu for the view and create a signal/slot mechanism to use a contextMenu for the item. The item contextmenu just has a "DONE" option that is suppose to delete the item and set the viewport cursor back to CrossCursor. However, the cursor viewed in the viewport after the item is deleted is still the ForbiddenCursor.

    I added an implementation of the viewportEvent method for the view and added a debug message for CursorChange. I see all the expected cursor changes, but there is an extra change event at the very end after I try to set the cursor back to CrossCursor. The event shows that the cursor is being set to the ForbiddenCursor.

    Digging thru the Qt source code (qgraphicsview.cpp), there is an internal originalCursor that is being saved/used when a mouse move is triggered. This is where the cursor is being set back to the ForbidenCursor in the app (followed it thru with qtcreator debugger). It seems that my item contextMenu and subsequent set cursor is not seen by the qgraphicsview and the next move of the mouse sets the cursor to this original cursor, which is really an old cursor. There is no access to this originalCursor to clear it or disable its use.

    I was hoping that someone can help me find a way around this issue. I need to change the cursors of the viewport with certain modes, but I cannot find the proper way/order that allows the viewport cursor to go back to the original cursor after the items use.

    -----------------------

    I have a much larger application that I am seeing the issue, but I have created a small app that exhibits the same behavior as descibed above and is included below.

    Qt Code:
    1. #include <QApplication>
    2. #include "window.h"
    3.  
    4. int main(int argc, char *argv[])
    5. {
    6. QApplication app(argc, argv);
    7. Window w;
    8. w.show();
    9. return app.exec();
    10. }
    To copy to clipboard, switch view to plain text mode 
    Qt Code:
    1. #ifndef _WINDOW_H_
    2. #define _WINDOW_H_
    3.  
    4. #include <QMainWindow>
    5.  
    6. class View;
    7.  
    8. class Window : public QMainWindow
    9. {
    10. Q_OBJECT
    11.  
    12. public:
    13. Window( QWidget * p = 0 );
    14. ~Window();
    15.  
    16. public slots:
    17. void viewContextMenu( const QPoint & pt );
    18. void extractContextMenu( const QPoint & pt, const QRectF & rect );
    19.  
    20. private:
    21. QGraphicsScene * m_scene;
    22. View * m_view;
    23. };
    24.  
    25. #endif
    To copy to clipboard, switch view to plain text mode 
    Qt Code:
    1. #include "window.h"
    2. #include "view.h"
    3. #include "item.h"
    4.  
    5. #include <QAction>
    6. #include <QGraphicsScene>
    7. #include <QMenu>
    8.  
    9. Window::Window( QWidget * p )
    10. : QMainWindow( p )
    11. {
    12. m_scene = new QGraphicsScene( 0, 0, 1000, 1000);
    13. m_scene->setBackgroundBrush(QBrush(Qt::black, Qt::SolidPattern));
    14.  
    15. m_view = new View;
    16. m_view->setScene(m_scene);
    17. m_view->fitInView( m_scene->sceneRect() );
    18. setCentralWidget(m_view);
    19.  
    20. r->setPen( QPen(Qt::cyan) );
    21. r->setRect( m_scene->sceneRect() );
    22. m_scene->addItem( r );
    23.  
    24. m_view->setContextMenuPolicy( Qt::CustomContextMenu );
    25. connect( m_view,
    26. SIGNAL( customContextMenuRequested(const QPoint &) ),
    27. SLOT( viewContextMenu(const QPoint &) ) );
    28.  
    29. m_view->viewport()->setCursor( Qt::CrossCursor );
    30. }
    31.  
    32. Window::~Window()
    33. {
    34. }
    35.  
    36. void Window::viewContextMenu( const QPoint & pt )
    37. {
    38. QMenu contextMenu;
    39. QAction * act;
    40.  
    41. contextMenu.addAction( tr("Extract Item") );
    42.  
    43. act = contextMenu.exec( m_view->viewport()->mapToGlobal(pt) );
    44. if( NULL != act )
    45. {
    46. Item *item = new Item;
    47. item->setRect( QRectF( 0, 0, 100, 100 ) );
    48. item->setPen( QPen(Qt::green) );
    49. item->setBrush( QBrush(Qt::red) );
    50. item->setPos( m_view->mapToScene(pt) );
    51. item->setCursor( Qt::SizeAllCursor );
    52. item->setFlag( QGraphicsItem::ItemIsMovable, true );
    53. connect( item,
    54. SIGNAL( requestContextMenu(const QPoint&,const QRectF&) ),
    55. SLOT( extractContextMenu(const QPoint&,const QRectF&) ) );
    56. m_scene->addItem(item);
    57.  
    58. m_view->setContextMenuPolicy( Qt::DefaultContextMenu );
    59. m_view->viewport()->setCursor( Qt::ForbiddenCursor );
    60. }
    61. }
    62.  
    63. void Window::extractContextMenu( const QPoint & pt, const QRectF & /*rect*/ )
    64. {
    65. QMenu contextMenu;
    66. QAction * act;
    67. Item *pGI = qobject_cast<Item*>(sender());
    68.  
    69. contextMenu.addAction( tr("Done") );
    70.  
    71. act = contextMenu.exec( pt );
    72. if( NULL != act )
    73. {
    74. m_view->setContextMenuPolicy( Qt::CustomContextMenu );
    75. m_view->scene()->removeItem( pGI );
    76. delete pGI;
    77.  
    78. m_view->viewport()->setCursor( Qt::CrossCursor );
    79. }
    80. }
    To copy to clipboard, switch view to plain text mode 
    Qt Code:
    1. #ifndef __VIEW_H__
    2. #define __VIEW_H__
    3.  
    4. #include <QDebug>
    5. #include <QEvent>
    6. #include <QGraphicsView>
    7.  
    8. class View : public QGraphicsView
    9. {
    10. Q_OBJECT
    11.  
    12. public:
    13. View( QWidget* parent = 0 ) : QGraphicsView( parent )
    14. {
    15. setFrameStyle( QFrame::NoFrame );
    16. setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
    17. setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
    18. }
    19.  
    20. protected:
    21. bool viewportEvent( QEvent * event )
    22. {
    23. if( QEvent::CursorChange == event->type() )
    24. {
    25. qDebug() << "Cursor Change: " << viewport()->cursor().shape();
    26. }
    27. return QGraphicsView::viewportEvent(event);
    28. }
    29. };
    30.  
    31. #endif
    To copy to clipboard, switch view to plain text mode 
    Qt Code:
    1. #ifndef __ITEM_H__
    2. #define __ITEM_H__
    3.  
    4. #include <QGraphicsRectItem>
    5. #include <QGraphicsSceneMouseEvent>
    6.  
    7. class Item : public QObject, public QGraphicsRectItem
    8. {
    9. Q_OBJECT
    10.  
    11. public:
    12. Item() : QGraphicsRectItem( NULL ) {}
    13. ~Item() {}
    14.  
    15. signals:
    16. void requestContextMenu( const QPoint & pt, const QRectF & requestRect );
    17.  
    18. protected:
    19. void contextMenuEvent( QGraphicsSceneContextMenuEvent* gscme )
    20. {
    21. emit requestContextMenu( gscme->screenPos(), mapRectToScene( rect() ) );
    22. }
    23. };
    24.  
    25. #endif
    To copy to clipboard, switch view to plain text mode 

  2. #2
    Join Date
    Feb 2008
    Posts
    491
    Thanks
    12
    Thanked 142 Times in 135 Posts
    Qt products
    Qt4 Qt5
    Platforms
    Unix/X11

    Default Re: qgraphicsview cursor setting logic

    Interesting problem.

    In the source code (here) there is this little tidbit:
    // Find the topmost item under the mouse with a cursor.
    Try making the QGraphicsRectItem that is the size of the sceneRect a class member and then change the cursor on it in your context menu slots. That way the mouseMoveEventHandler function will return before the code that resets the original cursor.

  3. #3
    Join Date
    Nov 2009
    Location
    San Antonio, TX
    Posts
    69
    Thanked 1 Time in 1 Post
    Qt products
    Qt4 Qt Jambi
    Platforms
    Unix/X11 Windows

    Default Re: qgraphicsview cursor setting logic

    Sorry, that sceneRect rect item code was left over from some previous test code . . . thats what happens with cut&paste. I removed that code and the same issue persists. I assume it has more to do with deleting the item before it has a chance to return to mouse move event.

  4. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: qgraphicsview cursor setting logic

    Does it help if you use QApplication::setOverrideCursor() and QApplication::restoreOverrideCursor() instead of setCursor()? Of course provided it makes sense to set an override cursor for your application logic. If not then I suggest you post a custom event to your view that will restore the proper cursor after are your functionality is done. Then you'll modify the cursor after the faulty code in Qt executes so it is bound to work.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  5. #5
    Join Date
    Nov 2009
    Location
    San Antonio, TX
    Posts
    69
    Thanked 1 Time in 1 Post
    Qt products
    Qt4 Qt Jambi
    Platforms
    Unix/X11 Windows

    Default Re: qgraphicsview cursor setting logic

    This widget is one of several components. I need the cursor to change just on the widget itself and not on the entire application so the override cursor is not an option.

    So I took your suggestion and implemented a custom event (with the code below), but the event is processed before returning back to qgraphicsview and same issue happens :-(

    I even added the ability to change the viewport cursor from the view context menu, and the same thing happens . . . the set cursor and the change cursor event are happening before the qv mouse move event and when it returns to the mouse event, it sets the cursor to the original "unwanted" cursor.

    Qt Code:
    1. #ifndef __EVENT_H__
    2. #define __EVENT_H__
    3.  
    4. #include <QEvent>
    5. #include <QCursor>
    6.  
    7. class SetCursorEvent : public QEvent
    8. {
    9. public:
    10. SetCursorEvent( const QCursor & cursor )
    11. : QEvent( SetCursorEvent::type() ),
    12. m_cursor( cursor )
    13. {}
    14.  
    15. virtual ~SetCursorEvent()
    16. {}
    17.  
    18. static QEvent::Type type()
    19. {
    20. return EventType;
    21. }
    22.  
    23. QCursor cursor() const
    24. {
    25. return m_cursor;
    26. }
    27.  
    28. private:
    29. static QEvent::Type EventType;
    30. QCursor m_cursor;
    31. };
    32.  
    33. #endif
    To copy to clipboard, switch view to plain text mode 
    Qt Code:
    1. #ifndef __VIEW_H__
    2. #define __VIEW_H__
    3.  
    4. #include "event.h"
    5.  
    6. #include <QDebug>
    7. #include <QEvent>
    8. #include <QGraphicsView>
    9.  
    10. class View : public QGraphicsView
    11. {
    12. Q_OBJECT
    13.  
    14. public:
    15. View( QWidget* parent = 0 ) : QGraphicsView( parent )
    16. {
    17. setFrameStyle( QFrame::NoFrame );
    18. setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
    19. setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
    20. }
    21.  
    22. protected:
    23. bool viewportEvent( QEvent * event )
    24. {
    25. if( QEvent::CursorChange == event->type() )
    26. {
    27. qDebug() << "Cursor Change:" << viewport()->cursor().shape();
    28. }
    29. else if( SetCursorEvent::type() == event->type() )
    30. {
    31. SetCursorEvent * e = static_cast<SetCursorEvent*>(event);
    32. qDebug() << "SetCursorEvent:" << e->cursor().shape();
    33. viewport()->setCursor( e->cursor() );
    34. }
    35. return QGraphicsView::viewportEvent(event);
    36. }
    37. };
    38.  
    39. #endif
    To copy to clipboard, switch view to plain text mode 
    Qt Code:
    1. #include "event.h"
    2. #include "window.h"
    3. #include "view.h"
    4. #include "item.h"
    5.  
    6. #include <QAction>
    7. #include <QApplication>
    8. #include <QGraphicsScene>
    9. #include <QMenu>
    10.  
    11. QEvent::Type SetCursorEvent::EventType =
    12. static_cast<QEvent::Type>(QEvent::registerEventType());
    13.  
    14. Window::Window( QWidget * p )
    15. : QMainWindow( p )
    16. {
    17. m_scene = new QGraphicsScene( 0, 0, 1000, 1000);
    18. m_scene->setBackgroundBrush(QBrush(Qt::black, Qt::SolidPattern));
    19.  
    20. m_view = new View;
    21. m_view->setScene(m_scene);
    22. m_view->fitInView( m_scene->sceneRect() );
    23. setCentralWidget(m_view);
    24.  
    25. m_view->setContextMenuPolicy( Qt::CustomContextMenu );
    26. connect( m_view,
    27. SIGNAL( customContextMenuRequested(const QPoint &) ),
    28. SLOT( viewContextMenu(const QPoint &) ) );
    29.  
    30. m_view->viewport()->setCursor( Qt::CrossCursor );
    31. }
    32.  
    33. Window::~Window()
    34. {
    35. }
    36.  
    37. void Window::viewContextMenu( const QPoint & pt )
    38. {
    39. QMenu contextMenu;
    40. QAction * act;
    41.  
    42. contextMenu.addAction( tr("Extract Item") );
    43. contextMenu.addAction( tr("Change Cursor") );
    44.  
    45. act = contextMenu.exec( m_view->viewport()->mapToGlobal(pt) );
    46. if( NULL != act )
    47. {
    48. switch( contextMenu.actions().indexOf(act) )
    49. {
    50. case 0:
    51. {
    52. Item *item = new Item;
    53. item->setRect( QRectF( 0, 0, 100, 100 ) );
    54. item->setPen( QPen(Qt::green) );
    55. item->setBrush( QBrush(Qt::red) );
    56. item->setPos( m_view->mapToScene(pt) );
    57. item->setCursor( Qt::SizeAllCursor );
    58. item->setFlag( QGraphicsItem::ItemIsMovable, true );
    59. connect( item,
    60. SIGNAL( requestContextMenu(const QPoint&,const QRectF&) ),
    61. SLOT( extractContextMenu(const QPoint&,const QRectF&) ) );
    62. m_scene->addItem(item);
    63.  
    64. m_view->setContextMenuPolicy( Qt::DefaultContextMenu );
    65. m_view->viewport()->setCursor( Qt::ForbiddenCursor );
    66. break;
    67. }
    68. case 1:
    69. {
    70. Qt::CursorShape shape;
    71. if( m_view->viewport()->cursor().shape() == Qt::OpenHandCursor )
    72. {
    73. shape = Qt::CrossCursor;
    74. }
    75. else
    76. {
    77. shape = Qt::OpenHandCursor;
    78. }
    79. SetCursorEvent * e = new SetCursorEvent( shape );
    80. QApplication::postEvent( m_view->viewport(), e );
    81. //m_view->viewport()->setCursor( shape );
    82. break;
    83. }
    84. }
    85. }
    86. }
    87.  
    88. void Window::extractContextMenu( const QPoint & pt, const QRectF & /*rect*/ )
    89. {
    90. QMenu contextMenu;
    91. QAction * act;
    92. Item *pGI = qobject_cast<Item*>(sender());
    93.  
    94. contextMenu.addAction( tr("Done") );
    95. contextMenu.addAction( tr("Change Cursor") );
    96.  
    97. act = contextMenu.exec( pt );
    98. if( NULL != act )
    99. {
    100. switch( contextMenu.actions().indexOf(act) )
    101. {
    102. case 0:
    103. {
    104. m_view->setContextMenuPolicy( Qt::CustomContextMenu );
    105. m_view->scene()->removeItem( pGI );
    106. delete pGI;
    107. //m_view->viewport()->setCursor( Qt::CrossCursor );
    108. SetCursorEvent * e = new SetCursorEvent( Qt::CrossCursor );
    109. QApplication::postEvent( m_view->viewport(), e );
    110. break;
    111. }
    112. case 1:
    113. {
    114. //m_view->viewport()->setCursor( Qt::WaitCursor );
    115. SetCursorEvent * e = new SetCursorEvent( Qt::WaitCursor );
    116. QApplication::postEvent( m_view->viewport(), e );
    117. break;
    118. }
    119. }
    120. }
    121. }
    To copy to clipboard, switch view to plain text mode 

  6. #6
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: qgraphicsview cursor setting logic

    In that case use a singleshot timer or QMetaObject::invokeMethod() to call the cursor change functionality with a small delay (e.g. 20ms). The delay will not be noticable to the user.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  7. #7
    Join Date
    Nov 2009
    Location
    San Antonio, TX
    Posts
    69
    Thanked 1 Time in 1 Post
    Qt products
    Qt4 Qt Jambi
    Platforms
    Unix/X11 Windows

    Default Re: qgraphicsview cursor setting logic

    With singleShot timer, I can get the delay but the single/slot does not allow any arguments, eg new cursorMask . . . but I can probably work around that.
    With invokeMethod, I can call the needed method with the proper argument, but I do not see a way to specify a delay? Am I missing something? Or are you saying to just use a 20 ms sleep?

  8. #8
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: qgraphicsview cursor setting logic

    Quote Originally Posted by mcarter View Post
    With singleShot timer, I can get the delay but the single/slot does not allow any arguments, eg new cursorMask . . . but I can probably work around that.
    With invokeMethod, I can call the needed method with the proper argument, but I do not see a way to specify a delay? Am I missing something? Or are you saying to just use a 20 ms sleep?
    No, no sleep(). You can store the "argument" in some member variable and then fetch it from there when the timer fires.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  9. #9
    Join Date
    Nov 2009
    Location
    San Antonio, TX
    Posts
    69
    Thanked 1 Time in 1 Post
    Qt products
    Qt4 Qt Jambi
    Platforms
    Unix/X11 Windows

    Default Re: qgraphicsview cursor setting logic

    Right, no sleep . . . was just thinking how to use the invokeMethod.

    I implemented the singleShot timer, and while it works with my linux laptop, it does not seem to work on my windows test machine. The cursor changes, but once I move the mouse it reverts to the previous cursor again.

    I did find QTBUG-3732 and QTBUG-4190 in the Qt bug reports, which both seem exactly related to what I am seeing. However, they are both closed (2009/2010). What is the best procedure to re-open these bugs, because it looks like an obvious logic problem with the cursor and graphicsview. My suggestion would be to get rid of the internal originalCursor and use the cursor of the GraphicsView, since that it not really used anywhere, for the cursor of the viewport. I guess in the meantime I need to abort what I am trying to accomplish or try to "fix" graphicsview with my oen code.

    Also, when I was working in windows, I noticed that the cursors are really unusable with a view that is mostly black (especially CrossCursor) . . . the cursor just "disappears". Do I need to use a custom cursor to get the same feel as with linux and X11?

Similar Threads

  1. Replies: 3
    Last Post: 3rd September 2012, 07:32
  2. Setting manually cursor position on multi screen systems
    By irreriwan in forum Qt Programming
    Replies: 0
    Last Post: 4th March 2008, 09:47
  3. Setting a cursor on QTextEdit
    By Erlendhg in forum Qt Programming
    Replies: 6
    Last Post: 20th March 2007, 17:53
  4. setting Cursor for one operation
    By keshab in forum Newbie
    Replies: 1
    Last Post: 22nd December 2006, 08:09
  5. setting cursor problem in QTextEdit
    By jyoti kumar in forum Qt Programming
    Replies: 3
    Last Post: 19th May 2006, 08:17

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.