Getting header title from model in QtQuick ListView - qt

It's not clear to me how to access the model from the header component in ListView. I have provided headerData in the (C++) model, but it doesn't seem to be called. I can grab the data from the model in theRowDelegate, so my roles are defined correctly (I have implemented the roleNames function).
I'm sure this must be explained in the documentation somewhere, but I can't find it.
ListView{
anchors.fill: parent
model: logfile_model
orientation: Qt.Vertical
header: Row{
Text{
text: increment // Doesn't work
width: 100
}
Text{
text: iteration // Doesn't work
width: 100
}
}
delegate: Row{
Text {
text: increment
width: 100
}
Text {
text: iteration
width: 100
}
}
}

This is the demo you want, but not recommend because the header text shall not put into model data.
You can drag the list to see the header fixed always keep visible.
ListModel{
id: testData
ListElement{
increment: "I am a Header"
iteration: "I am also aHeader"
}
ListElement{
increment: "testData"
iteration: "testData"
}
ListElement{
increment: "testData"
iteration: "testData"
}
ListElement{
increment: "testData"
iteration: "testData"
}
}
ListView{
anchors.fill: parent
model: testData
Rectangle{ // always visible
width: header.width
height: header.height
color: "white"
Row{
id: header
Text{
text: testData.get(0).increment
width: 100
}
Text{
text: testData.get(0).iteration
width: 100
}
}
}
delegate: Row{
Text {
text: increment
width: 100
}
Text {
text: iteration
width: 100
}
Component.onCompleted: if(index == 0) {
visible = false
}
}
}

Related

Is there a way to make unselectable a "list item" in ListView?

I am new to Qt. Wondering if there a possibility to make an item "unselectable" in ListView.
I see there are a lot of other things, e.g: collapsing , expanding, etc.
**
I have not find any simple example for this problem. **
Can you provide some minimalistic examples to make a specific item in the list unselectable?
I have the following minimalistic example. How can I set list item index 2 to be unselectable?
Window {
id: mainWindow
width: 130
height: 240
visible: truetitle: qsTr("Hello")
Rectangle {
id: bg
color: "#ffffff"
anchors.fill: parent
ListModel {
id: nameModel
ListElement { name: "Alice" }
ListElement { name: "Bob" }
ListElement { name: "Jay" }
ListElement { name: "Kate" }
}
Component {
id: nameDelegate
Text {
text: model.name
font.pixelSize: 24
}
}
ListView {
anchors.fill: parent
model: nameModel
delegate: nameDelegate
clip: true
highlight: Rectangle {
anchors { left: parent.left; right: parent.right }
//height: parent.height
color: "lightgrey"
}
}
}
}
I found numerous issues with your code snippet, so I attempted to address them all:
I made use of Page and set Page.background instead of declaring an outer Rectangle. This removes a level of indentation
I refactored NameComponent.qml to reduce the complexity of your main program
I change the delegate from Text to ItemDelegate so that it is clickable, and, it being clickable, I can (1) make the ListView have active focus so that it can receive keyboard events, (2) change the current item in the ListView => I think this achieves your criteria of being able to select a different item
I removed unnecessary anchoring from your highlight - your highlight will default anchor to your selected item
I set the width of your delegate to listView.width - I also made use of the ListView.view attached property so that your delegate and access properties from the ListView
Finally, I added a 20 pixel width vertical ScrollBar
import QtQuick
import QtQuick.Controls
Page {
background: Rectangle { color: "#ffffff" }
ListModel {
id: nameModel
ListElement { name: "Alice" }
ListElement { name: "Bob" }
ListElement { name: "Jay" }
ListElement { name: "Kate" }
}
ListView {
anchors.fill: parent
model: nameModel
delegate: NameDelegate { }
clip: true
highlight: Rectangle {
color: "lightgrey"
}
ScrollBar.vertical: ScrollBar {
width: 20
policy: ScrollBar.AlwaysOn
}
}
}
// NameDelegate.qml
import QtQuick
import QtQuick.Controls
ItemDelegate {
property ListView listView: ListView.view
width: listView.width - 20
text: model.name
font.pixelSize: 24
onClicked: {
listView.forceActiveFocus();
if (listView.currentIndex === index) {
listView.currentIndex = -1;
} else {
listView.currentIndex = index;
}
}
}
You can Try it Online!

How to get the list of QML Column Layout children?

