如何将动态创建的 qmlcomponent 对象绑定到另一个动态创建的 qmlcomponent 对象的属性?
Posted
技术标签:
【中文标题】如何将动态创建的 qmlcomponent 对象绑定到另一个动态创建的 qmlcomponent 对象的属性?【英文标题】:How do I bind a dynamically created qmlcomponent object to the property of another dynamic created qmlcomponent object? 【发布时间】:2018-07-26 18:30:12 【问题描述】:我在一个模块中有两个 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_())
但现在我想将边 E 的第一个点连接到 Class 组件 A 和边 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 文件中创建两个 id 为 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 的绑定?
【问题讨论】:
Edge.qml 和 Class.qml 是什么? 用“property Class anchor1”你正在创建一个变量来存储一个“Class”类型的对象,所以anchor2.Some_property会抛出一个错误,请提供一个像样的minimal reproducible example 我编辑了我的答案。 Edge.qml 是 StraightLine 类的包装器。 Class.qml 只是一个 qml 组件。带文字。 2 类组件应该连接到一个边缘。 【参考方案1】:解决方法是将属性anchor1
和anchor2
的数据类型建立为var
。
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))
另一方面,我没有包含 QtQuick.Controls 1.4
导入来识别 main.qml 中的 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你会找到完整的代码
【讨论】:
以上是关于如何将动态创建的 qmlcomponent 对象绑定到另一个动态创建的 qmlcomponent 对象的属性?的主要内容,如果未能解决你的问题,请参考以下文章