首页 文章

在QML a la Pd或Max(也称为“修补”界面)中动态连接图形的节点

提问于
浏览
0

我试图模仿QML中的patcher接口,其中用户可以单击节点并以下面显示的方式将其连接到另一个节点:

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

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

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

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 回答

  • 1

    我会在 C++ 中将其作为一个实体项目,"field" . 我的意思是在这个项目中绘制所有节点和"patches",实现 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
        }
    }
    

相关问题