QML single model attached with multiple delegates or views - qt

I have a model (markerModel) derived from AbstractListModel which have three roles status, position and label. I am showing them by drawing circles on map. At the same time I want to print their position and label n a rectangle rectangle1. But MapItemView already have a delegate. Can there be multiple delegates with one model ?
Map {
id: map
anchors.fill: parent
plugin: mapPlugin
center: QtPositioning.coordinate(22.5726, 88.3639)
zoomLevel: 14
MapItemView {
model: markerModel
delegate: markerDelegate
}
Component {
id: markerDelegate
MapQuickItem{
anchorPoint: Qt.point(2.5, 2.5)
coordinate: QtPositioning.coordinate(position.x, position.y)
zoomLevel: 0
sourceItem: Rectangle{
width: settings.marker_size;
height: settings.marker_size;
radius: settings.marker_size/2;
color: settings.marker_colors[status]
border.color: "white"
border.width: 1
}
}
}
}
Rectangle {
id: rectangle1
anchors.top: map.top
anchors.right: map.right
width: 500
height: 750
color: "#ffffff"
}

There is no direct connection between a model and a delegate, it is the view that connects the two.
You can have as many views using the same model for data source, and you can have whatever different delegates you want in each of those views:
ListModel {
id: mod
ListElement { value: "red" }
ListElement { value: "green" }
ListElement { value: "blue" }
ListElement { value: "cyan" }
ListElement { value: "magenta" }
}
Row {
ListView {
width: 100
height: 250
model: mod
delegate: Rectangle {
width: 100
height: 50
color: value
}
}
ListView {
width: 100
height: 250
model: mod
delegate: Rectangle {
width: 100
height: 50
color: "grey"
Text {
anchors.centerIn: parent
text: value
}
}
}
}

Related

Creating dynamic ListModel is QML

I've been trying to populate a ListView in QML with data from a list I have, but in the documentation it doesn't show how to dynamically populate a ListModel or ListView. The data in the list keeps changing and I intend to update the list in real time and that is why I don't have to have a hard-coded model.
Based on tutorials, this works:
Rectangle {
anchors.horizontalCenter: parent.horizontalCenter
color: "black"
height: 500
width: 0.95 * parent.width
ListView {
anchors.fill: parent
model: fruitModel
delegate: fruitDelegate
}
}
ListModel {
id: fruitModel
ListElement {
name: "Apple"
cost: 2.45
}
ListElement {
name: "Orange"
cost: 3.25
}
ListElement {
name: "Banana"
cost: 1.95
}
}
Component {
id: fruitDelegate
Row {
spacing: 10
Text { text: name; color: "white" }
Text { text: '$' + cost; color: "white" }
}
}
But this doesn't:
userModel : ["Tony", "Stark"] //list containing names of users
Rectangle {
anchors.horizontalCenter: parent.horizontalCenter
color: "black"
height: 500
width: 0.95 * parent.width
ListView {
anchors.fill: parent
model: userModel // a list containing all users
delegate: fruitDelegate
}
}
Component {
id: fruitDelegate
Row {
spacing: 10
Text { text: name; color: "white" }
}
}
The roles define how to access the information, for example fruitModel has 2 roles: name and cost. But when using a list as a model then you have to use modelData as a role to access the information:
Component {
id: fruitDelegate
Row {
spacing: 10
Text { text: modelData; color: "white" }
}
}
The ListModel can be updated through the append function:
Rectangle {
anchors.horizontalCenter: parent.horizontalCenter
color: "black"
height: 500
width: 0.95 * parent.width
ListView {
anchors.fill: parent
model: fruitModel
delegate: fruitDelegate
}
}
ListModel {
id: fruitModel
Component.onCompleted: {
fruitModel.append({"name": "Tony"})
fruitModel.append({"name": "Stark"})
}
}
Component {
id: fruitDelegate
Row {
spacing: 10
Text { text: name; color: "white" }
}
}

How can I change the listModel of an listview when I click on a button?

