python – How do I get mouse position relative to my dragging component in QML QT?

In my app I have a shape in left hand side like a menu on which the user can drag the shape to the main area. you can click a part of the shape and then a line attached to the shape to the mouse position will appear.

My problem is that this line has always an offset difference with mouse position and that’s because I can get only the absolute position of the mouse and not relative to the shape so I could adjust the position well.

enter image description here

here’s my code

this is addtion.qml



import QtQuick.Shapes 2.15
import QtQuick 2.15
import QtQml 2.15



Item {

    id: root
//    property alias color: shape.color






        Item{

            id: addition
            width: 40
            height: 40
//            Drag.active: addition.drag.active



            Component.onCompleted: {

                var globalPos = addition.mapToItem(addition.parent, 0, 0);

            }



            onXChanged: {

                var globalPos = addition.mapToItem(addition.parent, 0, 0);
                absolutePosX(globalPos);
            }
            onYChanged: {

                var globalPos = addition.mapToItem(addition.parent, 0, 0);
                absolutePosY(globalPos);
            }







            MouseArea{
                id: dragMe
                anchors.fill: parent



                drag {
                    target: parent
                    axis: Drag.XandYAxis
                }






                onPressed: {
                    root.z = 10;

                }

                onReleased: {

                    root.z = 2;

                }
                }


            Shape {
                id: shape
                width: 50
                height: 50
                anchors.centerIn: parent




                Text {
                    id: hello
                    text: qsTr("text")
                    x: -30

                    MouseArea{
                        id: shapeText;
                        anchors.fill: parent;
                        onClicked: {hello.text = qsTr("text2");
                        console.log("Clicked");}



                    }



                }



                ShapePath {

                    strokeColor: "black"
                    strokeWidth: 4
                    fillColor: "transparent"
                    startX: 0; startY: 0
                    PathLine { x: 40; y: 0 }
                    PathLine { x: 40; y: 40 }
                    PathLine { x: 0; y: 40 }
                    PathLine { x: 0; y: 0 }
                    PathLine { x: 20; y: 0 }
                    PathLine { x: 20; y: 40 }
                    PathLine { x: 0; y: 40 }
                    PathLine { x: 0; y: 20 }
                    PathLine { x: 40; y: 20 }
                    PathLine { x: 50; y: 20 }



                }






            Rectangle{

                id: link
                x: 50
                y: 15
                width: 20
                height: 10
                color: 'blue'


                Component.onCompleted: {


                }














                MouseArea{

                    anchors.fill: parent
                    hoverEnabled: true
                    onEntered: { parent.color="yellow";
                    hello.text = qsTr("text3");}
                    onExited:  { parent.color="blue"
                    hello.text = qsTr("text2");}






                    onClicked: {



                        var component = Qt.createComponent("wire.qml");
                        if (component.status === Component.Ready){
                            var newObject = component.createObject(addition, {x:  (link.x + 2 * link.width) , y: link.y, });

                            console.log(Math.round(mouse.x ) + ',' + Math.round(mouse.y));
//                            newObject.x = 50;
//                            newObject.y = 50;
                            drag.target = newObject;

//                            created(mouse);





                        }

                        }


            }





            }







wire.qml


import QtQuick.Shapes 2.15
import QtQuick 2.15
import QtQml 2.15


Item {



    Shape {
        id: wire
        width: 50
        height: 2
        anchors.centerIn: parent

        property int endposX: 0
        property int endposY: 0
        property int recX: 0
        property int recY: 0



        Component.onCompleted: {
            mousePosX.connect(x_handler);
            mousePosY.connect(y_handler);
            absolutePosX.connect(updatePosX);
            absolutePosY.connect(updatePosY);
        }


        function updatePosX(x1) {

            wire.recX  = x1;
            console.log(wire.recX+ '<<<<<<<x<<<<<<<<<' +  wire.recX  + '>>>>>>>>>>>>>>');


        }


        function updatePosY(y1) {

            wire.recY = y1;
            console.log(wire.recY + '<<<<<<<<y<<<<<<<<' +  wire.recY  + '>>>>>>>>>>>>>>');


        }
        function x_handler(x) {

            console.log('x' + Math.round(x));
            console.log('x' + Math.round(wire.endposX));
            wire.endposX = x;

//            wire.endposX = ;

        }


        function y_handler(y) {

            console.log('y' + Math.round(y));
            console.log('y' + Math.round(wire.endposY));
            wire.endposY = y;
//            wire.endposY =;


        }




        ShapePath {

            strokeColor: "black"
            strokeWidth: 4
            fillColor: "transparent"
            startX: 0; startY: 0

            PathLine { x: wire.endposX - wire.recX -330; y: wire.endposY- wire.recX - 240}
//            PathLine { x: wire.endposX - wire.recX; y:  wire.endposY - wire.recY}





        }
    }

}




main.qml



import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import QtQuick.Shapes 2.15
import QtQuick.Layouts 2.15
import QtQml 2.15

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


    signal created(var position)
    signal mousePosX(var x)
    signal mousePosY(var y)

    signal absolutePosX(var x1)
    signal absolutePosY(var y1)




    function updatePos (item_orig, item_dest) {
        var pos_abs = root.mapFromItem (item_orig.parent, item_orig.x, item_orig.y);


        return root.mapToItem (item_dest.parent, pos_abs.x, pos_abs.y);
    }





    Rectangle {
        id: main
        anchors.fill: parent
        x: 220
        y: 140
        width: 700
        height: 700
        color: "#c3afaf"

        Component.onCompleted: {

        }






        MouseArea {

            id: mouseMain;
            anchors.fill: parent;
            hoverEnabled: true

            onMouseXChanged: { mousePosX(mouseMain.mouseX);}
            onMouseYChanged: { mousePosY(mouseMain.mouseY);}

            onClicked: { }

        }


    }


Rectangle{
    id: sideMenu
    color: "grey"
    width: 50
    anchors.left: parent.left
    anchors.top: parent.top
    anchors.bottom: parent.bottom




    ColumnLayout{

            spacing: 10
            width: 50


            My_Thing{
                property var myNewObject
                Layout.alignment: Qt.AlignCenter
                Layout.preferredWidth: 40
                Layout.preferredHeight: 40
                id: thing
                color: 'red'
                width: 100
                height: 100
                z: 2



                MouseArea{
                    id:mouseArea_myThing
                    anchors.fill:thing

                    onPressed: {

                        var component = Qt.createComponent("rectangleCopy.qml");
                        if (component.status === Component.Ready)
                            var newObject = component.createObject(root, {x: mouseX, y: mouseY, });


                        newObject.x = parent.x;
                        newObject.y = parent.y;
                        newObject.text="Type1" ;
                        newObject.color="red" ;

                        drag.target = newObject;

                        thing.myNewObject = newObject;

                    }
                    onReleased: {

                        thing.myNewObject.z = 100
                        console.log('hi');
                    }

                }

                   }






            Rectangle {
                    property var myNewObject
                    Layout.alignment: Qt.AlignCenter
                    Layout.preferredWidth: 40
                    Layout.preferredHeight: 40
                    id: rec
                    width: 50
                    height: 50
                    color: "yellow"
                    border.color: "yellow"
                    border.width: 0
                    z: 2

    //                DragHandler {
    //                    id: rec_handler
    //                    target: rec
    //                }


                    MouseArea{
                        anchors.fill:rec
                        onPressed: {

                            var component = Qt.createComponent("rectangleCopy.qml");
                            if (component.status === Component.Ready)
                                var newObject = component.createObject(root, {x: mouseX, y: mouseY, });

                            newObject.x = parent.x;
                            newObject.y = parent.y;

                            drag.target = newObject;
                            newObject.text="Type2" ;
                            newObject.color="yellow" ;
                            rec.myNewObject = newObject

                        }
                        onReleased: {
                           console.log('hi');
                           rec.myNewObject.z = 2;


                        }

                    }

                       }



            Rectangle {
                    property var myNewObject
                    Layout.alignment: Qt.AlignCenter
                    Layout.preferredWidth: 40
                    Layout.preferredHeight: 40
                    id: circle
                    width: 50
                    height: width
                    color: "blue"
                    border.color: "blue"
                    border.width: 0
                    radius: width*0.5
                    z: 2


    //                DragHandler {
    //                    id: circle_handler
    //                    target: circle

    //                }




                    MouseArea{
                        anchors.fill: circle

                        onPressed: {

                            var component = Qt.createComponent("circleCopy.qml");
                            if (component.status === Component.Ready)
                                var newObject = component.createObject(root, {x: mouseX, y: mouseY, });

                            newObject.x = parent.x;
                            newObject.y = parent.y;

                            drag.target = newObject;
                            newObject.text="Type3" ;

                            circle.myNewObject = newObject;


                        }
                        onReleased: {
                            console.log('hi');

                           circle.myNewObject.z = 2;

                        }


                    }

                          }





            Addition {
                    property var myNewObject
                    Layout.alignment: Qt.AlignCenter
                    Layout.preferredWidth: 40
                    Layout.preferredHeight: 40
                    id: addition
                    width: 40
                    height: 40
                    z: 2


    //                DragHandler {
    //                    id: circle_handler
    //                    target: circle

    //                }




//                    DropArea {

//                    anchors.fill: main

//                    onDropped: {





//                    }


//                    }

                    MouseArea{
                        id: add_mouseArea
                        anchors.fill: parent

                        onPressed: {

                            var component = Qt.createComponent("Addition.qml");
                            if (component.status === Component.Ready)
                                var newObject = component.createObject(root, {x: add_mouseArea.mouseX, y: add_mouseArea.mouseY, });

                            newObject.x = parent.x;
                            newObject.y = parent.y;

                            drag.target = newObject;



                            addition.myNewObject = newObject;


                        }
                        onReleased: {
                            console.log('hi');

                           addition.myNewObject.z = 2;

                        }


                    }

                          }





}


            }















}



rectangleCopy.qml



import QtQuick 2.15
import QtQml 2.15


Item {

    id: root
    property alias text: txt.text
    property alias color: me.color


    QtObject {
        id: internalSettings
        property color color: "green"
    }








        Rectangle {
                    color: 'yellow'
                    width: 40
                    height: 40
                    id: me
                    Drag.active: dragMe.drag.active

                    Text {
                        id: txt
                        text: qsTr("text")
                        anchors.centerIn: parent
                    }

                    MouseArea{
                        id: dragMe
                        anchors.fill: me
                        drag.target: me


                        onPressed: {

                            root.z = 10;

                        }

                        onReleased: {

                            root.z = 2;

                        }


                    }

                  }

}

MyThing.qml

import QtQuick 2.15

Item {
    property alias color: rectangle.color
    width: 50; height: 50

    Rectangle
    {
        id: rectangle
        anchors.fill: parent
    }
}


circleCopy.qml


import QtQuick 2.15
import QtQml 2.15


Item {
    id: root
    property alias text: txt.text



    QtObject {
        id: internalSettings
        property color color: "green"
    }








    Rectangle {
            id: me2
            width: 50
            height: width
            color: "blue"
            border.color: "blue"
            border.width: 0
            radius: width*0.5

            Text {
                id: txt
                text: qsTr("text")
                anchors.centerIn: parent
            }


                    MouseArea{
                        id: dragMe
                        anchors.fill: me2
                        drag.target: me2

                        onPressed: {

                            root.z = 10;

                        }

                        onReleased: {

                            root.z = 2;

                        }



                    }

                  }

}



main.py


# This Python file uses the following encoding: utf-8
import os
from pathlib import Path
import sys

from PySide6.QtGui import QGuiApplication
from PySide6.QtQml import QQmlApplicationEngine


if __name__ == "__main__":
    app = QGuiApplication(sys.argv)
    engine = QQmlApplicationEngine()
    engine.load(os.fspath(Path(__file__).resolve().parent / "main.qml"))
    if not engine.rootObjects():
        sys.exit(-1)
    sys.exit(app.exec())


I’ve stumbled across some clues like using mapToItem, mapFromItem, mapToGlobal, mapFromGlobal and such but the documentation was not clear for me as to how these would work. I’m a beginner in qml so forgive me for the spaghetti code. If I left some explanation tell me to give you more details. any help would be appreciated thanks

Leave a Comment