QML ComboBox model can't be filled using Javascript using append() - qt

I'm using Qt 5.15.2 LTS for developing.
Suppose I have following ComboBox:
ComboBox {
id: myComboBox
ListModel {
id: myModel
}
model: myModel
delegate: ItemDelegate {
text: name
}
Component.onCompleted: {
myModel.append({ "name": "1", "value": "val1" });
myModel.append({ "name": "2", "value": "val2" });
myModel.append({ "name": "3", "value": "val3" });
myModel.append({ "name": "4", "value": "val4" });
}
}
When compiling my application, I get the following GUI output:
The ComboBox is just empty - however when calling
console.log("model.count: " + myModel.count) in Component.onCompleted, I get the output qml: model.count: 4 so the model seems to be filled but somehow the contents are not displayed.
However, when substituting ComboBox with ListView:
ListView {
id: myComboBox
ListModel {
id: myModel
}
model: myModel
delegate: ItemDelegate {
text: name
}
Component.onCompleted: {
myModel.append({ "name": "1", "value": "val1" });
myModel.append({ "name": "2", "value": "val2" });
myModel.append({ "name": "3", "value": "val3" });
myModel.append({ "name": "4", "value": "val4" });
}
}
I am getting the deserved output:
According to the QML ComboBox docs, the ComboBox should be perfectly fine being populated with a ListModel:
ComboBox {
currentIndex: 2
model: ListModel {
id: cbItems
ListElement { text: "Banana"; color: "Yellow" }
ListElement { text: "Apple"; color: "Green" }
ListElement { text: "Coconut"; color: "Brown" }
}
width: 200
onCurrentIndexChanged: console.debug(cbItems.get(currentIndex).text + ", " + cbItems.get(currentIndex).color)
}
How come the behaviors differ so much? What do I have to do to fill my ComboBox in a proper way using Javascript?

Try to set the currentIndex property. This is coming from the documentation:
currentIndex
The default value is -1 when count is 0, and 0 otherwise.
My guess is because you are adding the items to the model after the creation of the ComboBox the currentIndex keeps its intial value of -1, hence nothing is selected. When you open the ComboBox you can see the values, but by default none is selected.
Also another thing I did was to add the textRole property. You should also add the valueRole property. I've tested it with both Qt 5.15.11 and 6.4.0.
You should read the paragraph ComboBox Model Roles.
ComboBox {
id: myComboBox
ListModel {
id: myModel
}
textRole: "name"
currentIndex: 0
model: myModel
delegate: ItemDelegate {
text: name
}
Component.onCompleted: {
myModel.append({ "name": "1", "value": "val1" });
myModel.append({ "name": "2", "value": "val2" });
myModel.append({ "name": "3", "value": "val3" });
myModel.append({ "name": "4", "value": "val4" });
}
}

There's no real need to change the delegate just to display your content. It is enough to set textRole: "name". As a recommendation, it is generally best to separate the UI and non-UI components, so, I have moved the ListModel and Component.onCompleted to the bottom of the file:
import QtQuick
import QtQuick.Controls
Page {
ComboBox {
id: myComboBox
model: myModel
textRole: "name"
}
ListModel {
id: myModel
}
Component.onCompleted: {
myModel.append({ "name": "1", "value": "val1" });
myModel.append({ "name": "2", "value": "val2" });
myModel.append({ "name": "3", "value": "val3" });
myModel.append({ "name": "4", "value": "val4" });
}
}
You can Try it Online!

Related

QML Tableview change row color depending on row content

I'm new to qml and I need to write a simple list with 3 columns and an undefined number of rows showing the output of a log using a tableview. The first column shows the type (error, warning, info). Depending on this keywords I need to change the color of that row. I found code where I was able to change the color of all rows, but not individually depending on the data content. This is my starting point:
import QtQuick 2.13
import QtQuick.Window 2.11
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.4
import QtQuick.Controls 1.4 as QtC1
import QtQuick.Dialogs 1.2
ApplicationWindow {
id: applicationWindow
visible: true
width: 640
height: 480
title: qsTr("Log")
ListModel {
id: listModel
ListElement { category: 'warning'; type: "DEVICE IN USE"; comment: "Device with ID: PS-0002 is in use by Line with ID: L-0001A" }
ListElement { category: 'error'; type: "DEVICE IS OFFLINE"; comment: "Cannot reach device with ID: PS-0006 IP: 192.169.0.112 Port: 788" }
ListElement { category: 'info'; type: "DEVICE STATUS"; comment: "Device PS-00013 is ready for use." }
ListElement { category: 'info'; type: "DEVICE STATUS"; comment: "Device PS-00014 is ready for use." }
ListElement { category: 'info'; type: "DEVICE STATUS"; comment: "Device PS-00015 is ready for use." }
ListElement { category: 'info'; type: "DEVICE STATUS"; comment: "Device PS-00016 is ready for use." }
}
ColumnLayout
{
anchors.fill: parent
transformOrigin: Item.Center
Label {
id: logLabel
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
font.pixelSize: 22
text: qsTr("Summary")
Layout.topMargin: 13
}
QtC1.TableView {
id: tv
Layout.fillHeight: true
Layout.preferredHeight: 18
Layout.preferredWidth: 9
Layout.fillWidth: true
rowDelegate: Rectangle {
color: styleData.value ? "blue":"white"
}
/* Create columns */
QtC1.TableViewColumn
{
id: tv_category
horizontalAlignment: Text.AlignLeft
role: qsTr("category")
title: qsTr("Category")
width: 100
}
QtC1.TableViewColumn
{
id: tv_type
horizontalAlignment: Text.AlignLeft
role: qsTr("type")
title: qsTr("Type")
width: 100
}
QtC1.TableViewColumn
{
id: tv_comment
horizontalAlignment: Text.AlignRight
role: qsTr("comment")
title: qsTr("Comment")
width: contentWidth
}
model: listModel
}
}
}
Any help would be appreciated.
Martin
In the rowDelegate you have access to the row index (using styleData.row). Just use it to get the item from the list model like this:
rowDelegate: Rectangle {
color: {
var item = listModel.get(styleData.row)
if (item.category === "info")
return "skyblue"
else if (item.category === "warning")
return "yellow"
else if (item.category === "error")
return "red"
return "skyblue"
}
}

