Trying to make a very simple node editor in Qt Quick.
The most tricky part seems to be the Connection
item, which has to track the two absolute positions of the source and destination IOPort
s.
The following code works fine, except that the bindings are not evaluated (or are evaluated in the wrong order) at startup, resulting in the connection line to be in the wrong position at startup:
which is then adjusted to the correct position as soon as either node is moved:
I thought about adding:
Component.onCompleted: {
start = mapFromItem(from, 0, 0)
end = mapFromItem(to, 0, 0)
}
to Connection
, which fixes the startup problem, but breaks the bindings.
So I resorted to this ugly hack:
Component.onCompleted: {
from.x = from.x+1
from.x = from.x-1
}
Is there a better solution to this problem?
(files available in GitHub repository, link at bottom)
main.qml:
import QtQuick 2.15
import QtQuick.Window 2.15
Window {
width: 420
height: 280
visible: true
title: qsTr("Node editor")
Node {
x: 20
y: 40
width: 120
height: 50
IOPort {id: o1; x: 0; y: parent.height}
}
Node {
x: 260
y: 140
width: 120
height: 50
IOPort {id: i1; x: 0; y: 0}
}
Connection {
from: o1; to: i1
}
}
Node.qml:
import QtQuick 2.0
Rectangle {
id: rect
border.color: "black"
border.width: 2
color: "#eee"
MouseArea {
anchors.fill: parent
drag.target: rect
}
}
IOPort.qml:
import QtQuick 2.0
Item {
id: root
property real size: 15
property real globalX: x + parent.x
property real globalY: y + parent.y
property real globalZ: 1 + parent.z
Rectangle {
id: rect
x: -width/2
y: -height/2
width: root.size
height: root.size
border.color: "black"
color: "gray"
}
}
Connection.qml:
import QtQuick 2.0
import QtQuick.Shapes 1.15
Shape {
id: root
property IOPort from
property IOPort to
x: Math.min(from.globalX, to.globalX)
y: Math.min(from.globalY, to.globalY)
z: Math.max(from.globalZ, to.globalZ) + 0.5
width: Math.abs(from.globalX - to.globalX)
height: Math.abs(from.globalY - to.globalY)
property point start: from.globalX, from.globalY, to.globalX, to.globalY, mapFromItem(from, 0, 0)
property point end: from.globalX, from.globalY, to.globalX, to.globalY, mapFromItem(to, 0, 0)
ShapePath {
strokeWidth: 4
strokeColor: "black"
startX: root.start.x
startY: root.start.y
PathLine {
x: root.end.x
y: root.end.y
}
}
}
GitHub repository: https://github.com/fferri/qtquick-simple-node-editor.git
I cannot currently reproduce the error but I think I found a problem:
Your Connection
root
's start
and end
properties are missing a "forced" dependency on that same object's x
and y
For some reason you decided to not only to set the coordinates for path's points but also move the whole Connection
element itself. So if root
's x
and y
happen to update after start
and end
did, the latter still contain relative coordinates of the point when x
and y
were still default (probably 0,0
) and thus the line becomes displaced by x,y
pixels.
Try changing them this way (I also removed dependencies you shouldn't need):
property point start: from.globalX, from.globalY, x, y, mapFromItem(from, 0, 0)
property point end: x, y, to.globalX, to.globalY, mapFromItem(to, 0, 0)
(There were more suggestions here in case this didn't work but they were removed because the above seems to have solved the issue)