How to forward properties of a child component? - qml

When writing a wrapper around some components, for example :
MyComponent.qml
ColumnLayout{
ListView{
id: listview
}
}
Is it possible to expose all the properties from a child (listview here) without typing by hand all the aliases ?
So that I can do something similar to what the following would do if it was allowed :
ColumnLayout{
MyComponent{
listview.model: ListModel{ // Here
}
}
}
(Either by forwarding them, either by defining a property that point to listview (I tried, it does not seems to work...), or any other way that permit to bind a property from listview as I would do if I was defining a ListView)

You just need to alias the id of the object you want to expose. So in MyComponent.qml, you can do this:
ColumnLayout{
property alias listview: listview
ListView{
id: listview
}
}
Then you can access it from other objects:
ColumnLayout{
MyComponent{
listview.model: ListModel{
}
}
}

Related

How to define QML component inline and override a property?

I'm trying and failing at something seemingly simple: define a simple text formatting component inline, then instantiate it multiple times with different text. Here's the code
Item {
.
.
.
Component {
id: favButtonLabelText
Text {
text: "Blah!"
color: StyleSingleton.xNavPrimaryText
font.family: StyleSingleton.xNavTextFont
font.pointSize: 28
}
}
.
.
.
Loader { sourceComponent: favButtonLabelText; text: "Diameter" }
At the Loader line, the text property is invalid. Attempts to define a property or alias on the component are rejected with "Component objects cannot declare new properties".
The only example I find in the docs, shows overriding the x property of a Rectangle defined in an inline component. It seem to me overriding the text property of a Text element is analogous.
How can I do this?
Since Loader sets itself as the context object for the component it is loading, you could define a property in it and use it in the loaded Item.
However, you have to use a property name not used by your item, otherwise it will be shadowed by your item's own property and there's no easy way to access a context property explicitly.
Component {
id: favButtonLabelText
Text {
text: foobar
}
}
Loader {
sourceComponent: favButtonLabelText
property string foobar: "Diameter"
}
As GrecKo already said, it is possible to use a custom property of the Loader that has another name like in his example foobar.
If you don't do any fancy reparenting of the loaded Item it is also possible to use the same name, and reference it with parent.property
Component {
id: textComponent
Text {
// Use "parent" to reference the property of the parent,
// which is by default the Loader
text: parent.text
}
}
Column {
Repeater {
model: ['hallo welt', 'hello world', 'Bonjour monde', '你好世界']
delegate: Loader {
property string text: modelData
sourceComponent: textComponent
}
}
}
As of Qt 5.15, a new feature has been added: inline Components
As the name suggests, it allows to define an component inline, with the benefits of:
You can create an instance of the component, without the overhead of using a Loader.
You can use the component type in property declarations.
You can refer to the component in other files than the one it is defined in.
Item {
.
.
.
component FavButtonLabelText: Text {
property int aCustomProp: 0
text: "Blah!"
color: StyleSingleton.xNavPrimaryText
font.family: StyleSingleton.xNavTextFont
font.pointSize: 28
}
.
.
.
FavButtonLabelText { text: "myNewText"; aCustomProp: 5 }

How to determine which ListView a delegate QML Item is in?

I have two ListViews (selection and queue) which both use the same delegate.
I want to present some of the item information differently between the two lists.
How do I determine which ListView a QML Item is in? There is no item.parent I can access in the QML.
You could use the ListView.view attached property as folibis mentioned, but there is a nicer way. If you move the delegate into its own QML file, say, Delegate.qml, you can create instances of that type that simply set a property that changes their appearances.
For example:
ListView {
// ...
delegate: Delegate {
fancy: true
}
}
ListView {
// ...
delegate: Delegate {
fancy: false
}
}
You'd code Delegate in such a way that it knows how to render a fancy/non-fancy delegate. For example:
Rectangle {
property bool fancy
color: fancy ? "steelblue" : "grey"
// ...
}

How to get JS eval() to operate in the parent scope of a QML element

If I have some JS code as text and I call it in eval(), I can then use the functions defined by this statement only in the scope of where the eval() occurred. As far as I can tell, this means that any new JS definitions created from the eval are invisible to the rest of QML. Consider this QML signal handler:
Item {
id: testitem
onThesourceChanged: {
eval(thesource)
testfunction()
}
}
The testfunction() was defined in the text “thesource” and does indeed work in the signal handler above, printing out some test text; but it is not in the scope of the QML element and therefore cannot be called ever again, as far as I can see. I’ve tried various ideas like putting the eval() in a function, or inside Component.onCompleted, etc, but I can’t seem to figure out how to get anything created by the eval() to be recognized as part of the parent QML element.
For example I want to be able to call testitem.testfunction() — but it is not defined outside the scope of this handler.
You need to declare the variable in the scope where you want to access it later. Use eval() to initialize it in a child-scope:
import QtQuick 2.1
Rectangle {
width: 360
height: 360
MouseArea {
anchors.fill: parent
onClicked: {
testitem.thesource = "myfunction = function(text) { return text.toLowerCase() }"
}
}
Text {
id: testitem
property var myfunction: function(text) { return text.toUpperCase() }
property var thesource;
anchors.centerIn: parent
text: myfunction("Kullo – Secure Messaging")
onThesourceChanged: {
eval(thesource);
text = myfunction("Kullo – Secure Messaging")
}
}
}

Dynamically set Label's "id" property

I'm developing an application for SailfishOS using the QML language.
I want to dynamically set the id property of a Label by using an if condition.
This is my code:
Label {
id: {
if(myBool == false) {
thisText()
} else {
notThatText()
}
}
width: parent.width
horizontalAlignment: Text.AlignRight
text: ""
font.pixelSize: Theme.fontSizeLarge
}
This code is placed into my CoverPage.qml file, the one that display things on the application's cover while in background.
By doing this, the cover is simply black, nothing is displayed.
Is it possible in QML to do this?
Thanks in advance!
The Qt doc says this.
While it may look like an ordinary property, the id attribute is not an ordinary property attribute, and special semantics apply to it;
You cannot set the id of a QML component at runtime.(Correct me if I am wrong). You might find objectName property useful. But I don't understand why you are trying to assign dynamic id.
I have a use case where use a dynamic/specific id could be useful. The id could be view with Gammaray, it can help for debugging.
GridLayout {
id: layout
Repeater {
model: foo
Bar {
id: bar_X_Y // bar_{model.row}_{model.column}
}
}
}
But as far as I know, it's not possible.

How to access item in a ListDelegates / ListView outside of it?

I am new to Qt / QML coding and I am facing one problem with respect to accessing the elements in a listdelegate in a listview.
For Example if my Qml looks like this
Item
{
id: item_id
property int focus_id: 0
function setFocusImageSource() {}
ListView
{
id: listView_Id
delegate: listViewdelegate
model: listModeldata
}
Component
{
id: listViewdelegate
Rectangle
{
id: rectangle_id
Image
{
id: focus_Image
source: x.x
}
}
}
ListModel
{
id: listModeldata
/*elements*/
}
}
Now the basic functionality of the list view is working fine with my code ( not the above one ) how ever when I do specific operation I need to change the focusing Image . I want to change it using the function "setFocusImageSource()" . I have tried setting the image source directly using focus_Image.source = "xx" .
Is it like the Image inside the Rectangle component is local to the delegate and cannot be accessed from ITEM tag. If so How can I set the image from the function mention above.
Thanks in advance.
Chand.M
A counterpart of QML Component in C++ is a class. As you know you can change members' values only in class' instances - objects. The same is true for Components too: you can not change anything in Component - only in its instances. There are two possibilities to solve you problem:
Bind properties of listViewdelegate to some property outside of it: property of item_id or listView_Id or something else.
Bind properties of listViewdelegate to some property of the element of listModeldata.
Examples:
Image {
id: focus_Image
source: x.x // defualt value
Connections {
target: item_id
onFocus_idChanged: {
if ( /* some logic if needed */ ) {
focus_Image.source = xx;
}
}
}
}
or
Image {
id: focus_Image
source: {
// inidicator is a property of the element of listModeldata
if (indicator) {
return xx;
}
}
}