Letting another widget handle your events in Qt - qt

I have a QSpinBox in a QMainWindow holding a value. Natively the spinbox, well ... spins on QWheelEvent if focused. I would like to expand the scrolling of the value in the spinbox to be applied invariantly of focus within the window.
The spinbox manages a value that dictates behavior to the whole context of the window live.
I am trying to divert the scroll event to the spinbox to be handled by the latter to implement this instead of handling a custom value somewhere and to synchronize it with the spinbox manually.
But I am failing. I have an EventFilter in the window that can intercept the event in the window invariantly of focus, but the wheelEvent method in the spinbox is protected so I cannot call it from there.
I do not want to just make a custom spinbox for this if I can help it.
Any ideas?

In the event filter, do not call the protected spinBox->wheelEvent(wheelEvent). You can instead pass the event to the spin box using static function QCoreApplication::sendEvent(spinBox, wheelEvent).
Of course, seeing your code would help to show more concrete solution. Especially you should make sure that your event filter does not intercept this re-sent event again, creating an infinite loop...

Related

Difference between hide, close and show in qt

What is the difference between hide,close and show of pushbutton or any widget in terms of memory?
Which is better if I don't want to use widget again?
First as said #Hayt, read the documentation.
For the actual answer:
hide() is the same as setVisible(false).
show() is the same as setVisible(true).
close() attempts to close the widget by triggering a QCloseEvent, if the event is accepted the result is:
The same as calling hide() if Qt::WA_DeleteOnClose attribute is not set on the widget which is the default.
The same as calling deleteLater() if Qt::WA_DeleteOnClose is set.
In term of memory, any of the 3 will not change anything (except for close() if you have set Qt::WA_DeleteOnClose). If you do not want to use the widget ever, the best is to delete it:
delete pointerToMyWidget;
or
pointerToMyWidget->deleteLater();
The second form is generally safer as the 1st one can be dangerous depending on where your write it. (e.g you delete it in a slot called by a signal emitted by the widget you delete).
According to Qt, you can read this :
CLOSE :
Closes this widget. Returns true if the widget was closed; otherwise
returns false.
First it sends the widget a QCloseEvent. The widget is hidden if it
accepts the close event. If it ignores the event, nothing happens. The
default implementation of QWidget::closeEvent() accepts the close
event.
If the widget has the Qt::WA_DeleteOnClose flag, the widget is also
deleted. A close events is delivered to the widget no matter if the
widget is visible or not.
The QApplication::lastWindowClosed() signal is emitted when the last
visible primary window (i.e. window with no parent) with the
Qt::WA_QuitOnClose attribute set is closed. By default this attribute
is set for all widgets except transient windows such as splash
screens, tool windows, and popup menus.
.
HIDE : Hides the widget. This function is equivalent to
setVisible(false).
Note: If you are working with QDialog or its subclasses and you invoke
the show() function after this function, the dialog will be displayed
in its original position.
.
SHOW : Shows the widget and its child widgets. This function is
equivalent to setVisible(true).
If you don't need to use your widget, call close(). You can manage the event to destroy your widget.
hide() only hides. It's only graphical, you can't see your widget but you don't destroy it.
But I think that the name fo the function are enough explicit to understand!

Slider reacting on mouse wheel in entire application

By default QSlider reacts on mouse wheel only when cursor is on it. I want to control slider by mouse wheel not matter where the cursor is (of course only when my application has focus).
What's the best way to achieve that?
I just learned that mouse doesn't generate signals. So looks like I need to override wheelEvent in main window and use raise or lower method in it. But I guess that can cause double increment (or decrement) of slider value when mouse is hovering it.
So once again: What's the best way to achieve what I described?
You can override the wheelEvent() in your MainWindow and redirect it to your slider control, that is indeed one option.
Another option is to install an event filter on the qApp instance. This even filter then can check whether the event type is QEvent::Wheel, and when the receiver is not the slider, then again redirect it to the slider. Should work just as well.

