How to add a editable TableView header in qml? - qt

import QtQuick 2.7
import QtQuick.Controls 1.3
import QtQuick.Controls.Styles 1.3
Rectangle {
width: 640
height: 480
ListModel {
id: tstModel
ListElement { animal: "dog" }
}
TableView {
id: tableView
anchors.fill: parent
model: tstModel
headerDelegate: Item{
height: 50
width: animalColumn.width
TextField{
text: styleData.value
anchors.fill: parent
}
}
TableViewColumn {
id: animalColumn
title: "Animal"
role: "animal"
width: 50
resizable: false
movable: false
}
}
}
This code is not acting as I expect. Textfield gets focus only when I am clicking the header with right button. And there is a Textfield works fine next to the first column header, but it's not what I want.
How to add a editable TableView header in qml?

I find this headerDelegate to be rather buggy or not supposed to be used in this scenario. I would rather implemnt a header from scrath to use for your use-case. Try this as a starting point:
Rectangle {
width: 640
height: 480
ListModel {
id: tstModel
ListElement { animal: "cat" }
ListElement { animal: "cat" }
ListElement { animal: "cat" }
ListElement { animal: "cat" }
ListElement { animal: "cat" }
ListElement { animal: "cat" }
ListElement { animal: "cat" }
}
TextField{
id: tableViewCustomHeader
property int curRow: tableView.currentRow
property bool isActual: curRow >= 0
function reloadText() { text = tstModel.get(curRow).animal }
function saveText() { tstModel.setProperty(curRow, "animal", text); tableView.model = tstModel; }
width: animalColumn.width
height: isActual ? 20 : 0
onCurRowChanged: {
if ( isActual >= 0 ) reloadText();
focus = true;
}
onTextChanged: if ( isActual >= 0 ) saveText()
}
TableView {
id: tableView
anchors {
top: tableViewCustomHeader.bottom
bottom: parent.bottom
left: parent.left
right: parent.right
}
model: tstModel
headerVisible: false
TableViewColumn {
id: animalColumn
title: "Animal"
role: "animal"
width: 200
resizable: false
movable: false
}
}
}
You can edit this anyway you want afterwards.
If it's a strict requirement to go with headerDelegate - this what I've end up with:
Rectangle {
width: 640
height: 480
ListModel {
id: tstModel
ListElement { animal: "dog" }
ListElement { animal: "cat" }
}
TableView {
id: tableView
anchors.fill: parent
model: tstModel
headerDelegate:
TextField{
property int curRow: tableView.currentRow
function reloadText() { text = tstModel.get(curRow).animal }
function saveText() { tstModel.setProperty(curRow, "animal", text); tableView.model = tstModel; }
onCurRowChanged: {
if ( curRow >= 0 ) reloadText()
}
onTextChanged: saveText()
width: parent.width
}
TableViewColumn {
id: animalColumn
title: "Animal"
role: "animal"
width: 200
resizable: false
movable: false
}
}
}
But, again, it works in a very strange way once you are adding TextField to it, so I would vote against it.

Related

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

How to make a cell editable in qt tableview

I try to make a cell editable using a tableview in qt. I have found a few examples and came up with the following:
TableView {
id: tableView
objectName: "tableView"
horizontalScrollBarPolicy: -1
selectionMode: SelectionMode.SingleSelection
Layout.minimumWidth: 300
Layout.fillHeight: true
Layout.fillWidth: true
model: trackableInfoModel
itemDelegate: Rectangle {
Text {
anchors.verticalCenter: parent.verticalCenter
text: styleData.value
}
MouseArea {
id: cellMouseArea
anchors.fill: parent
onClicked: {
if(styleData.column === 2){
//do something
}
}
}
}
From what I found it looks like I need an itemDelegate to paint each cell. Then I add a MouseArea to the cell and check which cell was selected. In my case I only need to react on the cells in column 2.
The thing is when I use the code shown above I get the error that:
JavaScipt blocks are not supported in a QT Quick UI form. (M223)
Because of that I tried to register a property alias for cellMouseArea like this:
property alias cellMouseArea : cellMouseArea
However that leads to this error:
qrc:/EditPageForm.ui.qml:24 Invalid alias reference. Unable to find id "cellMouseArea"
Overlay cell with TextInput on click.
import QtQuick 2.7
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
TableView {
id: tableView
objectName: "tableView"
horizontalScrollBarPolicy: -1
selectionMode: SelectionMode.SingleSelection
anchors.fill: parent
TableViewColumn {
id: titleColumn
title: "Title"
role: "title"
movable: false
resizable: false
width: tableView.viewport.width - authorColumn.width
}
TableViewColumn {
id: authorColumn
title: "Author"
role: "author"
movable: false
resizable: false
width: tableView.viewport.width / 3
}
model: ListModel {
id: libraryModel
ListElement {
title: "A Masterpiece"
author: "Gabriel"
}
ListElement {
title: "Brilliance"
author: "Jens"
}
ListElement {
title: "Outstanding"
author: "Frederik"
}
}
itemDelegate: Rectangle {
Text {
anchors { verticalCenter: parent.verticalCenter; left: parent.left }
color: "black"
text: styleData.value
}
MouseArea {
id: cellMouseArea
anchors.fill: parent
onClicked: {
// Column index are zero based
if(styleData.column === 1){
loader.visible = true
loader.item.forceActiveFocus()
}
}
}
Loader {
id: loader
anchors { verticalCenter: parent.verticalCenter; left: parent.left}
height: parent.height
width: parent.width
visible: false
sourceComponent: visible ? input : undefined
Component {
id: input
TextField {
anchors { fill: parent }
text: ""
onAccepted:{
// DO STUFF
loader.visible = false
}
onActiveFocusChanged: {
if (!activeFocus) {
loader.visible = false
}
}
}
}
}
}
}
}

