Reputation: 645
I have several qml files, each of them define a screen in my application. Sometimes, an action on one screen should change items on a different screen. Right now I do this through setting the property Item buttonId and then do
for (var i = 0; i < buttonId.parent.children.length; i++) {
buttonId.parent.children[i].state="inactive"
}
Is it possible to access Items/Objects in different files directly, e.g. through their id?
Upvotes: 3
Views: 13056
Reputation: 13691
As dtech said, you can't access objects in different files as they are no objects yet.
Let's say you have a file called BlueSqare.qml
import QtQuick 2.0
Rectangle {
id: root
width: 100
height: 100
color: 'purple'
}
Now you have your main.qml
import QtQuick 2.0
import QtQuick.Controls 2.0
ApplicationWindow {
id: root
width: 300
height: 300
visible: true
Row {
id: rowdi
spacing: 3
Repeater {
model: 3
delegate: BlueSquare {}
}
}
}
You'll see, that it creates three of my BlueSquare
s so it is undefined which one I want to change if I set root.color = 'blue'
- or actually it is not: Because I have another object with the id: root
in the main.qml
, which is the ApplicationWindow
, I will set it's color to blue.
You can see: id
s need to be unique only within one file, and as such you can only reference objects within this one file by the id
.
There is a exemption from this: You can move up the tree of files in which a qml file is used and reference their ids.
So if you'd try to reference rowdi
in the BlueSqure
in my example this would reference the Row
which arranges them. This is possible as you can have a well defined rule, which object you try to reference by this id
.
If the id
is not found in the file (here: BlueSquare.qml) you try to reference it, then it will look in the file that instantiates the object (here: main.qml). If it finds it there, the search is over. If it does not find it, it will try to move one file up - which is impossible here, as with main.qml
the story ends.
However this should be avoided if possible. Maybe you want to reuse BlueSquare
somewhere else, and there you don't have a Row
that also coincidently has the id: rowdi
. Instead you should inject the references uppon instantiation.
import QtQuick 2.0
import QtQuick.Controls 2.0
ApplicationWindow {
id: root
width: 300
height: 300
visible: true
Row {
id: rowdi
spacing: 3
property color squareColors: 'blue'
Repeater {
model: 3
delegate: BlueSquare {
color: rowdi.squareColors
}
}
}
}
Here we us the id
rowdi
in the file where we defined it, to inject the data to the BlueSquare
s.
You may also pass them an QtObject
which holds all the values as a model. This is especially useful if you're going to change the values:
// MyModelCountingButton.qml
import QtQuick 2.0
import QtQuick.Controls 2.0
Button {
property QtObject model // Better would be to be more specific the QtObject and have a object that guarantees to have your properties
text: model ? model.count : '-'
onClicked: {
if (model) model.count++
}
}
And then in your main.qml
import QtQuick 2.0
import QtQuick.Controls 2.0
ApplicationWindow {
id: root
width: 800
height: 600
visible: true
QtObject {
id: myCountingModel
property int count: 0
}
MyModelCountingButton {
id: button1
model: myCountingModel
}
MyModelCountingButton {
id: button2
model: myCountingModel
}
}
Now you can use the common model to change values that will affect the other object without referencing things outside the own file, which improves reusability.
Basically, uppon instantiation you tell them from where they shall read and store their data, and if this place is shared among your screens, you have won.
For your problem the easiest way would be to have a currentIndex
-property in the model, a index assigned to each screen and then in the file
// Screen.qml
[...]
Item {
id: root
property int index
property QtObject indexObject
Binding {
target: root
property: 'state'
value: 'inactive'
when: index !== indexObject.currentIndex
}
}
and in main.qml
[...]
ApplicationWindow {
[...]
QtObject {
id: indexObject
property int currentIndex: 0
}
Screen {
index: 0
indexObject: indexObject
}
Screen {
index: 1
indexObject: indexObejct
}
[...]
}
Or you have the Screen as:
[...]
Item {
id: root
property int index
property int currentIndex
signal turningActive // this must be emitted when you want to have this screen active.
Binding {
target: root
property: 'state'
value: 'inactive'
when: index !== indexObject.currentIndex
}
}
main.qml
[...]
ApplicationWindow {
id: root
[...]
property int currentIndex: 0
Screen {
index: 0
currentIndex: root.currentIndex
onTuringActive: root.currentIndex = 0
}
Screen {
index: 1
currentIndex: root.currentIndex
onTurningActive: root.currentIndex = 1
}
[...]
}
Usually, if it is only few properties, you create the bindings where you declare their instantiation. If there will be massive numbers, the QtObject
as model is beneficial.
Only if you are really really really sure in which context a declared component will be used at all times, then you can think about referencing things that are from another file (e.g. using parent
in the root node of a file or using id
s that need to be resolved in another file)
Upvotes: 11
Reputation: 49289
You cannot access objects in "different qml files" unless you have an instance of that qml type or a singleton.
Access through the id is only possibly if the object that tries to access it is created in the scope of the object it wants to access via the id.
You you have several screens, simply expose them as properties of the root qml object, then they will be accessible from the entire application because of dynamic scoping, unless they are shadowed by a different property with the same name.
Upvotes: 6