How to catch all and only button release events in Qt?

My team is developing an UI for an apparatus with touch screen and we would like it to emit a sound (from a buzzer) each time the user correctly presses a button (so using the release event). Notice that I don't want to play the sound after each click on the interface, but only when the click is over a button.
We use many types of button, sometimes QPushButton and most of the times customized buttons derived from QAbstractButton. In most cases these buttons get an objectName.
So I supposed in order to do that, I would have to catch the MouseButtonRelease event and since I'm already working with a subclass of QApplication to handle excetions, I decided to do this in the notify function.
I tried, then, some methods to recognized when the MouseButtonRelease was related to a button but none of them were successfull. The best one, verifying the receiver's objectName was still not good enought not only because not all buttons had an objectName (which, of course, can be handled), but specially because not always the event was caught for buttons with names set. In other words, sometimes I would click in a button and it recognizes the event and sometimes I would click in the same button and the event is not recognized.
I did some research and another method I found was to set an event filter in the MainWindow, but not all widgets have the MainWindow as their parent which means I would have to Ctrl+c / Ctrl+V the same code time after time when I obviously want something more localized (i.e. in only one spot).
So why it happens that the notify not always handles the events? And how could I do this? Any suggestions are appreciated specially one that is less heavier then handling the events globally.
As info, the other two ways I tried to catch the events with similar or even worst results inside notify were with receiver->inherits("...") and qobject_cast< QAbstractButton* >(receiver).

QTableView: Best way to change activation-trigger to double-click

In my application, I have one tableview of items, and a side-panel "preview":ing the latest selected item.
I want clicking on an item to change the selection, and double-clicking to cause a "run"-action to be performed. More specifically, I want the "run"-action (including key-navigation and pressing enter) to be bound to the "activation" of the item in the table-row.
My problem is; single-clicks does not only change the selection, but fires the "activated" signal on the item. I would like to tweak it such that:
Navigation Keys, Single Mouse Click: Selection-change, update preview-panel
Enter Key, Double Mouse Click: Activate/run/open action triggered.
Is there a nice clean way to do it, or are overriding the onclick/doubleclick events my best option? Or is there some other tabular list-widget better suiting my needs?
I would connect the slot for the preview action to the currentChanged() signal of the table view's selectionModel(). This covers single clicks and key navigation.
Then there's two options for the double clicks and Enter key presses:
Subclass your tableview, override doubleClickEvent() and keyPressEvent() and fire your custom signal in there, with maybe the model index or something else as an argument. Then just connect your run method to your own signal as you have full control over when it is fired.
If you don't want to subclass, you can use the installEventFilter() mechanism.
Either I'm getting your approach wrong or I'm too tired, but if you want to trigger a run event you should avoid the activated signal completely. Set the signal slot mechanism so that your double click and Enter key press event trigger your run() function, and then the single click/nav buttons should trigger the 'activated' slot which will return your index in the tableview.
I'm pretty certain Qt wants you to be explicit about which signal points to which slot or it'll ignore it or point to a default.

How to force calling of QWidget::paintEvent() when its hovered by other window?

I have a problem:
I'm creating a widget which displays current date's day number. It's like a button, but it's not derived from QPushButton class. Just from QWidget. So I've reimplemented enterEvent(), leaveEvent(), mousePressEvent(), mouseReleaseEvent(). I do call update() inside these methods and widget has realistic button behavior (paintEvent() is reimplemented also).
But when I change system date and hover that widget with other window, my widget doesn't get paintEvent() and the old date is displayed. Only when I place mouse over it, widget repaints it's contents.
I guess there is a feature (like buffering) which paints old contents on hovering with other window to avoid unnecessary recalculations. But I need to disable it. Tried to set many attributes (the Qt::WidgetAttribute enum). But it doesn't work.
I think you should find a way to detect that the system time has changed and call update() when that happens. Any other method (like detecting the "hovering" of a window or waiting for a mouse event) will cause the update to occur too late.

Resources