How Navigate only on Items of current index of ListView?

I have a ListView that has many rows , each row has few Items, i want to select one row by up and down keys and then select highlighted row by space or enter key and navigate on its items from first button by up and down keys, how is it possible?
here is my code:
import QtQuick 2.6
import QtQuick.Controls 1.5
import QtQuick.Controls.Styles 1.4
ApplicationWindow {
visible: true
width: 400
height: 480
title: qsTr("Hello World")
Rectangle {
anchors.fill: parent
ListModel
{
id:myModel
ListElement
{
text1:"btn1"
text2:"btn2"
text3:"btn3"
}
ListElement
{
text1:"btn1"
text2:"btn2"
text3:"btn3"
}
ListElement
{
text1:"btn1"
text2:"btn2"
text3:"btn3"
}
}
ListView {
id: list
anchors.fill: parent;
model: myModel
currentIndex: 0
focus: true
delegate: Rectangle {
id: delegateItem
height: 100
width: parent.width;
color: "blue"
Row{
anchors.fill: parent
Button
{
text: model.text1
height: parent.height
onFocusChanged:
{
if(focus)
text="selected"
else
text= model.text1
}
}
Button
{
text: model.text1
height: parent.height
onFocusChanged:
{
if(focus)
text="selected"
else
text= model.text3
}
}
Button
{
text: model.text1
height: parent.height
onFocusChanged:
{
if(focus)
text="selected"
else
text= model.text3
}
}
}
onFocusChanged:
{
if(focus)
delegateItem.color="red"
else
delegateItem.color="blue"
}
}
Keys.onDownPressed: {
if (list.currentIndex + 1 < list.count )
list.currentIndex += 1;
}
Keys.onUpPressed: {
if (list.currentIndex >= 0)
list.currentIndex -= 1;
}
Keys.onEnterPressed:
{
list.currentItem.forceActiveFocus()
}
}
}
}
Using your example, you can select rows by navigating with the arrow keys, and give focus to an individual button by pressing tab until you get to the one you're interested in. Space activates a button once it has focus.
Comparing your answer with the information you added in your third edit, the cleaner way would be to give each button an id and refer to that. That is, rather than do this:
KeyNavigation.down: list.currentItem.children[0].children[1]
which is kinda fragile and difficult to read, do this:
KeyNavigation.down: button2
For navigating on first button of selected row, you should use list.currentItem.children here is modified codes
import QtQuick 2.6
import QtQuick.Controls 1.5
ApplicationWindow {
visible: true
width: 400
height: 480
title: qsTr("Hello World")
Rectangle {
anchors.fill: parent
ListModel {
id: myModel
ListElement {
text1: "btn1"
text2: "btn2"
text3: "btn3"
}
ListElement {
text1: "btn1"
text2: "btn2"
text3: "btn3"
}
ListElement {
text1: "btn1"
text2: "btn2"
text3: "btn3"
}
ListElement {
text1: "btn1"
text2: "btn2"
text3: "btn3"
}
ListElement {
text1: "btn1"
text2: "btn2"
text3: "btn3"
}
ListElement {
text1: "btn1"
text2: "btn2"
text3: "btn3"
}
ListElement {
text1: "btn1"
text2: "btn2"
text3: "btn3"
}
}
ListView {
id: list
anchors.fill: parent
model: myModel
currentIndex: 0
focus: true
delegate: Rectangle {
id: delegateItem
height: 100
width: parent.width
color: "blue"
Row {
anchors.fill: parent
Button {
text: model.text1
height: parent.height
onFocusChanged: {
if (focus)
text = "selected"
else
text = model.text1
}
KeyNavigation.down: list.currentItem.children[0].children[1]
}
Button {
text: model.text1
height: parent.height
onFocusChanged: {
if (focus)
text = "selected"
else
text = model.text3
}
KeyNavigation.down: list.currentItem.children[0].children[2]
KeyNavigation.up: list.currentItem.children[0].children[0]
}
Button {
text: model.text1
height: parent.height
onFocusChanged: {
if (focus)
text = "selected"
else
text = model.text3
}
KeyNavigation.up: list.currentItem.children[0].children[1]
}
}
onFocusChanged: {
if (focus)
delegateItem.color = "red"
else
delegateItem.color = "blue"
console.log(list.currentItem.children[0].children[0].focus)
}
Keys.onDownPressed:
{
if (list.currentIndex + 1 < list.count)
list.currentIndex += 1
}
Keys.onUpPressed:
{
if (list.currentIndex -1 > -1)
list.currentIndex -= 1
}
Keys.onSpacePressed: {
var focus=list.currentItem.children[0].children[children_index].focus
list.currentItem.children[0].children[children_index].focus
= !focus
if(focus)
list.currentItem.focus=true
console.log("entered: "+list.currentItem.children[0].children[0].focus)
}
property int children_index: 0
}
}
}
}

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

