Qt how to set global mouseReleaseEvent when i have pile of widgets - c++

is there away to set global mouseReleaseEvent?
what i mean is i have QMainWindow and on it QFrame and init QListView and In it
i have Widgets that constarct the QListView and inside the widget i have al sort of lables and text fields.
so i want to detect mouseRelease any where in my app i have to implement in all widgets the mouseReleaseEvent?
void ItemWidget::mouseReleaseEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
{
;
}
event->accept();
}

According to the QMouseEvent documentation, the widget that receives the mouse press will also get the mouse release. So, you shouldn't have to look any further for your mouse release than the widget that received the original press. This is usually referred to as a mouse "grab."
You may also want to check that Qt::WA_NoMousePropagation is not set on one of your children. If it is set, it will ensure that your mouse event does not bubble up.
If you really want to catch all mouse release events, you could try installing an event filter on the QApplication itself. That is a bit of a heavy solution, but you should get every mouse release event.

Looking at the (somewhat older) documentation here indicates that events are by default ignored by a widget and are propagated to their parents. So, if you make all your widgets children of your main application widget (or 'grandchildren', etc.) then you should only need to install the event handler on the application widget.

Related

Qt: Ignore MouseButtonRelease events when widget is hidden

The Documentation for QWidget says this:
mouseReleaseEvent() is called when a mouse button is released. A
widget receives mouse release events when it has received the
corresponding mouse press event. This means that if the user presses
the mouse inside your widget, then drags the mouse somewhere else
before releasing the mouse button, your widget receives the release
event. There is one exception: if a popup menu appears while the mouse
button is held down, this popup immediately steals the mouse events.
It also says this:
If you create new widgets in the mousePressEvent() the
mouseReleaseEvent() may not end up where you expect, depending on the
underlying window system (or X11 window manager), the widgets'
location and maybe more
In my programme, the is a context where the user can change the current visible widget by pressing Enter. If they click and hold on a toolbar button and press enter while the mouse is still pressed, they can send the mouse release event to the now hidden widget. This is a problem as the actions in the toolbar of the now hidden page, relate to a state which has been deinitialised when the active widget was changed.
The desired behaviour would be for the changing of active widget to somehow 'cancel' or 'release' the old widget's claim to the coming mouse release event even though it (or one of its children) received the corresponding mouse press event, and for the action in the toolbar not to be triggered.
Is there any way to do this? Or does anyone have any guidance on what I might be looking for?
Thanks
One options is by creating eventFilter function (either in widget itself (if your own) or parent widget), installing it with installEventFilter and then checking for mouse release event type and only accept the event if widget's isVisible() returns true.
Another option (in case you have your own Qt based widget class) is to override mouseReleaseEvent and do the same visibility check in there.

How to enable mouse tracking on a QWindow

I'm using a QWindow (Not a QMainWindow) with OpenGL. I need to use a QWindow to correctly control the OGL context.
I'm trying to follow the Scribble example to implement something similar to panning, but I can't find a paradigmatic way to trigger the mouseMoveEvent().
How can I get a "tooltip" effect where mouseMoveEvent() is constantly triggered, similar to setMouseTracking()?
It works fine for me. I created a test program with a MainWindow that inherits QWindow instead of QMainWindow, and handles the mouse move event to print the cursor position:
void MainWindow::mouseMoveEvent(QMouseEvent *e)
{
qDebug("%d, %d", e->pos().x(), e->pos().y());
}
It works, as I move the mouse I get events even without pressing any mouse buttons.
If mouse tracking is disabled (the default), the widget only receives mouse move events when at least one mouse button is pressed while the mouse is being moved.
you can call hasMouseTracking() or setMouseTracking() to control mouse's tracing state.
When mouse is traced, mouseMoveEvent() will be called, and you can reimpletment mouseMoveEven() to acquire mouse position, just as #sashoalm did.
BTW, mouse event is always transfered to your app, but filtered by it's parent or itself. You can reimpletment eventFilter() to code your own filter.

How to stop a paint event from propagating?

I have two widgets, A and B, A has B as its parent.
Inside the A widget, I have a timer to trigger the repaint slot of itself. Thus, the paintEvent of widget A is triggered. However, I found B's paintEvent is also triggered. How could I trigger only A's paintevet?
I have tried to accept A's paintEvent as:
void A::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
paintA();
event->accept();
}
But it doesn't help. What should I do?
When a widget is sent a paint event, so are all of its enabled children. You can work around this by installing an event filter on the child widget and discarding any paint events you don't want.
You can't because Qt must do composition of the widgets.
Options:
Consider making the widget a non-child and display it as a separate "window". You can use Qt::FramelessWindowHint and Qt::WA_TranslucentBackground to make it look as a child widget. This option will give you perfect results as it leaves the composition to the underlying OS, which, at least on Desktop, will not repaint the bottom widget unless requested.
Consider caching. Use QPixmapCache to cache all drawing of your bottom widget to one window-sized pixmap, which will be very fast to draw when needed.

