如何将动态创建的qmlcomponent对象绑定到另一个动态创建的qmlcomponent对象的属性?

时间:2018-07-26 18:30:13

标签: python qt pyqt qml pyqt5

我在一个模块中有两个qml组件。

components
  |- Edge.qml
  |- Class.qml
  |- qmdir
main
  |- main.qml
main.py

带有 main.qml

import urmelgraph.components 1.0

import CustomGeometry 1.0

ApplicationWindow {
    visible: true
    width: 640
    height: 240
    title: qsTr("Test")
    color: "#2C3E50"
}

qmdir

module urmelgraph.components
Class 1.0 Class.qml
Edge 1.0 Edge.qml

我正在将这两个文件都加载到我的python main.py 文件中。

from PyQt5.QtGui import QGuiApplication, QColor, QSurfaceFormat
from PyQt5.QtQml import QQmlApplicationEngine, QQmlComponent, QQmlContext, qmlRegisterType, QQmlProperty
from PyQt5.QtQuick import QQuickItem, QQuickView, QSGGeometryNode, QSGGeometry, QSGNode, QSGFlatColorMaterial
from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot, pyqtProperty, QUrl, QPointF, QSizeF

from  pathlib import Path

class StraightLine(QQuickItem):
    p1_Changed = pyqtSignal()
    p2_Changed = pyqtSignal()
    segment_count_Changed = pyqtSignal()

    def __init__(self, parent: QQuickItem, p1: QPointF = QPointF(0,0), p2: QPointF = QPointF(1,1), segment_count: int = 2):
        super().__init__(parent)
        self._p1 = p1
        self._p2 = p2
        self._segment_count = segment_count
        self.setFlag(QQuickItem.ItemHasContents, True)

    @pyqtProperty("QPointF", notify = p1_Changed)
    def p1(self):
        return self._p1

    @p1.setter
    def p1(self, p1: QPointF):
        if p1 == self._p1:
            return

        self._p1 = p1
        self.p1_Changed.emit()
        self.update()

    @pyqtProperty("QPointF", notify = p2_Changed)
    def p2(self):
        return self._p2

    @p2.setter
    def p2(self, p2: QPointF):
        if p2 == self._p2:
            return

        self._p2 = p2
        self.p2_Changed.emit()
        self.update()

    @pyqtProperty(int, notify = segment_count_Changed)
    def segment_count(self):
        return self._segment_count

    @segment_count.setter
    def segment_count(self, count: int):
        if count == self._segment_count:
            return

        self._segment_count = count
        self.segment_count_Changed.emit()
        self.update()

    def updatePaintNode(self, oldNode: QSGGeometryNode, _):
        if oldNode == None:
            node = QSGGeometryNode()
            geometry = QSGGeometry(QSGGeometry.defaultAttributes_Point2D(), self._segment_count)
            geometry.setLineWidth(3)
            geometry.setDrawingMode(QSGGeometry.DrawLineStrip)
            node.setGeometry(geometry)
            node.setFlag(QSGNode.OwnsGeometry)

            material = QSGFlatColorMaterial()
            material.setColor(QColor(45, 100, 120))
            node.setMaterial(material)
            node.setFlag(QSGNode.OwnsMaterial)
        else:
            node = oldNode
            geometry = node.geometry()
            geometry.allocate(self._segment_count)

        itemSize = self.size()
        vertices = geometry.vertexDataAsPoint2D()

        x1 = self._p1.x()
        y1 = self._p1.y()
        vertices[0].set(x1, y1)

        x2 = self._p2.x()
        y2 = self._p2.y()
        vertices[1].set(x2, y2)

        print(vertices[1].x)

        node.markDirty(QSGNode.DirtyGeometry)

        return node