What Qt Quick Controls should I use for this proposed UI?

I am relatively new to QML and Qt Quick and I am looking for recommendations on how to display the UI here:
This UI was made with QGraphicWidgets using Json as a model:
If you notice, the outside "Carriage Strength" container is basically a tree structure. A treeview list seems like the way to go, but I'm unsure if I can customize the view to contain the progress bar and html view (QWebEngineView). I will also need to be able to update specific components like the progress bar at runtime as well.
Any input is helpful. If you have any examples to point to would be great as well. Thanks in advance.
As requested below here is a sample of JSON which would be used to construct the model:
{
"SequenceHistory": [
{
"Definition": {
"ID": "carriage_strength",
"DisplayName": "Carriage Strength",
"TestArray": [
{
"ID": "sequence_one_setup",
"DisplayName": "Sequence 1 Setup",
"TestArray": [
{
"ID": "psm1_carriage_strength",
"DisplayName": "PSM1 Carriage Strength",
"Progress": 100,
"HtmlToDisplay": "<html><body>This is guide instruction</body></html>",
"Status": "Finish Failed",
},
{
"ID": "psm2_carriage_strength",
"DisplayName": "PSM2 Carriage Strength",
"Progress": 43,
"HtmlToDisplay": "<html><body>This is guide instruction</body></html>",
"Status": "In Progress"
},
{
"ID": "psm3_carriage_strength",
"DisplayName": "PSM3 Carriage Strength",
"Progress": 0,
"HtmlToDisplay": "<html><body>This is guide instruction</body></html>",
"Status": "Not Started"
},
{
"ID": "psm4_carriage_strength",
"DisplayName": "PSM4 Carriage Strength",
"Progress": 0,
"HtmlToDisplay": "<html><body>This is guide instruction</body></html>",
"Status": "Not Started"
}
],
},
],
}
}
]
}
The display name indicates the name, the progress indicates the progress bar percentage, the html indicates the html to be displayed in the WebEngineView, and the status indicates the status label. Disregard any timing info that is in the screenshot, but not in the JSON. The main difference between this JSON and the screenshot is that I added a container "Sequence 1 Setup" inside the Carriage Strength container to show that the containers can contain containers as well as items.
I make extensive use of such GUI elements, and the approach is always to represent the tree as lists of lists, that is, depending on the use case, either a ListView or a plain Repeater with a row or column container inside a Flickable, and then it is just delegate nesting.
The stock TreeView may cut it too, if you don't need access for fine-tuning and customizing the view.
I've personally ran into too much stiffness with many of the stock controls, they just don't work the way I need them to or outright lack the desired functionality, and unless it is something really standard, I prefer to roll out my own implementations, which is actually quite easy in QML.
Update:
Ok, now that you have provided an example data source, I can do a basic mock-up for you. BTW you are missing some commas in the JSON, and even tho in my example it is defined in-line, you can simply use JSON.parse(text) to get the same object from a string. Also note that modelData in each nested model refers to a different data object, basically to the respective array element index. And since only one of your arrays has more than one element, the example skips one level for the sake of brevity:
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
property var jsondata: {
"SequenceHistory": [
{
"Definition": {
"ID": "carriage_strength",
"DisplayName": "Carriage Strength",
"TestArray": [
{
"ID": "sequence_one_setup",
"DisplayName": "Sequence 1 Setup",
"TestArray": [
{
"ID": "psm1_carriage_strength",
"DisplayName": "PSM1 Carriage Strength",
"Progress": 100,
"HtmlToDisplay": "<html><body>This is guide instruction</body></html>",
"Status": "Finish Failed"
},
{
"ID": "psm2_carriage_strength",
"DisplayName": "PSM2 Carriage Strength",
"Progress": 43,
"HtmlToDisplay": "<html><body>This is guide instruction</body></html>",
"Status": "In Progress"
},
{
"ID": "psm3_carriage_strength",
"DisplayName": "PSM3 Carriage Strength",
"Progress": 0,
"HtmlToDisplay": "<html><body>This is guide instruction</body></html>",
"Status": "Not Started"
},
{
"ID": "psm4_carriage_strength",
"DisplayName": "PSM4 Carriage Strength",
"Progress": 0,
"HtmlToDisplay": "<html><body>This is guide instruction</body></html>",
"Status": "Not Started"
}
],
},
],
}
}
]
}
ListView {
id: rv
anchors.fill: parent
model: jsondata.SequenceHistory
delegate: Rectangle {
width: rv.width
height: childrenRect.height // fit the expanding part
color: "grey"
Column {
spacing: 2
Row {
spacing: 10
Button {
id: exp
checkable: true
text: checked ? "+" : "-"
implicitWidth: 20
implicitHeight: 20
}
Text {
text: modelData.Definition.DisplayName
anchors.verticalCenter: parent.verticalCenter
}
}
Column {
x: 20
spacing: 2
Repeater {
// if not expanded model is null else skip one level
model: exp.checked ? 0 : modelData.Definition.TestArray[0].TestArray
delegate: Rectangle {
width: rv.width
height: childrenRect.height
color: "lightgrey"
Column {
Row {
spacing: 10
Button {
id: exp2
checkable: true
text: checked ? "+" : "-"
implicitWidth: 20
implicitHeight: 20
}
ProgressBar {
value: modelData.Progress
from: 1
to: 100
anchors.verticalCenter: parent.verticalCenter
}
Text {
text: modelData.DisplayName
anchors.verticalCenter: parent.verticalCenter
}
}
Column {
visible: exp2.checked // hide if not expanded
TextArea {
width: 300
height: 200
text: modelData.HtmlToDisplay
}
}
}
}
}
}
}
}
}
}
And the result:
Note that you can also compartmentalize things by spreading the delegates across different sources, because as you style them property, they will get bigger. I put it in a single source just for the sake of the example.

