1
votes

I have a qml element and want to show a (own) tooltip element as a new window right above this element. for this i need the absolute screen position to place the new window (AFAIK).

i got as far that the regular approach is to use "mapToItem" to get the relative position, but i cannot get to the "main window" - because the element in question is located within a "Loader" (which in this case is again located in another Loader).

So my question is: Is it possible to access the mainWindow from inside the dynamically loaded component, or is there maybe another easier way to anchor a new (tooltip) window right above an element ?

EDIT

mapToGlobal would probably work too, but i have to use qt 5.6. i finally got it to work by setting the main window as a context property in c++:

this->qmlEngine->rootContext()->setContextProperty("mainWindow", this->root);

and in qml i can then access the main window position (on screen) and add the relative position the item has to the shown window like that:

tooltipWindow.setX(mainWindow.x +item1.mapToItem(item2,0,0).x )
1
Do you have some code to play with? I think the main problem is, that Window does not inherit from Item so there should be no mapToItem or mapFromItem-Method available.derM
Do you really intend to use a new Window for this tooltip, or rather a new Item within a common Window?derM
And do you intend to have it as a child of the mainWindow or as a sibling?derM
According to the documentation, if you pass "null" as the item to mapToItem then the coordinates get mapped to the "view", in your case that should be the window.Kevin Krammer
You can use Item::mapToGlobal() introduced in Qt 5.7 / QtQuick 2.7: doc-snapshots.qt.io/qt5-5.7/…jpnurmi

1 Answers

0
votes

The Window item has contentItem especially for that

[read-only] contentItem : Item

The invisible root item of the scene.

So you can refer to Window.contentItem as if it was Window:

import QtQuick 2.7
import QtQuick.Window 2.2

Window {
    id: mainWindow
    visible: true
    width: 600
    height: 300

    Component {
        id: testElement
        Rectangle {
            id: rect
            width: 100
            height: 100
            color: "orange"
            border { width: 1; color: "#999" }
            MouseArea {
                anchors.fill: parent
                hoverEnabled: true
                onEntered: tooltip.show(true);
                onExited: tooltip.show(false);
                onPositionChanged: tooltip.setPosition(mapToItem(mainWindow.contentItem,mouse.x, mouse.y));
            }
        }
    }

    Item {
        x: 40
        y: 50
        Item {
            x: 80
            y: 60
            Loader {
                sourceComponent: testElement
            }
        }
    }

    Rectangle {
        id: tooltip
        visible: false
        width: 100
        height: 20
        color: "lightgreen"
        border { width: 1; color: "#999" }
        Text {
            anchors.centerIn: parent
            text: "I'm here"
        }
        function show(isShow) {
            tooltip.visible = isShow;
        }
        function setPosition(point) {
            tooltip.x = point.x - tooltip.width / 2;
            tooltip.y = point.y - tooltip.height;
        }
    }
}

As for me I would reparent tooltip Item to hovered item itself at MouseArea.onEntered and so you can avoid position recalculation etc.:

onEntered: tooltip.show(true, rect);
onExited: tooltip.show(false);
onPositionChanged: tooltip.setPosition(mouse.x, mouse.y);

...

function show(isShow, obj) {
    obj = (typeof obj !== 'undefined' ? obj : null);
    if(obj !== null) {
        tooltip.parent = obj;
    }
    tooltip.visible = isShow;
}

function setPosition(x, y) {
    tooltip.x = x - tooltip.width / 2;
    tooltip.y = y - tooltip.height;
}