if __name__ == "__main__":
    import sys

    path = Path("..")
    resolved_path = path.resolve()

    # Create an instance of the application
    app = QGuiApplication(sys.argv)

    # Set antialising 4 samples
    format = QSurfaceFormat()
    format.setSamples(4)
    QSurfaceFormat.setDefaultFormat(format)

    # register custom types
    qmlRegisterType(StraightLine, "CustomGeometry", 1, 0, "StraightLine")

    # Create QML engine
    engine = QQmlApplicationEngine()

    # Load the qml file into the engine
    engine.addImportPath(str(resolved_path))
    engine.load("main/main.qml")

    # load the components
    component = QQmlComponent(engine)
    component.loadUrl(QUrl("components/Class.qml"))
    line_component = QQmlComponent(engine)
    line_component.loadUrl(QUrl("components/Edge.qml"))
    # check for component creation errors
    for error in component.errors():
        print(error.toString())
    # check for component creation errors
    for error in line_component.errors():
        print(error.toString())

    classes = []
    for index, class_name in enumerate(["Person", "Home"]):
        # create a new instance of the component
        cclass = component.create()
        # set the class name property of the component
        cclass.setProperty("className", class_name)
        cclass.setX((cclass.width() + 50) * index)
        cclass.setParentItem(engine.rootObjects()[0].findChild(QQuickItem))
        classes.append(cclass)

    line = line_component.beginCreate(engine.rootContext())
    line.setProperty("anchor1", classes[0])
    line.setProperty("anchor2", classes[1])
    line_component.completeCreate()

    # check for object creation errors
    for error in line_component.errors():
        print(error.toString())
    for error in component.errors():
        print(error.toString())

    engine.quit.connect(app.quit)
    sys.exit(app.exec_())

但是现在我想将Edge E 的第一点连接到Class组件 A 以及Edge E 的第二点到一个类组件 B

为此,我在 Edge.qml 中创建了属性。

import QtQuick 2.11
import CustomGeometry 1.0
import urmelgraph.components 1.0

StraightLine {
    property Class anchor1
    property Class anchor2

    anchors.fill: parent

    Component.onCompleted: {
        console.log(anchor1)
        console.log(anchor2)
    }

    p2: Qt.point(anchor2.x + (anchor2.width/2), anchor2.y + (anchor2.height/2))
    p1: Qt.point(anchor1.x + (anchor1.width/2), anchor1.y + (anchor1.height/2))
}

这是我的 Class.qml

import QtQuick 2.11
import QtQuick.Layouts 1.11

Rectangle {
    width: 50
    height: 20
    color: "#2980B9"

    border.color: "#ECF0F1"

    property string className

    Drag.active: dragArea.drag.active

    MouseArea {
        id: dragArea
        anchors.fill: parent

        drag.target: parent
        // disable delay when moved
        drag.threshold: 0
    }
    Text {
        text: className
    }
}

在我的 main.py 中,我有一个classes列表,其中包含所有生成的Class组件,但尝试通过Edge将第一类与第二类连接(行),例如,不起作用:

line = line_component.beginCreate(engine.rootContext())
line.setProperty("anchor1", classes[0])
line.setProperty("anchor2", classes[1])
line_component.completeCreate()

但是,如果我在 main.qml 文件中创建了两个分别为rect1和rect2的矩形。使用QQuickItem StraightLine,此代码有效:

StraightLine {
    anchors.fill: parent

    p1: Qt.point(rect2.x + (rect2.width/2), rect2.y + (rect2.height/2))
    p2: Qt.point(rect1.x + (rect1.width/2), rect1.y + (rect1.height/2))
}

Rectangle {
    id: rect1
    width: 10
    height: 10
    color: "red"
    radius: width*0.5

    Drag.active: dragArea.drag.active

    MouseArea {
        id: dragArea
        anchors.fill: parent

        drag.target: parent
        // disable delay when moved
        drag.threshold: 0
    }
}

Rectangle {
    id: rect2
    width: 10
    height: 10
    color: "blue"
    radius: width*0.5

    Drag.active: dragArea2.drag.active

    MouseArea {
        id: dragArea2
        anchors.fill: parent

        drag.target: parent
        // disable delay when moved
        drag.threshold: 0
    }
}

如何将引用从这些class组件传递到我的edge组件,以正确设置x,y,width,height的绑定?

1 个答案:

答案 0 :(得分:0)

解决方案是建立属性anchor1anchor2var的数据类型。

Edge.qml

import QtQuick 2.11
import CustomGeometry 1.0

StraightLine {
    property var anchor1
    property var anchor2

    anchors.fill: parent

    Component.onCompleted: {
        console.log(anchor1)
        console.log(anchor2)
    }

    p2: Qt.point(anchor2.x + (anchor2.width/2), anchor2.y + (anchor2.height/2))
    p1: Qt.point(anchor1.x + (anchor1.width/2), anchor1.y + (anchor1.height/2))
}

另一方面,我没有在main.qml中包括QtQuick.Controls 1.4导入以识别ApplicationWindow:

import QtQuick.Controls 1.4

import urmelgraph.components 1.0

import CustomGeometry 1.0

ApplicationWindow {
    visible: true
    width: 640
    height: 240
    title: qsTr("Test")
    color: "#2C3E50"
}

在下面的link中,您将找到完整的代码