ListView issue in QML

I'm trying to develop an application which has multi-layered navigation in drop-downs.
Below is the snapshot of the requirement. On clicking QSR only the subitems of QSR should pop out with proper alignment.
But with my implementation, I'm getting following result. The pop out window is not aligned, but extending itself to the list.
Below is the my code snippet
import QtQuick 1.1
Item {
width: 500
height: 300
ListView {
anchors.fill: parent
model: nestedModel
delegate: categoryDelegate
}
ListModel {
id: nestedModel
ListElement {
categoryName: "QSR"
collapsed: true
subItems: [
ListElement { itemName: "KFC" },
ListElement { itemName: "Mc Donalds" },
ListElement { itemName: "Pizza Hut" },
ListElement { itemName: "Brain's" }
]
}
ListElement {
categoryName: "Drinks"
collapsed: true
subItems: [
ListElement { itemName: "Pepsi" },
ListElement { itemName: "Coke" },
ListElement { itemName: "7up" },
ListElement { itemName: "Bacardi" }
]
}
}
Component {
id: categoryDelegate
Column {
width: 200
Rectangle {
id: categoryItem
border.color: "black"
border.width: 5
color: "white"
height: 50
width: 200
anchors.left: parent.right
Text {
anchors.right: parent.right
x: 15
font.pixelSize: 24
text: categoryName
}
MouseArea {
anchors.fill: parent
onClicked: nestedModel.setProperty(index, "collapsed", !collapsed)
}
}
Loader {
id: subItemLoader
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 {
color: "#cccccc"
height: 40
width: 200
border.color: "black"
border.width: 2
Text {
anchors.verticalCenter: parent.verticalCenter
x: 30
font.pixelSize: 18
text: itemName
}
}
}
}
}
}
Any help to achieve original requirement will be appreciable.
Have a close look at the delegate for your main list view: It's Column (put items on top of each over) of the main menu item and Loader for the popup menu. Obviously as soon as you load a popup menu it's displayed under its corresponding menu item in the list.
To get the behavior you intended you have to move the Loader for the popup menu out of the ListView:
import QtQuick 1.1
Item {
width: 400
height: 300
Row {
anchors.fill: parent
Loader {
id: subItemLoader
width: 200
height: parent.height
property variant subItemModel: null
sourceComponent: subItemModel == null? null: subItemColumnDelegate
function setModel() {
if (status == Loader.Ready) item.model = subItemModel
}
onStatusChanged: setModel()
onSubItemModelChanged: setModel()
}
ListView {
width: 200
height: parent.height
model: nestedModel
delegate: categoryDelegate
}
}
ListModel {
id: nestedModel
ListElement {
categoryName: "QSR"
subItems: [
ListElement { itemName: "KFC" },
ListElement { itemName: "Mc Donalds" },
ListElement { itemName: "Pizza Hut" },
ListElement { itemName: "Brain's" }
]
}
ListElement {
categoryName: "Drinks"
subItems: [
ListElement { itemName: "Pepsi" },
ListElement { itemName: "Coke" },
ListElement { itemName: "7up" },
ListElement { itemName: "Bacardi" }
]
}
}
Component {
id: categoryDelegate
Rectangle {
id: categoryItem
border.color: "black"
border.width: 5
color: "white"
height: 50
width: 200
Text {
anchors.centerIn: parent
x: 15
font.pixelSize: 24
text: categoryName
}
MouseArea {
anchors.fill: parent
onClicked: {
if (subItemLoader.subItemModel != subItems)
subItemLoader.subItemModel = subItems
else
subItemLoader.subItemModel = null
}
}
}
}
Component {
id: subItemColumnDelegate
Column {
property alias model : subItemRepeater.model
width: 200
height: 500
Repeater {
id: subItemRepeater
delegate: Rectangle {
color: "#cccccc"
height: 40
width: 200
border.color: "black"
border.width: 2
Text {
anchors.verticalCenter: parent.verticalCenter
x: 30
font.pixelSize: 18
text: itemName
}
}
}
}
}
}

Resources