In my code I want to change the ListModel of my ListView when I click on the button. My code doesn't work, how I can fix it?
ApplicationWindow {
id: window
visible: true
width: 640
height: 480
property bool typelist: false
Component {
id: l1
ListModel{
ListElement { test: "blue" }
}
}
Component {
id: l2
ListModel{
ListElement { test: "red" }
ListElement { test: "blue" }
}
}
Component {
id: deleg
Rectangle {
width: parent.width
height: 50
color: test
}
}
ListView {
id: list
width: parent.width
height: parent.height * 0.75
delegate: deleg
}
Button {
width: parent.width
height: parent.heigth * 0.25
anchors.bottom: parent.bottom
onClicked: {
if(typelist == false) {
list.model = Qt.createComponent(l1)
typelist =! typelist
}
else {
list.model = Qt.createComponent(l2)
typelist =! typelist
}
}
}
}
When I click, I get this error:
ReferenceError: test is not defined
Because you are using the wrong function.
Qt.createComponent takes a url as a parameter and returns a new Component.
You already have a Component, so you don't need that function.
You need Component.createObject. It creates an instance of an object from a Component.
Your code then becomes
list.model = l1.createObject();
Note that you don't have to use Component in your example if you don't mind instantiating both models from the start:
ApplicationWindow {
id: window
visible: true
width: 640
height: 480
property bool typelist : false
ListModel{
id: listModel1
ListElement { test: "blue" }
}
ListModel{
id: listModel2
ListElement { test: "red" }
ListElement { test: "blue" }
}
ListView {
id: listView
width: parent.width
height: parent.height * 0.75
model: typelist ? listModel1 : listModel2
delegate: Rectangle{
width: parent.width
height: 50
color: model.test
}
}
Button {
width: parent.width
height: parent.heigth*0.25
anchors.bottom:parent.bottom
onClicked: typelist=!typelist
}
}

QML: ScrollView with GridView inside: adjust cell to available space (with or without scroll bar)

I have a QML ScrollView with a GridView inside (rectangles in 3 columns) and I have a repaint problem when the scroll appears/disappears.
The window has fixed width (300) and variable height, so the scroll appears when window height is less than content height, of course.
My target is that the rectangles are completely visibles always (with or without scroll), expanded to the left when no scroll appears, and to the left of the scroll when it is visible. For that, I suppose I need to set the cell size depending on the scroll, for them to adjust the available space.
It works BUT just in the moment the scroll appears/disappears, there is a short window height range when the rectangles are not painted properly.
Here is my code, I have tried with other properties otions with no success...
import QtQuick 2.5
import QtQuick.Controls 1.3
import QtQuick.Controls.Styles 1.4
Item {
id: idGrid
height: 800
width: 300
property int iNumcolums: 3
property int iMarginGrid: 2
ListModel {
id: appModel
ListElement { colorR: "red"}
ListElement { colorR: "green" }
ListElement { colorR: "blue" }
ListElement { colorR: "cyan"}
ListElement { colorR: "yellow"}
ListElement { colorR: "blue" }
ListElement { colorR: "lightgray" }
ListElement { colorR: "red" }
ListElement { colorR: "green" }
ListElement { colorR: "blue" }
ListElement { colorR: "cyan" }
ListElement { colorR: "yellow" }
ListElement { colorR: "lightgray" }
ListElement { colorR: "blue" }
}
ScrollView {
id: scrollView
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: iMarginGrid
anchors.rightMargin: iMarginGrid
property int scrollWidth: 10
style: ScrollViewStyle {
id: sptScrollStyle
property int iScrollWidth: 10
handle: Rectangle {
implicitWidth: iScrollWidth
color: "gray"
radius: 20
}
scrollBarBackground: Rectangle {
implicitWidth: iScrollWidth
color: "lightgray"
radius: 20
}
decrementControl: Rectangle {
implicitWidth: 0
}
incrementControl: Rectangle {
implicitWidth: 0
}
}
GridView {
id: grid
//width: parent.width;
height: parent.height
model: appModel
property bool scrollBarVisible: contentHeight > height
width: parent.width - (scrollBarVisible ? scrollView.iScrollWidth : 0)
property int iSizeThumb: width / 3
cellWidth: iSizeThumb; cellHeight: iSizeThumb
delegate: Item {
width: grid.cellWidth; height: grid.cellHeight
Rectangle { color: colorR; anchors.fill: parent; anchors.margins: 2}
}
}
}
}
}

