TreeView focus/selection and button/mouse area delegate - delegates

I have a TreeViewand I have an image with a MouseArea in one of the columns. By clicking on it, the focus (selection, highlighting?) doesn't move to the string because the MouseArea is above the TreeView (as far as I understand)
Here is the code:
TreeView
{
clip: true id: mapsTreeView
objectName: "mapsTreeView"
model: theModel
TableViewColumn {
width: 100
role: "name_role"
title: "Map"
}
TableViewColumn {
width: 50
role: "description_role"
}
TableViewColumn {
id: imageColumn
width: 20
role: "image_role"
delegate: Item {
MouseArea {
anchors.fill: parent
onClicked: {
mapsTreeView.sigChangeState()
}
}
Image {
anchors.fill: parent
width: 5
source: "icon" + styleData.value + ".png"
}
}
}
signal sigChangeState()
}
}
The same story applies to the button:
TableViewColumn {
id: imageColumn
width: 20
role: "image_role"
delegate: Button {
iconSource: "icon" + styleData.value + ".png"
onClicked: mapsTreeView.sigChangeState()
}
}
When I click on the button, the focus doesn't moves to the string that contains button.
So the question is, how to make the image/button delegate so that by clicking on it focus will move to the string that contains this object, and some signal is emitted.
In ListView, all I had to do was simply the following:
onClicked:{
mapsView.currentIndex=model.index
mapsState.sigChangeState()
}
But TreeView doesn't allow one to write CurrentIndex

Related

Swipview laggy on swiping

I have bad problem on my qml code performance, laggy when swiping between "Inbox" and "MyBoxes", code is simple but...
Ok, here is my code, main:
Loader {
id: loader
anchors.fill: parent
sourceComponent: splash
}
Component {
id: splash
Splash {
percent: l_i.load
fin: ()=>{
loader.sourceComponent = swip_cmp
}
}
}
Component {
id: swip_cmp
Swip {
}
}
Swip.qml:
Page {
SwipeView {
id: swipeView
topPadding: 10
anchors.fill: parent
currentIndex: tabBar.currentIndex
Inbox {
title: "Inbox"
}
MyBoxes {
title: "MyBoxes"
}
}
header: Navigation {
id: tabBar
pageIndex: swipeView.currentIndex
implicitHeight: 50
width: parent.width
anchors.top: head.bottom
anchors.topMargin: 0
tabs:[
NavButton { text: "Inbox"; icon.source: "../assets/Inbox.png" },
NavButton { text: "MyBoxes"; icon.source: "../assets/Box.png" },
NavButton { text: "Leitners"; icon.source: "../assets/Cards.png" }
]
}
}
MyBoxes.ui.qml:
Page {
Rectangle{
id: page
width: parent.width * .9
anchors.horizontalCenter: parent.horizontalCenter
Column {
spacing: 5
Box {
width: page.width
active: true
title: "504"
totalwords: "504"
details: "Lorem ipsum is placeholder text commonly used in the graphic, print, and publishing industries for previewing layouts and visual mockups."
}
Box {
width: page.width
title: "504"
totalwords: "504"
details: "Lorem ipsum is placeholder text commonly used in the graphic, print, and publishing industries for previewing layouts and visual mockups."
}
}
}
}
Box.qml:
Item {
id: item2
property string title: "title"
property string totalwords: "totalwords"
property string details: "details"
property string src: "src"
property bool online: false
property bool active: false
height: head.contentHeight+det.contentHeight + 50
Rectangle {
id: bodybg
anchors.fill: parent
color: "#FFFFFF"
Text {
id: head
color: "#373737"
text: title
font.bold: true
font.pointSize: 14
anchors.leftMargin: 5
anchors.topMargin: 5
anchors.left: parent.left
anchors.top: parent.top
}
Text {
id: tw
color: "#777777"
text: totalwords
font.bold: true
font.pointSize: 10
anchors.top: parent.top
anchors.topMargin: 5
anchors.right: parent.right
anchors.rightMargin: 5
}
Rectangle {
id: hr
width: parent.width * .9
height: 1
color: "#707070"
anchors.top: head.bottom
anchors.topMargin: 5
anchors.horizontalCenter: parent.horizontalCenter
}
Text {
id: det
width: parent.width
color: "#222222"
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
text: details
anchors.margins: 5
anchors.top: hr.bottom
anchors.right: parent.right
anchors.left: parent.left
}
Button {
id: add
width: 64
height: 26
text: online ? "Download" : (active ? "Deactive" : "Active")
anchors.right: parent.right
anchors.top: det.bottom
anchors.rightMargin: 5
anchors.bottomMargin: 5
contentItem: Rectangle {
id: rectangle
anchors.fill: parent
color: (active ? "#BC0C52" : "#00C193")
Text {
text: add.text
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
color: "#FFFFFF"
}
}
}
Text {
id: delt
visible: !online
color: "#BC0C52"
text: "Delete"
anchors.verticalCenter: add.verticalCenter
anchors.right: add.left
anchors.rightMargin: 10
font.underline: true
}
}
DropShadow {
anchors.fill: bodybg
samples: 17
color: "#80000000"
source: bodybg
}
}
I have no matter cpp code yet!
It's mostly code:|
I think Box.qml must optimize, or may problem be because of long texts in MyBoxes.ui.qml
Or maybe I should change compile configuration, here is qmake:
-spec android-clang "CONFIG+=debug" "CONFIG+=qml_debug" ANDROID_ABIS="armeabi-v7a" && D:/Android/SDK/ndk/21.1.6352462/prebuilt/windows-x86_64/bin/make.exe qmake_all
You can try setting cached: true on the DropShadow:
This property allows the effect output pixels to be cached in order to improve the rendering performance. Every time the source or effect properties are changed, the pixels in the cache must be updated. Memory consumption is increased, because an extra buffer of memory is required for storing the effect output.
It is recommended to disable the cache when the source or the effect properties are animated.
By default, the property is set to false.
https://doc.qt.io/qt-5/qml-qtgraphicaleffects-dropshadow.html#cached-prop

