PDA

View Full Version : Change mouse cursor while the mouse is grabbed



pavele
3rd May 2019, 11:35
Hi, I want to change the mouse cursor while the mouse is being grabbed by my widget. This is to react to different objects the mouse is over. QWidget::setCursor does not do the job. Under Windows a special care needs to be taken in that case (which I have done in the past not using Qt). How it can be done in Qt?

d_stranz
3rd May 2019, 17:01
From the docs for QWidget::cursor():


Some underlying window implementations will reset the cursor if it leaves a widget even if the mouse is grabbed. If you want to have a cursor set for all widgets, even when outside the window, consider QApplication:: setOverrideCursor().


There is more information in QApplication::setOverrideCursor(). If you find that when using the QWidget setCursor() call that Windows is restoring the default cursor, then you may need to handle enter, leave, and mouseMove events in your widget to change the cursor back to what you want if Windows has changed it for you.

pavele
3rd May 2019, 22:14
Thank you, d_stranz. I already have read the relative docs including the ones you refer. Thanks again, but did you read my question carefully? If so, please post a working solution to the problem.

d_stranz
4th May 2019, 01:39
If so, please post a working solution to the problem.

If you have read other posts in this forum, you will understand that we aren't contractors who write your code for you. And typically, you don't get very good answers when you simply post something like "QWidget:: setCursor() does not do the job". Our response will amost always be "Why not? What have you tried?"

You also asked:


How it can be done in Qt?

and I pointed you to the Qt documentation that I thought discussed the problem you might be having, and I suggested ways you might work around it.

So the next thing for you to do is to post your non-working code and hopefully someone here will see why it isn't working and can help you fix it.

pavele
7th May 2019, 11:24
For those who have bumped the same problem and want a concrete solution (works for Qt 5.12.0):



void SpyButton::mousePressEvent(QMouseEvent *ev)
{
MyBase::mousePressEvent(ev);
grabMouse(m_cursor);
}

void SpyButton::mouseMoveEvent(QMouseEvent *ev)
{
MyBase::mouseMoveEvent(ev);
if (QGuiApplication::queryKeyboardModifiers()&Qt::ShiftModifier)
{
setCursor(m_cursorDifferent); // <- does nothing while mouse is gabbed
QGuiApplication::changeOverrideCursor(m_cursorProh ibited); // <- this works!
}
else
{
setCursor(m_cursor); // <- does nothing while mouse is grabbed
QGuiApplication::changeOverrideCursor(m_cursor); // <- this works!
}
}

It seems like (I do not have the time to download and debug Qt now) that QWidget::grabMouse() uses QApplication::setOverrideCursor() and QApplication::restoreOverrideCursor() internally (which makes sense). Otherwise QGuiApplication::changeOverrideCursor() would not work in the suggested solution. The documentation explicitly states that QApplication::setOverrideCursor() shall be called before changeOverrideCursor().

If we do not want to rely on QWidget::grabMouse() to internally call QApplication::setOverrideCursor() then I would suggest to ensure that one calls setOverrideCursor()/restoreOverrideCursor() pair explicitly in the code in the same way grabMouse() calls those on grab/release the mouse. Note that those must go in pairs because of the internal stack of cursors in the Qt application.

anda_skoa
7th May 2019, 11:55
Instead of


QGuiApplication::queryKeyboardModifiers()&Qt::ShiftModifier

you could also write


ev->modifiers() & Qt::ShiftModifier


Cheers,
_

pavele
7th May 2019, 12:14
Thanks anda_skoa
I would imagine QGuiApplication::queryKeyboardModifiers() would check the state at the moment of call.
ev->modifiers() would reflect the state in the moment of event generation.