I am working on some QML + c++ project and, I have a little problem with QML layouts:
I have two custom components :
First one: is a side-bar "SideTabBar.qml" (the purple rectangle in the image below).
Second one: is the element in the side-bar "SideBarElement.qml".
This image describes what I am talking about:
What I want is: highlight each side bar element on click.
To do so I am trying to iterate over the columnLayout children and lowlight them excepting the clicked one. But, I have not managed to make it works.
SideTabBar.qml:
Item {
id: sideTabBar
width: 70
height: parent.height
property string activeElement: ""
ColumnLayout{
id:sidebarLayout
anchors.fill: parent
spacing:2
SideBarElement{elementId:"a1";image:"../assets/product.svg"}
SideBarElement{elementId:"a2";image:"../assets/product.svg"}
Item {Layout.fillHeight: true}
}
}
SideBarElement.qml:
Item {
property alias image: sideBarElementicon.source
property string elementId: ""
id: sideBarElement
width:parent.width
Layout.preferredHeight: 70
Layout.alignment: Qt.AlignTop
Rectangle{
anchors.fill: parent
color:Qt.rgba(0,0,0,0)
}
Image {
id: sideBarElementicon
source: "genericIcon.png"
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
width: 50
height: 50
}
MouseArea{
anchors.fill: parent
onClicked:{ sideTabBar.activeElement = elementId
// compiler does not even enter this loop.
// for(var child in Layout.children){
// console.log("this is a child")
// }
}
}
}
In this case it is better to work with a Repeater since it has an associated index and use a model to set the properties:
SideBarElement.qml
import QtQuick 2.0
Item {
property alias icon: sideBarElementicon.source
property bool highlight: false
width: parent.width
Rectangle{
anchors.fill: parent
color: highlight ? Qt.rgba(1,1,0,1) : Qt.rgba(0,0,0,0)
}
Image {
id: sideBarElementicon
source: "genericIcon.png"
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
width: 50
height: 50
}
}
SideTabBar.qml
import QtQuick 2.0
import QtQuick.Layouts 1.11
Item {
id: sideTabBar
width: 70
height: parent.height
property int currentIndex: -1
ListModel{
id: elements
ListElement {
image: "../assets/product.svg"
}
ListElement {
image: "../assets/product.svg"
}
ListElement {
image: "../assets/product.svg"
}
ListElement {
image: "../assets/product.svg"
}
ListElement {
image: "../assets/product.svg"
}
ListElement {
image: "../assets/product.svg"
}
}
Rectangle{
anchors.fill: parent
color: "purple"
}
ColumnLayout{
id:sidebarLayout
anchors.fill: parent
spacing:2
Repeater{
model: elements
SideBarElement{
id: element
highlight: ix == currentIndex
icon: image
property int ix: index
Layout.preferredHeight: 70
Layout.alignment: Qt.AlignTop
MouseArea{
anchors.fill: parent
onClicked: currentIndex = ix
}
}
}
Item {Layout.fillHeight: true}
}
}

Is it possible to make a cycle swipe items in qml?

I use swipeview in qml. I can swipe items from first to final and back. Is it possible to swipe from final to first immediatly ? I didn't find any information in docs.
You can do that with PathView. Qt Quick Controls 2's Tumbler can also be made to wrap because it uses PathView internally.
You can use PathView. Some codes like this:
import QtQuick 2.0
Rectangle {
width: 200
height: 200
ListModel {
id: model
ListElement {
color: "red"
}
ListElement {
color: "green"
}
ListElement {
color: "blue"
}
}
Component {
id: delegate
Rectangle {
id: wrapper
width: view.width
height: view.height
color: model.color
Text {
anchors.centerIn: parent
font.pointSize: 26
font.bold: true
color: "white"
text: index
}
}
}
PathView {
id: view
anchors.fill: parent
snapMode: PathView.SnapOneItem
highlightRangeMode: PathView.StrictlyEnforceRange
currentIndex: -1
model: model
delegate: delegate
path: Path {
startX: -view.width / 2 // let the first item in left
startY: view.height / 2 // item's vertical center is the same as line's
PathLine {
relativeX: view.width * view.model.count // all items in lines
relativeY: 0
}
}
}
}

QML - Possible to display 3 listViews in a single view

Is it possible to display multiple listViews in a single page?
I have 3 seperate list views and I'd like to display them on a single page and I'm struggling to lay them out. They all overlap each other.
Simple example of the layout:
ListView {
id: listOne
property string headertitle: "list one header"
spacing: 5
header: headerComponent
model: ListOneModel
}
ListView {
id: listTwo
property string headertitle: "list two header"
spacing: 5
header: headerComponent
model: ListTwoModel
}
ListView {
id: listThree
property string headertitle: "list three header"
spacing: 5
header: headerComponent
model: ListThreeModel
}
Note that a Column with 3 ListViews in it will give you a rather odd scrolling experience, where you wouldn't be scrolling it all as if it is a single view, but scroll individual list views.
As long as you don't go crazy with the model sizes (and I mean like thousands), you can simply use a Flickable with a Column with 3 repeaters in it. This will give you a single continuous column you could scroll through.
The reason this solution will not be efficient for thousands of model items is that under normal circumstances, list view creates and destroys delegates as needed, and keeps created only what is visible on screen plus some optional caching. Whereas this solution will create all items, in order to get one uniform column to scroll through.
Here is a quick example demonstrating the 2 distinct behaviors:
Row {
anchors.fill: parent
Flickable {
width: parent.width * .5
height: parent.height
flickableDirection: Flickable.VerticalFlick
contentHeight: contentItem.childrenRect.height
Column {
spacing: 2
Repeater {
model: 5
delegate: Rectangle { width: 100; height: 100; color: "red" }
}
Repeater {
model: 5
delegate: Rectangle { width: 100; height: 100; color: "green" }
}
Repeater {
model: 5
delegate: Rectangle { width: 100; height: 100; color: "blue" }
}
}
}
Column {
width: parent.width * .5
height: parent.height
spacing: 2
ListView {
spacing: 2
width: parent.width
height: parent.height / 3
model: 5
clip: true
delegate: Rectangle { width: 100; height: 100; color: "red" }
}
ListView {
spacing: 2
width: parent.width
height: parent.height / 3
model: 5
clip: true
delegate: Rectangle { width: 100; height: 100; color: "green" }
}
ListView {
spacing: 2
width: parent.width
height: parent.height / 3
model: 5
clip: true
delegate: Rectangle { width: 100; height: 100; color: "blue" }
}
}
}
You can use Column:
import QtQuick 2.0
Rectangle {
width: 180; height: 200
id: root
Column {
ListView {
width: root.width; height: root.height/3
model: myModel
delegate: Text {
text: name + ": " + number
}
}
ListView {
width: root.width; height: root.height/3
model: myModel
delegate: Text {
text: name + ": " + number
}
}
ListView {
width: root.width; height: root.height/3
model: myModel
delegate: Text {
text: name + ": " + number
}
}
}
ListModel {
id: myModel
ListElement {
name: "Bill Smith"
number: "555 3264"
}
ListElement {
name: "John Brown"
number: "555 8426"
}
ListElement {
name: "Sam Wise"
number: "555 0473"
}
}
}

