Get specific item in model QML - qt

I can recover an element in my model:
property var model: [
{ title: i18n.tr("Standard"), descr: i18n.tr("Style by default"), style:"default" },
{ title: i18n.tr("None"), descr: i18n.tr("Icons without style", style:"none" }
]
ListItem.ItemSelector {
id: styleIconList
model: settingsColumn.model
delegate: OptionSelectorDelegate {
property var item: model.modelData ? model.modelData : model
text: item.title
subText: item.descr
}
onSelectedIndexChanged: {
launchermodular.settings.iconStyle = model.get(selectedIndex).style //here is problem
}
}
Can you tell me how?
Thank you

Related

How to create different component base on ListModel in QML

There are 9 parameters that I need to use TextField1 to input value.
So I use
ListModel lstPara {
ListElement{
text:"A";value:"123"
}...(9 Elements)
}
Grid{
id: grid
anchors.fill: parent
columns: 3
spacing: 5
Repeater {
id: rpPara
model: lstPara
delegate: TextField1 {
}
}
}
But now there is a parameter that i need to use in another QML type to set the value, all others are used in TextField1.
I tried to define ListModel like this
ListModel lstPara{
ListElement {
text: "A";
type: 1";
value: "123"
}
ListElement {
text: "B";
type: 2";
value: "321"
}
...(9 Elements)
}
Grid{
id: grid
anchors.fill: parent
columns: 3
spacing: 5
Repeater {
id: rpPara
model: lstPara
(some code : like this)
delegate: {
return type === 1 ?
TextField1 {
}
:
another QML type {
}
}
}
}
The code above can not run.
And I don`t want to write 8 TextField1 and 1 another QML type.
So, is there a way to use ListModel?
You can't directly use an Item declaration in a conditional expression like that, but you can do it with a Component. Here's an example of how to do it using a Loader as your delegate, and choosing which Component to load based on the model:
ListModel {
id: lstPara
ListElement {
text: "A"
type: 1
value: "123"
}
ListElement {
text: "B"
type: 2
value: "321"
}
}
Grid {
id:grid
anchors.fill: parent
columns: 3
spacing: 5
Repeater {
id: rpPara
model: lstPara
delegate: Loader {
sourceComponent: type === 1 ? someText : otherText
onLoaded: {
item.text = text
item.value = value
}
}
}
Component {
id: someText
Text {
property string value
color: "blue"
}
}
Component {
id: otherText
Text {
property string value
color: "red"
}
}
}

ReferenceError: "Item" is not defined

I want to check if an item of component is vissible or not but I don't know how to do this.
Here is my code but error is "ReferenceError: tagFilterPlaylist is not defined" how to solve this?
Repeater {
id: tagRepeater
model: main.playListBrowseModel
Component {
id: componentTagFilterPlaylist
BasicUI.Tag {
id: tagFilterPlaylist
tag: "playlist"
selected: true
}
}
Loader {
id: filterLoader
sourceComponent:
if (item_type === "playlist"){
console.debug("check"+tagFilterPlaylist)
if (!tagFilterPlaylist) {
tagFilterPlaylist.visible = true;
return componentTagFilterPlaylist
}
}
}
}
You can't refer to an id within a Component because you first need to have an instance of that Component. What you should do is simply keep a boolean property outside the Repeater that keeps track of whether or not you're displaying your one and only tagFilterPlaylist.
property bool playlistVisible: false
Component {
id: componentTagFilterPlaylist
...
}
Repeater {
id: tagRepeater
model: main.playListBrowseModel
Loader {
id: filterLoader
sourceComponent:
if (item_type === "playlist"){
if (!playlistVisible) {
playlistVisible = true;
return componentTagFilterPlaylist
}
}
}
}

QML render list in list

My simplified code is
import QtQuick 2.0
Item {
ListModel {
id: items_model
dynamicRoles: true
}
Component.onCompleted: {
var data = {
"items": [{
"name": "test1",
"rows": ["1", "2", "3"]
}, {
"name": "test2",
"rows": ["1", "2", "3"]
}, {
"name": "test3",
"rows": ["1", "2", "3"]
}]
}
data.items.forEach(function (element) {
items_model.append(element)
console.log(element.rows)
})
console.log(items_model.count)
}
ListView {
orientation: ListView.Horizontal
model: items_model
delegate: Item {
height: parent.height
width: 50
Column {
anchors.fill: parent
Text {
text: name
}
Repeater {
model: rows
delegate: Text {
text: rows.get(index) + " " + index
Component.onCompleted: {
console.log(rows.get(index))
}
}
}
}
}
}
}
But I have DynamicRoleModelNode, not text
qml: DynamicRoleModelNode(0x563014585300)
qml: DynamicRoleModelNode(0x563014585330)
qml: DynamicRoleModelNode(0x563014585360)
qml: DynamicRoleModelNode(0x563014570350)
qml: DynamicRoleModelNode(0x563014570380)
qml: DynamicRoleModelNode(0x5630145703b0)
qml: DynamicRoleModelNode(0x563014558e00)
qml: DynamicRoleModelNode(0x563014558e30)
qml: DynamicRoleModelNode(0x563014558e60)
modelData not provided here besause of rows converted to QQmlListModel
How can i extract text from it?
Take a look at the documentation about models here:
https://doc.qt.io/qt-5/qtquick-modelviewsdata-modelview.html#models
In particular:
Models that do not have named roles (such as the ListModel shown below) will have the data provided via the modelData role. The modelData role is also provided for models that have only one role. In this case the modelData role contains the same data as the named role.
So in your case, the string data you are looking for will be provided in a variable called modelData in the context of the Text component.
Note that in your specific case, this cannot be done directly because the ListModel is converting the child role items into a ListModel itself instead of a StringList model. This may be a bug in Qt as you would think you should normally get a StringList there.
To work around it, you can store your child items in a separate map and apply them directly to the Repeater so that you correctly get a StringList model and then modelData will indeed work.
Something like this:
property var itemsMap: ({
"test1": ["1", "2", "3"],
"test2": ["1", "2", "3"],
"test3": ["1", "2", "3"]
})
Item {
ListModel {
id: items_model
dynamicRoles: true
}
Component.onCompleted: {
var data = {
"items": [{
"name": "test1"
}, {
"name": "test2"
}, {
"name": "test3"
}]
}
data.items.forEach(function (element) {
items_model.append(element)
})
console.log(items_model.count)
}
ListView {
orientation: ListView.Horizontal
model: items_model
delegate: Item {
height: parent.height
width: 50
Column {
anchors.fill: parent
Text {
text: name
}
Repeater {
model: itemsMap[name]
delegate: Text {
text: modelData
}
}
}
}
}
}
As workaround wrap text to object
data.items.forEach(function (element) {
element.rows.forEach(function (item, index) {
element.rows[index] = {text: item}
})
items_model.append(element)
})
and
Repeater {
model: rows
delegate: Text {
text: text
}
}

How change field of reused component in Qml?

I have the following code. I need to set different "model" field for different TableViews. How can i do this?
I need override "model" field for every TableView. It is possible?
// main.qml
ApplicationWindow {
id: window
TabView {
Tab {
title: "Tab 1"
MyTable {}
}
Tab {
title: "Tab 2"
MyTable {}
}
}
}
.
// MyTable.qml
MyTableView {
TableView {
TableViewColumn {
role: "number"
title: "Number"
}
model: MyModel
}
}
The next code is correct but too long.
// main.qml
ApplicationWindow {
id: window
TabView {
Tab {
title: "Tab 1"
TableView {
TableViewColumn {
role: "number"
title: "Number"
}
model: MyModel_1
}
}
Tab {
title: "Tab 2"
TableView {
TableViewColumn {
role: "number"
title: "Number"
}
model: MyModel_2
}
}
}
}
You can set a property alias for the model. First set an id for the TableView then hook up its model.
// MyTable.qml
MyTableView {
property alias model: tableView.model
TableView {
id: tableView
TableViewColumn {
role: "number"
title: "Number"
}
// model: MyModel // redundant in most cases
// unless you want to have a DEFAULT model
}
}
And use model in each MyTable item like so:
// main.qml
ApplicationWindow {
id: window
TabView {
Tab {
title: "Tab 1"
MyTable { model: MyFirstModel }
}
Tab {
title: "Tab 2"
MyTable { model: MySecondModel }
}
}
}

QML - Retrieving index of delegate in DelegateModel

I have trouble retrieving the index of a delegate that is instantiated inside a DelegateModel for a ListView.
The minimal example as following:
LastProcedures.qml
ListModel {
ListElement {
procedure: "Liver Resection"
surgeon: "Prof. Dr. Joyride"
recent: true
}
...
}
main.qml
ListView {
id: list_lastProcedures
model: displayDelegateModel
}
DelegateModel {
id: displayDelegateModel
delegate: lastProceduresDelegate
model: LastProcedures {}
groups: [
DelegateModelGroup {
includeByDefault: false
name: "recent"
}
]
filterOnGroup: "recent"
Component.onCompleted: {
var rowCount = model.count;
items.remove(0,rowCount);
for( var i = 0;i < rowCount;i++ ) {
var entry = model.get(i);
// Only the recent three
if((entry.recent == true) && (items.count < 3)) {
items.insert(entry, "recent");
}
}
}
}
Component {
id: lastProceduresDelegate
Text{
text: model.index
}
}
The text index prints always -1. Without a DelegateModel it prints the index in the ListView. How can I access the correct index of the delegate in the Listview?
you can use "lastProceduresDelegate.DelegateModel.itemsIndex" instead of "model.index"
just like this:
Component {
id: lastProceduresDelegate
Text{
text: lastProceduresDelegate.DelegateModel.itemsIndex
}
I ended up with not removing all entries and adding them back to groups, but instead just remove unwanted entries. This ways the index stays valid.
If someone could explain this behavior further, that would be nice.
DelegateModel {
id: displayDelegateModel
delegate: lastProceduresDelegate
model: LastProcedures {}
groups: [
DelegateModelGroup {
includeByDefault: true
name: "recenttrue"
}
]
filterOnGroup: "recenttrue"
Component.onCompleted: {
for( var i = 0;i < items.count;i++ ) {
var entry = items.get(i).model;
// Only the recent
if((entry.recent != true)) {
items.removeGroups(i, 1, "recenttrue");
}
}
}
}
The DelegateModel has some hidden magic regarding groups (it's not very visible but it's here ). For each group you create, the DelegateModel attached property will receive two new properties: <group>Index and in<Group>.
In your case this means you will get the following properties: recentIndex and inRecent (or in your own answer: recenttrueIndex and inRecenttrue).
I think with what you want to do you should go the recenttrue route and draft the Component as follows:
Component {
id: lastProceduresDelegate
Text {
text: lastProceduresDelegate.DelegateModel.recenttrueIndex
}
}

Resources