QPushButton: How to know whether a "released" signal will be followed by a "clicked" signal? - c++

In my application, there are a few QPushButtons that I need to handle "invalid release" and "click" differently.
By "invalid release" I mean a release that happens outside the button (following a press within the button).
So I'm trying to inherit from QPushButton and implement my own signal void released(bool validClick);.
I'm thinking about using mouseReleaseEvent to check whether it's in the button's rect() to infer if a clicked() signal will follow the released() signal. Is this a good way to do it?
Update::background:
I have a group of three buttons, each of which can start the same action to the backend (with different configurations). However the backend can not handle multiple successive start commands without already started ones being cleaned up, so I have to prevent such a case in the button group.
This application is multi-touch, which makes it very easy to click all three buttons at the same time.
What I want to do:
1) When one of the buttons is pressed, disable others. This is essential because this is a multi touch GUI and multiple buttons being clicked at the same time is the first thing I need to avoid.
2) When the backend informs the button group that all previously started services has been closed and cleaned up and it's ready for next button click, button group unlocks all buttons.
3) If the user triggers a invalid release (press on the button, release outside it), all buttons should be unlocked immediately.
4) If the user triggers a valid release (click), the button group should also disable the button that the user has clicked so that it can not be clicked again until allowed by the backend.
If I can not differentiate between valid and invalid release, then I would have to treat case 4) and case 2) the same way as case 3). This is not desirable.

You don't care about presses nor releases, only about clicks and indications that tasks are done by the backend. You have two states: idle and busy. When idle, buttons are enabled. When any button is clicked() you transition to the busy state until the backend signals that it's not busy anymore. This is trivial to implement using the state machine framework.
You could also have three states to make failure handling easier: idle, pending, and busy. When any button is clicked() you transition to the pending state and request the work by the backend. When the backend signals that it has accepted the request, transition to busy, until the backend has signaled that it has done processing the request, whereas you transition to idle.

Related

QT C++ How to lock application or disable clickable for 3-5 minute

I want to disable click for whole application while receiving data from serial connection. I want to print information on the screen with a message box and turn off clicking for a certain time, how can I do it?
Grabbing mouse for widgets or setKeepMouseGrab for qml may be useful. Add a dummy widget which gets the mouse events. Make it grab the events when you start receiving data.
'Blocking' an application is never a good idea, because your OS will think the application unresponsive and shoot it down forcibly.
What you want, is a modal dialog (which runs on the main thread) with a progress indicator and no clickable interfaces.
A very basic code to achieve that would be:
void startTransfer()
{
ProgressBarDialog dlg; //Inherits from QDialog
//Create asynchronous transfer task.
dlg.setModal(true);
//Connect task and modal dialog
dlg.exec();
}
exec will 'block' all interaction with the other windows while the transfer is running. In fact, exec will only return, once the dialog is done with its job.

How are mouse events delivered to widgets in QT

Consider this situation:
For a button on a widget: if there is a chance that the button's clicked() slot is delivered (processed) after the widget (that contains the button) gets hided by explicitly calling hide()?
For instance, suppose that there is a timer, and in its timeout() slot, widget.hide() gets called. Coincidentally, The user clicks the button just at the same time time is up.
The question is: Is there a chance that the button's clicked() slot get called after timer's timeout() slot (which hides the widget that contains the button)?
No, the main thread in synchronous respect the GUI actions, so you cannot change the visibility of an object living in the main thread (like your QPushButton) exactly at the same time an user is clicking on it. Also, unless you 're on a multithread app with different events loops, your QTimer will be processed in the main thread too, so it is synchronous respect the UI. In few words: you may get a millisecond concurrence (clicking immediately before hiding it), but not actual parallelism.
If you care about this, maybe you can set a small delay before actually processing the click, just to check if the button was clicked but immediately hidden. In this case you can ignore the user input but it would be confusing. Another option would be to delay hiding the button if it was clicked, so the user doesn't get the wrong visual feedback.

Qt GUI event recording and playback

