[Interest] Track global mouse position in QML

Jérôme Godbout godboutj at amotus.ca
Mon Mar 25 14:42:47 CET 2019


@Jerome, I think the singleton approach would work, but it feels like reversing responsibilities, which would lead to some weird patterns down the road.
// MySingleton.qml
pragma Singleton

QObject
{
   property int mousePosX: 0
   property int mousePosY: 0
}

// Main.qml
Window
{
    MouseArea
    {
        id: mouseOver_
        /* fill as below for mouseArea properties */
        Binding
        {
            target: MySingleton
            property: mousePosX
            value: mouseOver_.mouseX
        }
        Binding
        {
            target: MySingleton
            property: mousePosY
            value: mouseOver_.mouseY
        }
    }
}

// Other component that want to known mouse is hover area
Item
{
    visible: MySingleton.mousePosX < 100 && MySingleton.mousePosY < 100
}

The singleton is only there to avoid carrying the mouse area everywhere. It make a single point of connection for other components (consumers) to know and the mousearea (provider) is binding itself to it. I would restrain the C++ for this, the mouse behavior is pure GUI behavior and in my mind belong to Qml (Qml for Gui and interaction behavior, more UX where C++ is for algo, model, type declaration and controller with business logic). That may differ since the line is blur sometime.

From: Interest <interest-bounces at qt-project.org> On Behalf Of Jérôme Godbout
Sent: March 22, 2019 2:18 PM
To: René Hansen <renehh at gmail.com>
Cc: interest <interest at qt-project.org>
Subject: Re: [Interest] Track global mouse position in QML

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5

Window {
  visible: true
  width: 640
  height: 480
  title: qsTr("Hello World")

  TextField {
    anchors.centerIn: parent
    width: 0.7 * parent.width
  }

  Rectangle {
    width: 30
    height: 30
    anchors.left: parent.left
    anchors.leftMargin: 20
    anchors.top: parent.top
    anchors.topMargin: 20
    color: "blue"

    visible: ma.mouseX < 100 && ma.mouseY < 100
  }

  MouseArea
  {
    id: ma
    z: 1
    anchors.fill: parent
    hoverEnabled: true
    preventStealing: true
    propagateComposedEvents: true
    acceptedButtons: Qt.NoButton
    onClicked: mouse.accepted = false;
    onDoubleClicked: mouse.accepted = false;
    onPressed: mouse.accepted = false;
    onWheel: wheel.accepted = false;
  }
}

This should work for you I guess, TextField is now working.

From: René Hansen <renehh at gmail.com<mailto:renehh at gmail.com>>
Sent: March 22, 2019 5:24 AM
To: Jérôme Godbout <godboutj at amotus.ca<mailto:godboutj at amotus.ca>>
Cc: Jason H <jhihn at gmx.com<mailto:jhihn at gmx.com>>; interest <interest at qt-project.org<mailto:interest at qt-project.org>>
Subject: Re: [Interest] Track global mouse position in QML

Imagine this example:

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5

Window {
  visible: true
  width: 640
  height: 480
  title: qsTr("Hello World")

  TextField {
    anchors.centerIn: parent
    width: 0.7 * parent.width
  }

  Rectangle {
    width: 30
    height: 30
    anchors.left: parent.left
    anchors.leftMargin: 20
    anchors.top: parent.top
    anchors.topMargin: 20
    color: "blue"

    visible: ma.mouseX < 100 && ma.mouseY < 100
  }

  MouseArea {
    id: ma
    anchors.fill: parent
    hoverEnabled: true
  }
}

So here's the idea. I want the blue rectangle in the upper left corner, to only appear given some condition based on the X, Y position of the mouse within the window. Now overlaying the MouseArea enables me to track the cursor position at all times. The catch is then, that the TextField is now broken. You cannot click it to give it focus and the cursor doesn't change when you hover over it, to indicate text input is available.

If I change the ordering and underlay the MouseArea instead, then the TextField works, but now I loose X, Y tracking, as soon as I'm hovering over the TextField. I've tried all of:

hoverEnabled: true
preventStealing: true
propagateComposedEvents: true
acceptedButtons: Qt.NoButton

As well as:

mouse.accepted = false;

But it doesn't seem to work as expected.

@Jerome, I think the singleton approach would work, but it feels like reversing responsibilities, which would lead to some weird patterns down the road.
@Jason, A dispatch is probably fine for clicks, since they're only run sporadically. Hover I think is a different thing, and I'd rather keep the logic triggered to a bare minimum, since it'll be running pretty much constantly.