QML ListView - Limit the number of items displayed in the list

I have a ListView ListModel with 10 ListElements, I want the ListView to display the first ListElement from the model.
Is there a way to limit the number of ListElement items that are displayed, or select the ListElement to display from an ID in the data?
Example ListModel:
ListModel {
id: homeMenuModelData
ListElement {
name: "Sam Wise Is A Very Wise Man"
number: "555 0473"
}
ListElement {
name: "Bill Smith"
number: "555 3264"
}
ListElement {
name: "John Brown"
number: "555 8426"
}
}
The ListView:
ListView {
anchors.fill: parent
interactive: false
model: HomeMenuModel
delegate: homeMenuDelegate
highlight: Rectangle { color: "lightsteelblue"; radius: 5 }
focus: true
}
I'm thinking something like this would be useful to me:
model.clear();
for( var i=0; i < bookList.length ; ++i ) {
model.append(bookList[i]);
}
****** Updated ******
Props to #folibis (below comments) for the suggestion, good explanation here of using DelegateModel and filterOnGroup: Is it possible to show only certain indexes of a QML listview?

QML: Set Property of Nested ListElement

I have a ListModel like the following:
ListModel {
id: liveFeedModel
ListElement {
modelSrc: [
ListElement { src: "../img/pano.jpg" },
ListElement { src: "../img/pano1.jpg" },
ListElement { src: "../img/pano2.jpg" },
ListElement { src: "../img/pano3.jpg" }
]
name: "Cookies"
temp: "456 °C"
time: "--:--"
}
ListElement {
modelSrc: [
ListElement { src: "../img/pano2.jpg" }
]
name: "Sourdough Roll"
temp: "123 °F"
time: "--:--"
}
}
And I would like to set the value of the nested ListElements within modelSrc.
I am looking for something similar to:
liveFeedModel.get(0).modelSrc.get(2).src
except with set, setProperty, or something along those lines, instead of get
Thanks in advance
use:
myListView.model.get(0).modelSrc.setProperty(0, "src", "../img/pano2.jpg");
simple as that!

How to apply the styles for Kendo treeview parent node only

I have kendo tree-view in my application,I want to apply the styles for kendo tree-view parent node only.How to apply the styles like Font weight-bold for the parent node of tree-view?
My treeview code is
var tree= $("#treeview").kendoTreeView({
checkboxes: {
checkChildren: true
},
dataSource: [{
id: 2, text: "select all", expanded: true,
items: [
{ id: 3, text: "ABH" },
{ id: 4, text: "VFG" },
{ id: 5, text: "VFGT" },
{ id: 6, text: "GTYUJ" },
{ id: 7, text: "GHJ" }
]
}]
}).data("kendoTreeView");
here is the JSfiddle.
Try to configure this in scripts.
.k-top.k-bot {font-weight: bold;}

Resources