I'm attempting to implement a simple, lightweight system for recording Qt GUI events and playing them back from a script. I thought this would be fairly straightforward using the magic of Qt's event system, but I'm running into a problem I don't understand.
Here's quick summary of what I'm doing:
RECORDING:
I use QApplication.instance().eventFilter() to capture all GUI events I'm interested in* and save them to a Python script, in which each step looks something like this:
obj = get_named_object('MainWindow.my_menubar')
recorded_event = QMouseEvent(2, PyQt4.QtCore.QPoint(45, 8), 1, Qt.MouseButtons(0x1), Qt.KeyboardModifiers(0x0))
post_event(obj, recorded_event)
PLAYBACK:
I simply execute the script above, in a worker (non-GUI) thread. (I can't use the GUI thread because I want to keep sending scripted events to the application, even if the 'main' eventloop is blocked while a modal dialog eventloop is running.)
The important stuff happens in my post_event() function, which needs to do two things:
First, call QApplication.postEvent(obj, recorded_event)
Wait for all events to finish processing:**
Post a special event to the same eventloop that obj is running in.
When the special event is handled:
Call QApplication.processEvents()
Set a flag that tells the playback thread it's okay to continue
After the second part is complete, my expectation is that all effects of the first part (the recorded event) have completed, since the special event was queued after the recorded event.
The whole system mostly seems to work just fine for mouse events, key events, etc. But I'm having a problem with QAction handlers when I attempt to playback events for my main QMenuBar.
No matter what I try, it seems that I can't force my playback thread to block for the completion of all QAction.triggered handlers that result from clicking on my QMenu items. As far as I can tell, QApplication.processEvents() is returning before the QAction handler is complete.
Is there something special about QMenu widgets or QAction signals that breaks the normal rules for QApplication.postEvent() and/or QApplication.processEvents()? I need a way to block for the completion of my QMenu's QAction handlers.
[*] Not every event is recorded. I only record spontaneous() events, and I also filter out a few other types (e.g. Paint events and ordinary mouse movements).
[**] This is important because the next event in the script might refer to a widget that was created by the previous event.
I think your problem might best be served by using QFuture and QFutureWatcher (that is, if you're using the QtConcurrent namespace for threads, and not QThreads). Basically, the Qt Event handling system does NOT necessarily handle events in the order they're posted. If you need to block until a certain action is completed, and you're doing that action in a separate thread, you can use the QFuture object returned by QtConcurrent::run() with a QFutureWatcher to block until that particular thread finishes its processing.
Something else to consider is the way you handle events. When you use QApplication.postEvent(), the event you create gets added to the receiver's event queue to be handled later. Behind the scenes, Qt can reorder and compress these events to save processor time. I suspect this is more your problem.
In your function which handles playback, consider using QCoreApplication::processEvents(), which will not return until all events have finished processing. Documentation for QCoreApplication is here.
QMenu widgets and QAction signals are a special case. QMenu has an exec() function, normally used for popups. I suspect (but I don't know for sure) that QMenuBar would use this mechanism when it opens a regular pull-down menu. The docs are not clear about this, but Menus act a lot like dialog boxes in that they block all other user activity - how would Qt do this except by giving menus their own event loop? I can't fill in all the blanks from the information in your post, but I don't see how your playback thread would cope with a new event loop.

Sending action to Ember.StateManager : is goToState mandatory?

In the documentation of Ember.StateManager it's said that : "Inside of an action method the given state should delegate goToState calls on its StateManager". Does it mean that if I send an action message, I necessarily need to transit to another state. Is it possible to stay in the same state but doing some task by sending an action ? For example, I'm in a state "loading" and I run two actions "preprocess" and "display".
Very simply: an action message may but does not have to transition to another state.
Something you didn't ask, but is related and important: it is a bad idea and bad design to call goToState in an enter or exit method.
When dealing with statecharts in general, you can do whatever you want. It's not mandatory to switch states in an event handler. A common case would be an event handler that shows a cancel/save dialog. You can easily put the dialog on the page in the event handler, and proceed accordingly depending on which button is pressed.
A separate question is should every event handler basically just go to another state. In the above scenario, you can certainly go to a "confirm" state, the state-enter method will show the dialog, and there would be two handlers, one for each button. Those handler would in turn go to other states.
Both design choices I think are equally valid, at least in that scenario. If you choose to implement a separate state for every action, you will end up with a lot of small but concise states. If you choose to do stuff in the event handlers themselves, your states will be bigger, but there will be less of them.
One thing I will say is if an event handler is getting complicated, you are probably better of with a new state. Also, be consistent.
For you specific scenario, if I'm reading it right, you want to load data and then change the display to show the data, based on an event. In this case, I would use new states.
So you press a button that starts the process
In the event handler, go to some sort of 'MyDataSection' state
Initial substate is 'loadData'
Enter state method of 'loadData' starts the loading process
Event handler 'dataLoaded' in 'loadData' to handle when the data loads; this means you need to fire an event when the data loads
'dataLoaded' event goes to the 'show' state
show state shows the view (or removes activity indicator etc) and handles any events that come from the display.
What's good here is that if you have multiple ways to get to this section of the app, all actions that lead to this section only need to go to this state, and everything will always happen the same. Also note that since the view event handlers are on the show state, if the user hits a button while the data is loading, nothing will happen.

Distinguish between single and double click events in Qt

I have a QAbstractItemView that needs to react to single and double click events. The actions are different depending on whether it was single clicked or double clicked. The problem that is occurring is that the single click event is received prior to the double click event.
Is there a recommended way/best practice for distinguishing between the two? I don't want to perform the single click action when the user has actually double clicked.
I am using Qt 4.6
It's a good UI design to make sure your single-clicks and double-clicks are conceptually related:
Single-Click: select icon
Double-Click: select icon and open it
Single-Click: select color
Double-Click: select color and open palette editor
Notice how in these examples the single-click action is actually a subset of the double-click. This means you can go ahead and do your single-click action normally and just do the additional action if the double-click comes in.
If your user interface does something like:
Single-Click: select icon
Double-Click: close window
Then you are setting your users up to fail. Even if they remember what single-clicking does versus double-clicking all the time, it's very easy to accidentally move your mouse too far while double-clicking or wait too long.
Edit:
I'm sorry to hear that.
In that case, I found these two articles useful:
Logical consequences of the way
Windows converts single-clicks into
double-clicks
Implementing
higher-order clicks
You can find answer in the thread titled Double Click Capturing on QtCentre forum;
You could have a timer. Start the
timer in the releaseEvent handler and
make sure the timeout is long enough
to handle the double click first.
Then, in the double click event
handler you can stop the timer and
prevent it from firing. If a double
click handler is not triggered, the
timer will timeout and call a slot of
your choice, where you can handle the
single click. This is of course a
nasty hack, but has a chance to work.
wysota
Using PySide which is the Python binding of Qt 4.8 I saw that single clicks deliver a QEvent.MouseButtonPress event and double clicks deliver a single QEvent.MouseButtonPress event closely followed by a QEvent.MouseButtonDblClick. The delay is approximately about 100ms on Windows. That means you still have a problem if you need to differentiate between single and double clicks.
The solution needs another QTimer with a slightly higher delay than the inbuilt delay (adding some overhead). If you observe a QEvent.MouseButtonPress event you start your own timer, in case of timeout it is a single click. In case of a QEvent.MouseButtonDblClick it is a double click and you stop the timer to avoid counting as single click.