Steve Fallows
Steve Fallows

Reputation: 6424

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?

Upvotes: 3

Views: 8639

Answers (3)

skaldesh
skaldesh

Reputation: 1530

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 }

Upvotes: 9

derM
derM

Reputation: 13701

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
        }
    }
}

Upvotes: 6

GrecKo
GrecKo

Reputation: 7160

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"
}

Upvotes: 7

Related Questions