/René

On Thu, 21 Mar 2019 at 15:35 Jérôme Godbout <godboutj at amotus.ca<mailto:godboutj at amotus.ca>> wrote:
Not sure I get what you are trying to achieve, but having a mouse area where the coordinate are local you can map them to global or to an item. If the mouse area should not grab the mouse event, make sure to add those to your mouse area

hoverEnabled: true
preventStealing: true
propagateComposedEvents: true
acceptedButtons: Qt.NoButton

Also do not accept the events if not processing it or the event will be stopped (do this for all event that can be accepted):

onClicked:
{
   mouse.accepted = false;
}

This should make your overlay mouse area nearly transparent. This way the mouseArea overlay known the “global position” and can act upon it and the actual behavior under it can process the click like normal.

You can use a single mouse area that overlay the whole items tree (MouseArea into Root Item fill) and change the global coordinate into a Qml Singleton. Any part of the application could connect to the coordinate and check if the global to whatever item you need match and act according to it.


[36E56279]
une compagnie  [cid:image002.jpg at 01D4DFD1.D847A580]
RAPPROCHEZ LA DISTANCE

Jérôme Godbout
Développeur Logiciel Sénior /
Senior Software Developer

p: +1 (418) 800-1073<tel:(418)%20800-1073> ext.:109

amotus.ca<http://www.amotus-solutions.com/>
statum-iot.com<http://statum-iot.com/>
[cid:image003.png at 01D4DFD1.D847A580]<https://www.facebook.com/LesSolutionsAmotus/> [cid:image004.png at 01D4DFD1.D847A580] <https://www.linkedin.com/company/amotus-solutions/>  [cid:image005.png at 01D4DFD1.D847A580] <https://twitter.com/AmotusSolutions>  [cid:image006.jpg at 01D4DFD1.D847A580] <https://www.youtube.com/channel/UCoYpQgsmj1iJZyDjTQ3x8Ig>





From: Interest <interest-bounces at qt-project.org<mailto:interest-bounces at qt-project.org>> On Behalf Of Jason H
Sent: March 21, 2019 10:11 AM
To: "René Hansen" <renehh at gmail.com<mailto:renehh at gmail.com>>
Cc: interest <interest at qt-project.org<mailto:interest at qt-project.org>>
Subject: Re: [Interest] Track global mouse position in QML

Please forgive me if I don't completely understand...

Maybe you want an underlying mouse area, not an overlaynig one? I'd suggest you just move the MouseArea in the file.
You can always use an overlaying one and translate the mouse events to the child, if there is one. This is what I do for a sample drawing app I have:

In TouchTestRect.qml:



function dispatchTouchEvent(x,y) {

var c = childAt(x,y);

var typename =  "" + c;

var box;

if (c && (typename.startsWith("QQuickRow") || typename.startsWith("QQuickColumn"))) {

        var point = mapToItem(c, x, y);

        box = c.childAt(point.x, point.y);

        typename =  "" + box;

} else if(typename.startsWith("TouchHitBox_QMLTYPE")) {
....

}
...
}

then:
MouseArea {
anchors.fill: parent
onMouseXChanged: {
touchTestRect.dispatchTouchEvent(mouseX, mouseY)
}
onMouseYChanged: {
touchTestRect.dispatchTouchEvent(mouseX, mouseY)
}
}
Sent: Thursday, March 21, 2019 at 7:50 AM
From: "René Hansen" <renehh at gmail.com<mailto:renehh at gmail.com>>
To: interest <interest at qt-project.org<mailto:interest at qt-project.org>>
Subject: [Interest] Track global mouse position in QML
Hi all,


I want to track mouse movement within my entire application window, because I need to show/hide/move items around where my cursor is at certain times. (Think e.g. custom cursor)

I can do it easily by filling the entire window with a MouseArea and handle onPositionChanged. The problem is that any mouse sensitive inputs underneath, then get's blocked by the overlaying MouseArea. E.g. a TextField that is usually highlighted on hover and clickable, no longer receives any mouse events.

Is there any straightforward solution to this?

I know QQuickWindow has a mouseMoveEvent, but that doesn't seem to be exposed in QML and if I can avoid subclassing and exposing a custom class, I'd rather do that.


Cheers,

René Hansen
_______________________________________________ Interest mailing list Interest at qt-project.org<mailto:Interest at qt-project.org> https://lists.qt-project.org/listinfo/interest
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/interest/attachments/20190325/dc29595d/attachment.html>


More information about the Interest mailing list