Change QWidget Parent During Mouse Event

I'm trying to create a detachable type style widget, like in the way Chrome tabs are detachable (class is called Tab). I have everything working, except for a bug where sometimes (maybe 50% of the time), the Tab object never gets the mouse release event, and stops getting mouse move events.
Essentially, the detaching system works by allowing drags in the mouse press/move/release functions, just like normal. The mouseMoveEvent checks the total distance moved from the start, and if over a certain amount, will start the "detaching" process. The detaching process involves setting the parent widget to 0 (top level widget, undecorated window), so the Tab object is pretty much floating above everything, under the mouse, and continues to be dragged along with it until released.
I ran through all the QEvent items being delivered, and I found that when this issue occurs, the QEvent::MouseMove items (and all mouse events after this) are being sent to the TabBar (the Tab object's original parent). This occurs directly after calling setParent(0) on the Tab.
Basic mouse handling overview:
void Tab::mousePressEvent(*) {
[set up some boolean, start positions, etc]
}
void Tab::mouseMoveEvent(*) {
[track the updated position]
if (positionChange > STATIC_AMOUNT)
detachTab();
}
void Tab::mouseReleaseEvent(*) {
[return the Tab to its original position, and set the parent back to the TabBar]
}
void Tab::detachTab() {
QPoint mappedPos = mapToGlobal(0, 0);
setParent(0); //The loss of MouseMove events occurs when this returns.
move(mappedPos);
show();
raise();
}
Here are the events that the Tab object receives (first row is QEvent type, second is the name)
[Tab::detachTab() started]
[setParent(0) started]
QEvent::Hide
QEvent::Leave
qApp QEvent::MouseMove [ TabBar ] <-- now the TabBar is soaking up the mouse events
QEvent::HideToParent
QEvent::ParentAboutToChange
QEvent::ParentChange
[setParent(0) returned]
....
Summed up: my draggable QWidget loses QEvent::MouseMove and QEvent::MouseButtonRelease events after having its parent set to 0.
Any advice would be really appreciated!
A bit tricky workaround. I didn't test it, it's just an idea.
When your mouse hovers draggable part of a widget you may create topmost widget (let's call it Shade) with Qt::FramelessWindowHint (and possible with Qt::WA_TranslucentBackground). You may manipulate with Shade apperance via reimplementing paintEvent. For example - draw content of original widget, or draw some transparent preview, etc.
Then you may resize a Shade during dragging, to show user that widget will be detached. You will not loose mouse capture.
When user release mouse - you remember position of Shade, destroy it and detach+move original widget.
Feel free to ask, if you want more details.
Here is similar question.
So you suppose to use QDocWidget and enforce stacking of this widgets using tabifyDockWidget.

Tracking mouse cursor in QWidget

I am using the mouseMoveEvent to track the position of the mouse cursor in a simple QT app. My problem is that I want the mouseMoveEvent to fire only when the cursor is in a 400x400 QWidget. Right now it is firing no matter where the mouse is. Here is my code...
void IPA2::mouseMoveEvent(QMouseEvent * event) {
cout << event->x() << endl;
cout << event->y() << endl;
}
IPA2 is the name of my class. The ui was created in designer mode.
If I understand you correctly, you may just perform a check here like if (x,y in range) do_something.
Another way would be to create a fake widget with 400x400 dimensions and reimplement it's mouse event.
The third (probably an overkill) is to use event filters (see here).
Update:
You can't just "easily" handle the mouse events using the Qt Designer. Each .ui scheme is almost always paired up with the corresponding implementation for that scheme. This is where your handling should be done.
Qt Designer is great for automatic signal-slot handling, but mouseMoveEvent is an event and has nothing to do with the slot system.
I would say how would I implement this and you can choose (see the three possible ways before).
I would create some DummyWidget, which would have a 400x400 dimensions and custom virtual mouseMoveEvent method, which would actually handle the mouse movement.
In the constructor of my main window (which also does the .ui-based construction) I would say something like
dummy_widget_ = new DummyWidget(...);
// `dummy_widget_` is a private `DummyWidget*` member of the main window
and then probably would reposition it somewhere.
That's it - now when my main window is created, a dummy widget is added to it and every mouse movement at that widget is handled (because we've provided custom implementation).
Another moment, which is related to mouse events only: http://doc.qt.nokia.com/4.7/qwidget.html#mouseTracking-prop