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.
Related
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.
I want to create a behavior in which when I finished editing a text, the focus either moves to the next child or clear the focus on the current field when I pressed "Enter". I would then get one signal to trigger a part of the code.
When I do editingFinished() and reimplement keyReleaseEvent() for "Enter" with focusNextChild() or clearFocus(), I get two signals for the text edit, one when the "Enter" is pressed, and one when the focus is change via focusNextChild() or clearFocus(). The extra signal is undesirable.
If I do returnPressed() and reimplement keyReleaseEvent() for "Enter" with focusNextChild() or clearFocus(), it would only create one signal, but I also want the signal to be created when the user exits the lineEdit via tab() or mouse click on any other line items, which would not be the case if I use returnPressed()
Ideally, I could use a signal when a lineEdit loses focus, its connected to a slot that runs the code and I can reimplement the keyReleaseEvent() for "Enter" to set the focus, but it doesn't seem like such a signal exists in Qt.
Does anyone have recommendations on how to implement this or a better way to approach it?
You can connect/disconnect signals when you want. For example, when you focus in the QLineEdit you can connect both listed signals to slot which will disconnect those two connections and move focus to the next child. Thus, you will have only one signal processed.
Another solution - you can call QLineEdit.blockSignals(true) in the beginning of the slot and call QLineEdit.blockSignals(false) in the end of the slot. In this case whatever you do in the slot you will not trigger any signal in QLineEdit and no duplicates will arise.
Problem
Windows has a system setting that will cause the mouse pointer to jump (move) to a new focus element automatically, e.g. the default button of a dialog that pops up. While the advantage is an increase in speed and a reduction of mouse movements, it has a disadvantage:
If this happens just when before the user clicks on another element, the user is unable to abort his/her action in time and will immediately accept the dialogs default button because the focus is moved by the system. Usually this may entail cumbersome work to retrace the steps up to this point (think a file chooser dialog that forgot the very long path you input previously) but it could also mean triggering an irreversible process (e.g. file deletion).
Aim
Essentially I would like to disable the dialog's inputs for a small amount of time, just enough to prevent an inadvertant mouse click or keyboard button press.
Question
It comes down to a C++ question, namely how to access the base classes' objects (GUI widgets) from the inheriting class, i.e.
disable the button widgets of a QMessageBox
start a single shot QTimer and connect it to a slot that
enables the previously disabled widgets
(As alternative, I probably could reimplement input event handlers that suppress all input for a specific amount of time, but although I intend to keep that time very short (e.g. 100 ms), the user is not informed of the disabled input using that method.)
A simple class derived from QDialogBox can be found at http://www.qtforum.org/article/24342/messagebox-auto-close-mouse-event-close.html.
Do you need to use one of the "native"-ish message boxes provided by the QMessageBox static functions?
Otherwise, that's pretty simple to achieve, by building a QMessageBox and adding standard buttons to it:
QMessageBox *messageBox = new QMessageBox;
QPushButton *okButton = messageBox->addButton(QMessageBox::Ok);
okButton->setEnabled(false);
// use a QTimer to add logic to reenable the button
// use QCursor to move the mouse cursor on the button
// add a nice countdown in the button's label, like Firefox does
// add other nice UX touches as wanted
Last points are left as an exercise to the reader :)
To en/disable the buttons in QMessagebox one would need access to them.
qmessagebox.cpp uses buttonBox = new QDialogButtonBox; and the addButton() method
d->buttonBox->addButton(button, (QDialogButtonBox::ButtonRole)role);
d->customButtonList.append(button);
But I don't understand Qt internals and am unable to find these in qmessagebox.h and thus fail to find out if there is a chance to access the buttons..
I have implemented a widget which has a grid (QTableView object) and two scollbars, one horizontal and one vertical. I have implemented a function that fetches the data to be shown in the grid from a database. I want when the user pressed the arrow from the scroll bar in order to make a single step the application instntly fetch the data. On the contrary when the user scrolls with the whell or move the slider the app don’t fetch the data instantly. More specifically i want the data to be fetched when the user stops the slider for some time or releases the slider. For this reason i have used sliderReleased() signal. Moreover, i have write, as a user from this forum suggested, this code for the vertical scrolling actions.
void handleVTableScrollAction(int action)
{
switch(action)
{
case QAbstractSlider::SliderSingleStepAdd:
case QAbstractSlider::SliderSingleStepSub:
drawGrid();
requestSlot();
break;
case QAbstractSlider::SliderMove:
drawGrid();
m_Timer.start(500);
}
the timer is connected to a slot the fetches the data
connect (&m_Timer, SIGNAL(timeout()), this, SLOT (requestSlot()));
So my problem is when i wnt to make a single step (by pressing the arrow key) the app don’t responds instantly. When i press the arrow for the firtst time nothing seems to be done, but when i am pressing second time the grid follows the movement. All the other movements(wheel and slider move) work fine.
So i tried to use the valueChange() signal just like this:
connect(ui->verticalScrollBar, SIGNAL(valueChanged(int)), this, SLOT(sliderSigleStep()));
connect(ui->verticalScrollBar, SIGNAL(sliderMoved(int)), this, SLOT(sliderMoveSlot()));
In this way the single step works fine, but the sliderMoveSlost is never called as the valueChanged singal is always emmited first.
Is there an explantion for my first issue?
Can i call a function with the condition that two signals emmited? For example call the sliderMoveSlot only if sliderMove(int) and valueChanged(int) singals emmited and call sliderSingleStep() if only valueChanged(int) is emmited.
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.