I have a Qml component that is reasonably large so that I want to make it a reusable component but it is too small/non-generic such that I want to avoid creating its own .qml file. It seems like Components are the right method to define reusable objects in the same file, but when I do that I don't know how to access and change properties of the contained objects.
More specifically, imagine having an in-file definition like this
Component {
id: myReusableComponent
// This cannot be set because component does not allow properties
// (Would work fine in a separate file myReusableComponent.qml)
// property alias string innerText: innerText.text
Rectangle {
id: rect
width: 200
height: 200
color: "red"
Text {
id: innerText
text: "Want to set text later"
}
}
How can I reuse this component later, while changing some properties of it? I know the following is not valid syntax, but I want to use it similarly to this:
Loader {
id: hello
sourceComponent: myReusableComponent
item.innerText: "Hello" }
Text { text: "Some other stuff in between" }
Loader {
id: world
sourceComponent: myReusableComponent
item.anchors.left: hello.right
item.rect.width: 100
item.rect.color: "blue"
item.innerText: "World" }
Loader {
id: excl
sourceComponent: myReusableComponent
item.rect.color: "green"
item.innerText: "!!!" }
etc...
Any ideas? Or is there a fundamentally different way of doing this?
What I essentially want is reusability of QML objects that are defined in place while still being able to change the properties of them.
This seems to be related but does not solve the problem of creating multiple objects. Repeaters seem to be useful but don't give me the flexibility I want.
NOTE: I will add some remarks about the answers here since they might get overlooked in the comments. I like all three answers from Blabbouze, derM and ddriver! I accepted Blabbouze's answer because it provides a concrete solution that is closest to what I was looking for. However, I also didn't know about the overhead of Loaders and might consider using a different approach after reading derM's answer. Finally, dynamic object creation as suggested by ddriver is not exactly what I was looking for but might be useful for others. Thanks everyone!
This can be used to execute script code at startup, once the full QML environment has been established. The onCompleted signal handler can be declared on any object. The order of running the handlers is undefined. Rectangle { Component. onCompleted: console.
QML is the language; its JavaScript runtime is the custom V4 engine, since Qt 5.2; and Qt Quick is the 2D scene graph and the UI framework based on it. These are all part of the Qt Declarative module, while the technology is no longer called Qt Declarative.
The Qt QML module provides a framework for developing applications and libraries with the QML language. It defines and implements the language and engine infrastructure, and provides an API to enable application developers to extend the QML language with custom types and integrate QML code with JavaScript and C++.
A component provides a way of defining a new type that we can re-use in other QML files. A QML component is like a black-box and interacts with the outside world through properties, signals and functions and is generally defined in its own QML file. (For more details, see the Component documentation).
I think you are looking for onLoaded()
signal. It is emitted when the Loader
have successfully created the Component
.
You can then access your loaded type properties with item
.
import QtQuick 2.7
import QtQuick.Controls 2.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Component {
id: myReusableComponent
Rectangle {
id: rect
property alias innerText: innerText.text
width: 200
height: 200
color: "red"
Text {
id: innerText
text: "Want to set text later"
}
}
}
Loader {
id: hello
sourceComponent: myReusableComponent
onLoaded: {
item.innerText = "hello"
}
}
Loader {
id: world
sourceComponent: myReusableComponent
anchors.left: hello.right
onLoaded: {
item.width = 100
item.color = "blue"
item.innerText = "World"
}
}
}
At first I will try to explain why you do not want to do it
If the Component is reused - even in one file and not only by the means of Repeaters
, ListViews
e.t.c - you should consider creating a seperate file, to keep your file clean and readable.
If you create inline-components, and then create the instances by the means of a Loader
just to be able to create them, they come with an overhead, that can be tolerated if the component is really enormous, or you really need the Loader
for the possibility to change the source dynamically. Otherwise, it helps you only to make everything complex, and raise the ressource consumption.
There is almost no penalty for outlaying the code into multiple files. So do it, when ever you have a reasonable, logically enclosed unit - and especially when you are going to reuse it multiple times in a file.
Use the Component
when you are planning to use this as a delegate
. Some perfere to directly declare the delegate
where it is used. I do so, if there are only few properties to set.
Especially if you have multiple Views
that share the same delegate
-prototype, it is a good idea to use the Component
.
If you really need to use a Loader
(for the reasons you need a Loader
and not for non-dynamic object creation) then you can use a Component
to avoid the need of the onLoaded
-event. It enables you to preconfigure the Component, and set the event-handlers without the need of a Connections
-Object.
Ok - now a short answer to your question:
You can create instances of a Component by many means:
componentID.createObject(parent)
) at any point where you can execute JS code.Read: http://doc.qt.io/qt-5/qtqml-javascript-dynamicobjectcreation.html#creating-objects-dynamically
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With