How to add an onClick event to a QML TreeView

I was implementing the example, shown at: http://imaginativethinking.ca/how-to-use-qt-quicks-treeview/
I want to add an event handler that reacts, if I click on a tree view item.
The following does not work:
TreeView {
anchors.fill: parent
model: theModel
itemDelegate: Rectangle {
color: ( styleData.row % 2 == 0 ) ? "white" : "lightgrey"
height: 20
Text {
anchors.verticalCenter: parent.verticalCenter
text: styleData.value === undefined ? "" : styleData.value // The branches don't have a description_role so styleData.value will be undefined
}
// console.log("Saving the current project...");
}
TableViewColumn {
role: "name_role"
title: "Name"
width: 110
}
TableViewColumn {
role: "description_role"
title: "Description"
width: 570
}
onCurrentItemChanged: console.log("Running test..")
}
I get the error message:
Cannot assign to non-existent property "onCurrentItemChanged"
Any idea how to add such an event handler?
The following code works:
import QtQuick 2.4
import QtQuick.Controls 1.4
import QtQuick.Window 2.2
import ca.imaginativethinking.tutorials.models 1.0
Item {
width: 480
height: 410
MyTreeModel {
id: tests
}
// #disable-check M300
TreeView {
anchors.fill: parent
model: tests
itemDelegate: Rectangle {
color: ( styleData.row % 2 == 0 ) ? "white" : "lightgrey"
height: 20
Text {
anchors.verticalCenter: parent.verticalCenter
text: styleData.value === undefined ? "" : styleData.value // The branches don't have a description_role so styleData.value will be undefined
}
// console.log("Saving the current project...");
}
TableViewColumn {
role: "name_role"
title: "Name"
width: 110
}
TableViewColumn {
role: "description_role"
title: "Description"
width: 570
}
onClicked: {
if (index.parent.row >= 0) {
console.log(index.parent.row, index.row)
console.log(tests.data(index))
}
}
}
}
Instead of using onCurrentItemChanged I use the signal onClicked. I can access the index of the item with index.parent.row and index.row. I can access the content with tests.data(index), where tests is the name of the Model (was named theModel in the question).
I think is better to include a mouse area inside your item delegate, so you can get the onlclick event in each item instead in the whole tree. Something like this:
itemDelegate: MouseArea{
Rectangle {
anchors.fill: parent
color: ( styleData.row % 2 == 0 ) ? "white" : "lightgrey"
height: 20
Text {
anchors.verticalCenter: parent.verticalCenter
text: styleData.value === undefined ? "" : styleData.value // The branches don't have a description_role so styleData.value will be undefined
}
// console.log("Saving the current project...");
}
onClicked: {
console.log(styleData.index)
console.log(tests.data(styleData.index))
}
}

