[Solved] "Lock" the UI while waiting on an async event?
-
The common "hack" to accomplish this in Java would be to enable a glass pane
over the window to block user mouse clicks. If I'm waiting for an animation to finish
or if I have to block until an async event returns, how do I protect the app
from impatient clicks (and ideally, any input), lol? -
That sort of worked. I blocked the key and mouse events, but a click on a button
that is connected to a signal still -- randomly -- goes through. It'll consume it
most of the time, but sometimes one gets through?The easier way is to consume everything and only allow what I'm waiting for, but I'm
assuming that's "dangerous". -
My event filter is on another machine but is essentially:
@
qapp->installEventFilter(this)eventFilter(...){
if(event.type == mouse press|release|dblclick or key press)
return true
else
return false}
@The weird thing (aside from the random failure to consume a button signal) is that if I click
in text fields it moves the cursor between them - though it does at least always consume
key presses. How is the cursor bouncing around if the mouse events are consumed? -
I think they will be getting translated to FocusInEvent's somewhere earlier in the chain.
Try setting a break point in your event filter to see what object/event combinations are being accepted. You can then add to the list of combinations that you need to filter out.
-
I am printing out the event types and in the cases where the button is firing I'm seeing a 200 event type (CloseSoftwareInputPanel). I should say - if I just put the mouse over the button and click away, the filter works as expected. These "randomly" successful button clicks is when I alternate quickly between a text field and the button while pressing a key repeatedly.
-
Gah! That didn't work. It seems that moving the mouse to the text edit component right above the button and then back down and clicking is sufficient to outsmart the filter. :(
EDIT: I figured out the cause! Clicking on the button and not releasing and then moving the mouse outside the button. I don't even have to release the mouse button. Just moving it outside fires the signal. Now to fix it...
-
Unfortunately it's not a trivial GUI with just a couple of static widgets. There are many nested pieces full of widgets that change with time. Many user actions must wait on a server response message that could take (uncomfortably) many seconds to come back. I really didn't want to blank out the screen or display a modal "waiting..." dialog for that long, but I would like to defend against impatient mouse clickers and button mashers.
I'm new to Qt so I have no idea what the best way to do this. I'm only trying the eventFilter way because that's the response I got. blockSignals() sounds good but I'd have to traverse the whole layout tree and do it on everything which doesnt sound appealing.
Gerolf, what did you mean by "disabling" the main window?
-
Well, applying it to all buttons at least should be easy enough:
@
//mainWindow is a pointer to the widget that represents your ui widgetQList<QAbstractButton*> buttons = mainWindow.findChildren<QAbstractButton*>();
foreach(QAbstractButton* button, buttons)
button->blockSignals(true);
@I think Gerolf was talking about this:
@
mainWindows->setEnabled(false);
@ -
SON OF A...! :)
mainWindow->setEnabled(false) was EXACTLY what I was looking for. Thanks so much.Going back to that "glitch" for a moment, is that behavior a bug?
Clicking on a button without release and then moving outside the button while still
holding the button down, should not fire. In fact, in most cases isn't this exactly how
you cancel an accidental press.
I've never seen that type of behavior on any platform. -
OK, that's good. I marked the issue as "Solved".
I hope you did notice that the setEnabled() call also modifies the visual appearance of your application? I hope that is what you intended? Personally, I like it when I can see that clicking won't have an effect, but that wasn't too clear from your use case.
I think Qt normally won't fire a clicked() signal if you move the mouse off a button before releasing. If it does, I would considder that a bug, but perhaps it was caused by your own event filter (blocking a focus out, perhaps?)
-
modifies the visual appearance of your application
TBH, I wanted to block for X seconds without a different visual appearance, and then
after a timeout then go to the disabled look. I'm not going to be choosy though!
The eventFilter() solution was almost perfect, but reliable code is more important.Apparently, that unwanted button behavior happens when you consume mouse press and
mouse release (but not either alone). Another mark against the eventFilter method is that
if you right-click in a text box and popup displays that locks up the app for good.Apologies... My bad
No way. Thanks for the help. It would have been a great solution without that one hiccup.