How to define QML component inline and override a property? - qml

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 }

Related

How to forward properties of a child component?

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

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

ExtJs 4... How to extend Extjs 4 components?

can somebody help me with how to extend extjs components using extjs version 4. I am looking for a proper syntax for the same. please help..!!
Following is an example code of extending textfield in ExtJS 4.
Other then using the existing configs and methods, this extended component also has a new config property created and a new method created & associated with an event.
The purpose of component is simple that it displays the label in red color if the value is mandatory, modifies the background color of the field if its readOnly and also changes the background color of the field when focussed.
The code is properly commented. Hope it helps.
Ext.define('Ext.pnc.Textfield', {
extend: 'Ext.form.field.Text',//Extending the TextField
alias: 'widget.pnctextfield',//Defining the xtype
config:{
focusCls:'focusClassFieldPnC',//Providing value for existing config property.
testConfig:'testConfigValue'//Creating a new config. Accessor functions will be created for this one by ExtJS engine
},
constructor:function(cnfg){
this.callParent(arguments);//Calling the parent class constructor
this.initConfig(cnfg);//Initializing the component
this.on('beforerender',this.beforeRender);//Associating a new defined method with an event
},
//Defining a method below and associating this with an event in the constructor above
beforeRender:function(){
if(!this.allowBlank){
this.labelStyle = 'color:#FF0000';
}
if(this.readOnly){
this.fieldCls = 'readOnlyClass';
}
},
//Over-riding a function which already exists in parent class. Note that this has not been associated with any event in constructor as it already defined in parent class
afterRender:function(){
console.log('after render function');
this.callParent();//Calling the parent class method. This can be omitted if not required and is not a must
}
});
.readOnlyClass{
background:#FF0000 !important
}
.focusClassFieldPnC{
background:#00ff00 !important
}
Ext.define('myApp.Grid', {
extend: 'Ext.Grid',
alias: 'widget.mygrid'
....
....
}
now you can use xtype:'mygrid'
Ext.define('BS.view.MyGrid' , {
extend: 'Ext.grid.Panel',
alias: 'widget.my-grid',
// Non-complex config types (booleans, integers, strings) go here
width: 1000,
autoHeight: true
initComponent: function() {
Ext.apply(this, {
// complex configs (objects / arrays) go here
columns: colModel,
});
this.callParent(arguments);
}
});
why not see the src of extjs4's components such as Grid,Table ...
and here are docs:
http://docs.sencha.com/ext-js/4-0/#/guide/components <== important
http://docs.sencha.com/ext-js/4-0/#/guide/class_system
Ext.define('My.custom.Component', {
extend: 'Ext.Component'
});