How do I emit signal while clicking TableViewColumn?

I would like to add a MouseArea/Button to a TableViewColumn to perform specific tasks. However, if I add one of the above type, it overrides the "click" event of TableViewColumn so that I lose row selection.
Here is an example code. The row is not switching when I click it in the area of the last column:
TreeView {
clip: true id: mapsTreeView
objectName: "mapsTreeView"
model: theModel
TableViewColumn {
width: 100
role: "name_role"
title: "Map"
}
TableViewColumn {
width: 50
role: "description_role"
}
TableViewColumn {
id: imageColumn
width: 20
role: "image_role"
delegate: Item {
MouseArea {
anchors.fill: parent
onClicked: {
mapsTreeView.sigChangeState()
}
}
Image {
anchors.fill: parent
width: 5
source: "icon" + styleData.value + ".png"
}
}
}
signal sigChangeState()
}
Maybe there is a better solution, but this works for me:
MouseArea {
anchors.fill: parent
onContainsPressChanged: {
if(containsPress)
{
console.log("PRESSED")
}
}
onPressed: {
mouse.accepted = false
}
}

Get data from a specific column in a TableView QML

I'm trying to get data from a specific column when the row is selected.
For exemple, when the user selects the first row, I need to retrieve the value of the column "Image source". Many thanks!!
main.qml
TableView {
onClicked: {
console.log("value "+ column2.value )
}
id:tablev
model: mySQLmodel
anchors.margins: 12
anchors.fill: parent
TableViewColumn {
id: column1
role: "Title"
title: "Title"
width: 120
}
TableViewColumn {
id: column2
role: "Credit"
title: "Credit"
width: 120
}
TableViewColumn {
id: column14
role: "Image"
title: "Image source"
width: 120
}
itemDelegate: Text
{
text: styleData.value
elide: Text.ElideRight
} }}}
Assume you are using TableView with model.
ListModel {
id: libraryModel
ListElement{ title: "A title 1" ; credit: "N/A"; source: "http://someurl.com" }
ListElement{ title: "A title 2" ; credit: "N/A"; source: "http://someurl.com" }
ListElement{ title: "A title 3" ; credit: "N/A"; source: "http://someurl.com" }
}
TableView {
TableViewColumn{ role: "title" ; title: "Title" ; width: 100 }
TableViewColumn{ role: "credit" ; title: "Credit" ; width: 200 }
TableViewColumn{ role: "source" ; title: "Image source" ; width: 200 }
model: libraryModel
}
So you can add onClick event to the view in that way:
onClicked: {
console.log(libraryModel.get(row).source);
}
when row is the selected row passed to onClicked by engine
[Solved]
I use the function bellow and works great:
QVariantMap Model::get(int idx) const {
QVariantMap map;
foreach(int k, roleNames().keys()) {
map[roleNames().value(k)] = data(index(idx, 0), k);
}
return map;
}
Happy codding :)
You could add something like:
`
TableView {
itemDelegate: Item {
MouseArea {
anchors.fill: parent
onClicked: {
console.log("row: " + styleData.row + " column: " + styleData.column + " value: " + styleData.value)
}
}
}
}
`

