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
}
}
}
}
Related
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
}
}
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.
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;
}
}
}
}
}
}
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);
}
}
}
}
I want to show a context menu when right-clicking on TableView rows. I tried this code:
import QtQuick 2.0
import QtQuick.Controls 1.0
TableView { id: tableView
width: 300
height: 200
TableViewColumn { role: 'a'; title: 'a'; width: 50 }
TableViewColumn { role: 'b'; title: 'b'; width: 50 }
model: ListModel {
ListElement { a: 1; b: 2 }
ListElement { a: 3; b: 4 }
ListElement { a: 5; b: 6 }
ListElement { a: 7; b: 8 }
ListElement { a: 9; b: 10 }
ListElement { a: 11; b: 12 }
}
Menu { id: contextMenu
MenuItem {
text: qsTr('Delete')
}
}
rowDelegate: Item {
Rectangle {
anchors {
left: parent.left
right: parent.right
verticalCenter: parent.verticalCenter
}
height: parent.height
color: styleData.selected ? 'lightblue' : 'white'
MouseArea {
anchors.fill: parent
propagateComposedEvents: true
onReleased: {
if (typeof styleData.row === 'number') {
tableView.currentRow = styleData.row
if (mouse.button === Qt.RightButton) { // never true
contextMenu.popup()
}
}
mouse.accepted = false
}
}
}
}
}
The context menu is not shown because the onReleased handler is not called for right-clicks.
I used propagateComposedEvents and mouse.accepted = false as suggested in the documentation here but it doesn't work anyway and I don't think that onReleased is a composed event.
I need help to make the code above work as expected.
Thank you.
Looks like this can be done easier:
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: {
console.log("Click")
if (mouse.button == Qt.LeftButton)
{
console.log("Left")
}
else if (mouse.button == Qt.RightButton)
{
console.log("Right")
}
}
}