在QML a la Pd或Max中动态连接图形的节点(又称"修补"接口)

时间:2016-08-25 05:16:13

标签: javascript c++ qt qml

我正在尝试模仿QML中的patcher接口,其中用户可以单击节点并按照此处显示的方式将其连接到另一个节点:

https://youtu.be/rtgGol-I4gA?t=4m15s

最终在QML中连接这些节点将在相应的C ++图中设置指针。创建一个QML节点实例化一个C ++等价物,到目前为止一直很好。但是对于该死的补丁本身,我无法找到一个聪明的解决方案。

我试图制作一个补丁"在第一次单击时实例化的类,然后使用拖放连接到第二个。它提供了一个起点和终点,以便画布可以绘制补丁(线)。初始端点本身,一旦点击第二个节点就会被修改......

import QtQuick 2.7

Item {

id: root
height: 30
width: 30

property Canvas myCanvas
property var start
property var end

Component.onCompleted: {
    end = root
}

onXChanged: myCanvas.requestPaint()
onYChanged: myCanvas.requestPaint()

Rectangle {
    id: rect
    color: "blue"
    anchors.fill: root

    MouseArea {
        id: mouseArea

        anchors.fill: rect
        Drag.active: true
        drag.target: root
        drag.axis: Drag.XAndYAxis
        drag.minimumX: 0
        drag.minimumY: 0

        onReleased: mouseArea.Drag.drop()
    }

}
} 

但是在创建时设置拖动不起作用,它仍然需要鼠标释放和另一次单击/拖动。 (我也不能让这一点下降,但一次只能解决一个问题......)

我对正确的方法表达了一些意见。

1 个答案:

答案 0 :(得分:1)

我会在C++中将其作为一个固定项,一个"字段"。我的意思是绘制所有节点和"补丁"在此项目中,实施QQuickItemQQuickPaintedItem。因此,您可以根据需要重新实现所有鼠标事件。您也可以使用Canvas完成所有工作,例如:

import QtQuick 2.7
import QtQuick.Window 2.0
impor

Window
{
    id: mainWindow
    width: 800
    height: 800
    x: (Screen.width - width) / 2
    y: (Screen.height - height) / 2
    visible: true

    Canvas {
        id: canvas
        property var objects: []
        property var connections: []
        property int objectSize: 50
        property int objectCount: 30
        property point startPoint: Qt.point(0,0)
        property point endPoint: Qt.point(0,0)
        anchors.fill: parent
        focus: true
        Component.onCompleted: {
            fillField();
        }

        function fillField() {
            for(var i = 0;i < canvas.objectCount;i ++) {
                do {
                    var x = canvas.objectSize + Math.round(Math.random() * (mainWindow.width - canvas.objectSize * 2));
                    var y = canvas.objectSize + Math.round(Math.random() * (mainWindow.height - canvas.objectSize * 2));
                    if(checkCoord(x, y) === true) {
                        objects.push(Qt.point(x,y));
                        break;
                    }
                } while(true);
            }
            canvas.requestPaint();
        }

        function checkCoord(_x, _y) {
            for(var i = 0;i < objects.length;i ++) {
                if(Math.abs(objects[i].x - _x) < canvas.objectSize &&
                        Math.abs(objects[i].y - _y) < canvas.objectSize) {
                    return objects[i];
                }
            }
            return true;
        }

        onPaint: {
            var ctx = getContext("2d");
            ctx.beginPath();
            ctx.fillStyle = Qt.rgba(1,1,1,1);
            ctx.fillRect(0,0,width,height);
            ctx.fillStyle = Qt.rgba(1, 0, 0, 1);
            ctx.strokeStyle = Qt.rgba(0.8, 0.8, 0.8, 1);
            ctx.lineWidth = 3;
            ctx.lineCap = "round";
            ctx.lineJoin = "round";
            for(var i = 0;i < objects.length;i ++) {
                ctx.ellipse(objects[i].x - canvas.objectSize/2,objects[i].y - canvas.objectSize/2,canvas.objectSize,canvas.objectSize);
            }
            if(startPoint.x !== 0 && startPoint.y !== 0) {
                ctx.moveTo(startPoint.x, startPoint.y);
                ctx.lineTo(endPoint.x, endPoint.y);
            }
            ctx.fill();
            ctx.stroke();
            ctx.beginPath();
            ctx.strokeStyle = Qt.rgba(0, 0, 1, 1);
            ctx.lineWidth = 5;
            for(var i = 0;i < connections.length;i ++) {
                ctx.moveTo(connections[i].start.x, connections[i].start.y);
                ctx.lineTo(connections[i].end.x, connections[i].end.y);
            }
            ctx.stroke();
            ctx.beginPath();
            ctx.fillStyle = Qt.rgba(1,1,0,1);
            for(var i = 0;i < connections.length;i ++) {
                ctx.ellipse(connections[i].start.x - 5, connections[i].start.y - 5, 10, 10);
                ctx.ellipse(connections[i].end.x - 5, connections[i].end.y - 5, 10, 10);
            }
            ctx.fill();
        }

        MouseArea {
            anchors.fill: parent
            onPressed: {
                var point = canvas.checkCoord(mouse.x, mouse.y);
                if(point !== true) {
                    canvas.startPoint = point;
                }
                else
                    canvas.startPoint = Qt.point(0,0);
            }
            onReleased: {
                if(canvas.startPoint.x === 0 && canvas.startPoint.y === 0)
                    return;
                var point = canvas.checkCoord(mouse.x, mouse.y);
                if(point === true)
                    canvas.startPoint = Qt.point(0,0);
                else {
                    if(point.x !== canvas.startPoint.x || point.y !== canvas.startPoint.y) {
                        canvas.connections.push({
                                                    start: Qt.point(canvas.startPoint.x,canvas.startPoint.y),
                                                    end: Qt.point(point.x, point.y)
                                                });
                    }
                    canvas.startPoint = Qt.point(0,0);
                }
                canvas.requestPaint();
            }
            onPositionChanged: {
                if(canvas.startPoint.x !== 0 && canvas.startPoint.y !== 0){
                    canvas.endPoint = Qt.point(mouse.x, mouse.y);
                    canvas.requestPaint();
                }
            }
        }

        Keys.onPressed: {
            switch(event.key)
            {
            case Qt.Key_Escape:
                canvas.objects = [];
                canvas.connections = [];
                canvas.startPoint = Qt.point(0,0);
                canvas.endPoint = Qt.point(0,0);
                canvas.fillField();
                break;
            case Qt.Key_Backspace:
                canvas.connections.pop();
                canvas.requestPaint();
            }
        }
    }

    Text {
        text: " Esc - rearange, Backspace - undo ";
    }

    Text {
        text: "Draw your own constellation"
        font.bold: true
        font.capitalization: Font.AllUppercase
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.top: parent.top
    }
}