Search in Qml ListView contact model

What I have is a listview, to show list of contacts. Also, there is a search box and a label. Based on the text typed in the search box, the contact list will be filtered.
Here is my code:
import QtQuick 1.1
import com.nokia.symbian 1.1
import com.nokia.extras 1.1
import QtMobility.contacts 1.1
Window {
id: window
StatusBar {
id: statusBar
anchors.top: window.top
Text {
id: statusBarTitle
text: "Contacts"
color: "#ffffff"
}
}
ContactModel {
id: contactModel
filter:
IntersectionFilter {
DetailFilter {
detail: ContactDetail.PhoneNumber
field: PhoneNumber.PhoneNumber
value: PhoneNumber.Mobile
}
UnionFilter {
DetailFilter {
detail: ContactDetail.Name
field: Name.FirstName
value: searchbox.searchText
matchFlags: Filter.MatchStartsWith
}
DetailFilter {
detail: ContactDetail.Name
field: Name.LastName
value: searchbox.searchText
matchFlags: Filter.MatchStartsWith
}
DetailFilter {
detail: ContactDetail.DisplayLabel
field: DisplayLabel.Label
value: searchbox.searchText
matchFlags: Filter.MatchStartsWith
}
}
}
sortOrders:
SortOrder {
detail: ContactDetail.Name
field: Name.FirstName
direction: Qt.AscendingOrder
}
}
Component {
id: contactListDelegate
ListItem {
id: listItem
Image {
id: avatar
source: contact.thumbnail
sourceSize.width: 60
sourceSize.height: 60
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
}
ListItemText {
id: nameText
text: contact.name.firstName + " " + contact.name.lastName
color: "white"
anchors.left: avatar.right
anchors.leftMargin: 10
font.family: "Helvetica"
anchors.verticalCenter: parent.verticalCenter
}
}
}
ListView {
id: listView
anchors.top: searchbox.bottom
anchors.right: parent.right
anchors.left: parent.left
anchors.bottom: toolBar.top
clip: true
model: contactModel
delegate: contactListDelegate
visible: true
}
SearchBox {
id: searchbox
anchors.top: statusBar.bottom
placeHolderText: "Search Contact"
onSearchTextChanged: {
searchingBusyIndicator.running = true
searchingBusyIndicator.visible = true
searchTimeoutTimer.restart()
}
}
Label {
id: noMatchesLabel
anchors.centerIn: listView
visible: false
text: "No matches"
}
BusyIndicator{
id: searchingBusyIndicator
anchors.centerIn: parent
platformInverted: window.platformInverted
width: 80
height: 80
visible: false
}
Timer{
id: searchTimeoutTimer
interval: 1000
onTriggered: {
searchingBusyIndicator.running = false
searchingBusyIndicator.visible = false
}
}
ToolBar {
id: toolBar
anchors.bottom: window.bottom
tools: ToolBarLayout {
id: toolBarLayout
ToolButton {
flat: true
iconSource: "toolbar-back"
onClicked: {
Qt.quit()
}
}
ToolButton {
flat: true
iconSource: "toolbar-search"
}
}
}
}
}
Now I need to change the visible property of the list view to false & the label property to true, when there is no matches in the list. How to achieve that.?
What's happening now is, the application crashes and terminates when there is no matches.
I spent 2 days while find solution of this problem...
here is my fix:
ContactModel {
...........
onRowsInserted: {
if(last === 0)
{
noMatchesLabel.visible = true;
listView.model = {};
}
else
{
noMatchesLabel.visible = false;
listView.model = contactModel;
}
}
While the contactModel haven't contacts because of using filters, we swap the model of listView to empty one. In that way the app doesn't crash

Resources