QML Nested List view with Highlight

I need to create nested list view and as shown below, and highlight the main list and sub-list with different color
I have tried with ListView highlight but there are issue like the highlight showing for child as well as parent as shown
below image.
I am using the code from here with some minor modification.
Here is the full code
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.1
ApplicationWindow {
id: loginWindow
//visibility: "Maximized"
visible: true
width: 720
height: 720
Item {
width: 200
height: 720
ListView {
id: list
anchors.fill: parent
model: nestedModel
delegate: categoryDelegate
highlight: Rectangle {
color: "#FF00AAFF" //"#FF59ACFF";
radius: 2
}
}
ListModel {
id: nestedModel
ListElement {
categoryName: "Veggies"
collapsed: true
// A ListElement can't contain child elements, but it can contain
// a list of elements. A list of ListElements can be used as a model
// just like any other model type.
subItems: [
ListElement {
itemName: "Tomato"
},
ListElement {
itemName: "Cucumber"
},
ListElement {
itemName: "Onion"
},
ListElement {
itemName: "Brains"
}
]
}
ListElement {
categoryName: "Fruits"
collapsed: true
subItems: [
ListElement {
itemName: "Orange"
},
ListElement {
itemName: "Apple"
},
ListElement {
itemName: "Pear"
},
ListElement {
itemName: "Lemon"
}
]
}
ListElement {
categoryName: "Cars"
collapsed: true
subItems: [
ListElement {
itemName: "Nissan"
},
ListElement {
itemName: "Toyota"
},
ListElement {
itemName: "Chevy"
},
ListElement {
itemName: "Audi"
}
]
}
}
Component {
id: categoryDelegate
Column {
width: 200
Rectangle {
id: categoryItem
border.color: "black"
border.width: 5
color: "#33FF5225"
height: 50
width: 200
Text {
anchors.verticalCenter: parent.verticalCenter
x: 15
font.pixelSize: 24
text: categoryName
}
Rectangle {
color: "red"
width: 30
height: 30
anchors.right: parent.right
anchors.rightMargin: 15
anchors.verticalCenter: parent.verticalCenter
MouseArea {
anchors.fill: parent
// Toggle the 'collapsed' property
onClicked: {
list.currentIndex = index
nestedModel.setProperty(index, "collapsed",
!collapsed)
}
}
}
}
Loader {
id: subItemLoader
// This is a workaround for a bug/feature in the Loader element. If sourceComponent is set to null
// the Loader element retains the same height it had when sourceComponent was set. Setting visible
// to false makes the parent Column treat it as if it's height was 0.
visible: !collapsed
property variant subItemModel: subItems
sourceComponent: collapsed ? null : subItemColumnDelegate
onStatusChanged: if (status == Loader.Ready) item.model = subItemModel
}
}
}
Component {
id: subItemColumnDelegate
Column {
property alias model: subItemRepeater.model
width: 200
Repeater {
id: subItemRepeater
delegate: Rectangle {
x: 10
color: "#33FF5225"
height: 40
width: 190
border.color: "black"
border.width: 2
Text {
anchors.verticalCenter: parent.verticalCenter
x: 30
font.pixelSize: 18
text: itemName
}
}
}
}
}
}
}
How can I overcome this issue. Basically I need to highlight Parent and child Item with different color.
Edit:
I can highlight parent list using the code
color:categoryDelegate.ListView.isCurrentItem ? "#FF00AAFF" : "#CCBBBBBB"
but coud'nt a find similar way to change the color of child list (sub list) on click.
Change the color property of the delegate in subItemRepeater to your choice.
Example
Component {
id: subItemColumnDelegate
Column {
...
Repeater {
id: subItemRepeater
delegate: Rectangle {
...
color: "purple"
...
}
}
}
}
Similarly change the color property categoryItem in the categoryDelegate.
Example
Component {
id: categoryDelegate
Column {
...
Rectangle {
id: categoryItem
...
color: "blue"
...
}
}
}
EDIT:
In that case the the overall concept is wrong. In the comment of the original code the author has written A ListElement can't contain child elements, but it can contain a list of elements. So we can't highlight the child item. But the following approach will give good result to you.
import QtQuick 2.0
Rectangle {
width: 360
height: 360
ListModel {
id: model1
ListElement {
name: "name"
}
ListElement {
name: "name"
}
ListElement {
name: "name"
}
}
ListModel {
id: model2
ListElement {
name: "inside"
}
ListElement {
name: "inside"
}
ListElement {
name: "inside"
}
}
ListView {
id: outer
model: model1
delegate: listdelegate
anchors.fill: parent
}
Component {
id: listdelegate
Item {
width: 100
height: col.childrenRect.height
Column {
id: col
anchors.left: parent.left
anchors.right: parent.right
Text {
id: t1
text: name
}
ListView {
id: insidelist
model: model2
property int collapseHeightFlag: childrenRect.height
delegate: Component {
id: delegate2
Item {
width: 100
height: col2.childrenRect.height
Column {
id: col2
anchors.left: parent.left
anchors.right: parent.right
Text {
id: name1
text: name
}
}
MouseArea {
anchors.fill: parent
onClicked: {
insidelist.currentIndex = index;
}
}
}
}
contentHeight: contentItem.childrenRect.height
height: 0
anchors.left: parent.left
anchors.right: parent.right
clip: true
highlight: Rectangle {
color: "pink"
radius: 2
}
focus: true
}
}
Rectangle {
color: "red"
width: 10
height: 10
anchors.right: parent.right
anchors.rightMargin: 5
anchors.top: parent.top
anchors.topMargin: 5
MouseArea {
anchors.fill: parent
onClicked: {
if(insidelist.height === insidelist.collapseHeightFlag) {
insidelist.height = 0;
}
else
insidelist.height = insidelist.collapseHeightFlag;
}
}
}
}
}
}

