Search code examples
c++qtuser-interfaceselectiontextselection

Releasing and locking mouse events between multiple widgets


Straight to the point

I have multiple QLabel widgets inside QVBoxLayout.

When I press left mouse button and start dragging (I don't actually drag any widgets, I only move the mouse cursor while left mouse button is being pressed), one of the QLabels receives the mousePressEvent, and all subsequent mouseMoveEvents are sent to that QLabel which received the mousePressEvent, even when the mouse cursor has moved outside of the bounding box of this QLabel.

This does not work for me. I want the original QLabel which first received the mousePressEvent to stop receiving mouse events if the event occurred outside of the QLabel's bounding box. If it happens, I want the other QLabel (to where the cursor has moved) to start handling the mouse events.

Setting mouse tracking to true did not help, "locking" still happens.

Any suggestions? Thanks <3


Some background

What I am actually implementing is text selection mechanism for my document viewer application.

Pixmaps are obtained from pages of a document and set as QLabels' pixmaps. When a mousePressEvent occurs selection starts and continues on the following onMouseMove events. But when I want to select text from multiple pages and I move the mouse cursor to another QLabel, events are still being sent to that original QLabel. This is the issue. I have perfectly functioning selection mechanism for a single page. The issue arose just now when I realized that mouse events work this way in Qt.


UPD

I've recorded a short 1 minute video describing the problem - https://youtu.be/m00dV4s1Am8


Solution

  • I've achieved what I needed by following steps:

    • Widget (QLabel with pdf page in my case) receives a mousePressEvent and handles subsequent mouseMoveEvents
    • It accepts a mouseMoveEvent only in case if it occurred inside the bounding box of the widget.
    • If it occurred outside of widget's bounding box, it ignores it and the event is being sent to the parent widget, which holds the rest of the widgets (PagesContainer in my case is the parent, it hold all the QLabels with pdf pages).
    • The parent widget then resolves relative coordinates by using mapFromGlobal to get coordinates relative to the his coordinate system.
    • Then it tries to find a widget in its layout at specified coordinates by using childAt.
    • If a widget was found, it creates a new mouseMoveEvent with all parameters copied from the original mouseMoveEvent except the coordinates - they are being converted one more time, but to the found widget's coordinate system this time, and posts this event.

    Here is the video demonstrating the solution: https://youtu.be/zHebZRYnF5Y?si=1zKBQs7JuEd2sjpp

    Note: All mouseMoveEvents which occur outside of the very first (which captured the mousePressEvent) widget's bounding box will still be forwarded through it's mouseMoveEvent handler. And every time it will ignore it, and every time the parent will have to do its job. What I don't like is that on every such event it will have to go through multiple widgets' event handlers, as well as the need to create a new event and post it to the found widget. This solution is not ideal, but it does it's job well.