Change Text Color of the selected item in a ListView

Let me start by saying that I am pretty new to QML.
I have a ListView (with model and delegate), it works fine in my model but I would like to change the color (currently color: skin.gray) of the selected item to something else when the item is the currentIndex-item.
ListView {
id: menuBody_listview
width: parent.width
height: parent.height
currentIndex: 0
clip: true
highlight: highlighter
highlightFollowsCurrentItem: true
Behavior on opacity {
NumberAnimation { property: "opacity"; duration: 300; easing.type: Easing.InOutQuad }
}
anchors {
top: menuHeader_listview.bottom
bottom: parent.bottom
}
model: ListModel {
ListElement {
itemIconLeft: 'images/icons/menu/pause.png'
itemText: "Cancel"
itemIconRight: 'images/icons/menu/take-me-home.png'
}
ListElement {
itemIconLeft: 'images/icons/menu/pause.png'
itemText: "Mute"
itemIconRight: 'images/nill.png'
}
ListElement {
itemIconLeft: 'images/icons/menu/repeat.png'
itemText: "Repeate"
itemIconRight: 'images/nill.png'
}
}
delegate: MenuBodyItem {
width: menuBody_listview.width
anchors.horizontalCenter: parent.horizontalCenter
iconLeft: itemIconLeft
message: itemText
iconRight: itemIconRight
}
}
Following is the code for the item which is being populated, ManuBodyItem.qml.
Item {
width: 100
height: 50
property alias iconLeft: menuitem_icon_start.source
property alias message: menuitem_text.text
property alias iconRight: menuitem_icon_end.source
RowLayout {
spacing: 20
anchors.fill: parent
Image {
id: menuitem_icon_start
fillMode: Image.PreserveAspectCrop
anchors {
left: parent.left
verticalCenter: parent.verticalCenter
}
}
Text {
id: menuitem_text
anchors {
left: menuitem_icon_start.right
verticalCenter: parent.verticalCenter
verticalCenterOffset: -2
leftMargin: 20
}
color: skin.gray
font {
family: "TBD"
}
}
Image {
id: menuitem_icon_end
fillMode: Image.PreserveAspectCrop
source: iconRight
anchors {
right: parent.right
verticalCenter: parent.verticalCenter
}
}
}
}
Use ListView's isCurrentItem attached property:
Text {
id: menuitem_text
anchors {
left: menuitem_icon_start.right
verticalCenter: parent.verticalCenter
verticalCenterOffset: -2
leftMargin: 20
}
color: itemDelegate.ListView.isCurrentItem ? "red" : skin.gray
font {
family: "TBD"
}
}
Note that you have to give your root delegate item an ID in order to qualify the expression above:
Item {
id: itemDelegate
RowLayout {
// ...
}
// ...
}
You can see the same approach used in the example I linked to.
From your example:
color: skin.gray is used for the Text element which will change the color of the text and not it's background viz. i understood you want.
You can use a Rectangle element here which can act as a background component to set the background color.
So instead of Item root element in the delegate you can use Rectangle. So MenuBodyItem.qml will look as
Rectangle {
width: 100
height: 50
...
}
Now to set background color to the Rectangle if it is current one you can use ListView.isCurrentItem to check.
So,
Rectangle {
color: ListView.isCurrentItem ? "cyan" : "lightblue"
width: 100
height: 50
}
and now finally you will have to set the clicked item as the current one which can be done in the MouseArea of the Delegate Item
delegate: MenuBodyItem {
width: menuBody_listview.width
anchors.horizontalCenter: parent.horizontalCenter
iconLeft: itemIconLeft
message: itemText
iconRight: itemIconRight
MouseArea {
anchors.fill: parent
onClicked: menuBody_listview.currentIndex = index
}
}

Resources