How to access the property of a GridView - or ListView - element

Here is the code, I create 4 buttons. When one is clicked I wanna that its color changes to red and the color of all the others change to black.
But looks like I could not access the color property.
Rectangle {
id: root
width: 200; height: 100
DelegateModel {
id: visualModel
model: ListModel {
ListElement { my_color: "red" }
ListElement { my_color: "black" }
ListElement { my_color: "black" }
ListElement { my_color: "black" }
}
groups: [
DelegateModelGroup { name: "selected" }
]
delegate: Rectangle {
id: item
height: 25
width: 200
color:my_color
MouseArea {
anchors.fill: parent
onClicked: {
console.log(visualModel.items.get(index).color)
for (var i = 0; i < root.count; i++){
if(index == i)
visualModel.items.get(i).color = "red";
else
visualModel.items.get(i).color = "black";
}
}
}
}
}
ListView {
anchors.fill: parent
model: visualModel
}
}
I advice you to use ExclusiveGroup from QML controls. Usually it is used for Action but it's possible to use it for any other Item. From the Qt docs:
It is possible to add support for ExclusiveGroup for an object or
control. It should have a checked property, and either a
checkedChanged, toggled(), or toggled(bool) signal.
So all we need is to add suitable property. Small example:
import QtQuick 2.5
import QtQuick.Window 2.0
import QtQuick.Controls 1.4
Window {
width: 200
height: 400
ExclusiveGroup { id: exclusiveGroup }
ListView {
anchors.fill: parent
anchors.margins: 5
spacing: 2
model: 10
delegate: Rectangle {
id: myItem
property bool checked: false // <-- this is necessary
height: 30
width: parent.width
color: myItem.checked ? "lightblue" : "#DEDEDE"
border { width: 1; color: "#999" }
radius: 5
Text { text: "item" + (index + 1); anchors.centerIn: parent}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: myItem.checked = !myItem.checked;
}
Component.onCompleted: {
exclusiveGroup.bindCheckable(myItem);
}
}
}
}

Resources