Qt qml - how to use component in its definition? - c++

I have to implement TreeView in qml. Basically because each subtree is just TreeView itself, i want to use TreeView component in TreeView definition (this is that Repeater on the end).
This is part of code where i reference the component i am defining.
You can see that rootDelegate is actually id of the Component.
Problem is Qt gives error Unable to assign QQuickRow to QQmlComponent
Repeater {
model: childrens
delegate: rootDelegate
}
TreeView.qml
import QtQuick 2.0
Component {
id: rootDelegate
Column {
Row {
id: itemControl
spacing: 2
Rectangle {
anchors.verticalCenter: parent.verticalCenter
gradient: Gradient {
GradientStop { position: 0.0; color: "#EEEEEE" }
GradientStop { position: 1.0; color: "#404040" }
}
width: openChar.implicitWidth
height: openChar.implicitHeight - 6
radius: 3
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
}
Text {
id: openChar
text: "+"
color: "black"
anchors.centerIn: parent
}
}
Rectangle {
height: 1
color: "#A0A0A0"
width: 10
anchors.verticalCenter: parent.verticalCenter
}
Text {
text: model.text
color: "white"
}
}
Repeater {
model: childrens
delegate: rootDelegate
}
}
}

You are trying to use a Сomponent recursively in itself, it is not allowed in Qml

Related

Nested ListView in Qml

I am trying to achieve this output [Refer snapshot :
click here]
I tried Using, since I am new to Qt not sure whether my approach of using repeater is right or wrong.
ListView {
id: outer
model: model1
delegate: model2
anchors.fill: parent
}
Component {
id: model1
Item {
Column{
Repeater {
model: 3
Rectangle {
id: rect
anchors.top: parent.bottom
width: 300
height: 30
color: listColor2[index]
}
}
}
}
}
Component {
id: model2
Column{
Repeater {
model: 4
Rectangle {
id: rect
width: 150
height: 30
color: listColor[index]
}
}
}
}
I have found the solution to my problem.
Obtained output click here
Rectangle {
width: 360
height: 360
ListView {
id: outer
model: 4
delegate:
Rectangle {
id: rect
color: listColor[index]
width: 60
implicitHeight: col.height
Column{
id: col
anchors.left: rect.right
Repeater {
id: lv2
model: 4
Rectangle {
id: rect2
color: listColor2[index]
width: 200
height: 20
}
}
}
}
anchors.fill: parent
}
}

Provide activeFocus to Flickable

I have a QML component with a Flickable list and I need this Flickable to get activeFocus when I am clicking on it. I am trying to do it with MouseArea, but can't figure out how to make it work.
My tries:
FocusScope {
id: root
implicitHeight: 100
implicitWidth: 100
Flickable {
id: flickable
anchors.fill: parent
onActiveFocusChanged: console.log("Work!")
...
}
MouseArea {
anchors.fill: parent
onClicked: {
flickable.forceActiveFocus()
mouse.accepted = false
}
preventStealing: true
}
}
FocusScope {
id: root
implicitHeight: 100
implicitWidth: 100
MouseArea {
anchors.fill: parent
onClicked: flickable.forceActiveFocus()
Flickable {
id: flickable
anchors.fill: parent
onActiveFocusChanged: console.log("Work!")
...
}
}
}
In the first variant, my flickable is working, but MouseArea is not handling the click. In the second one, Flickable is not working, but MouseArea is handling the click.
So the question is how to correctly set activeFocus of Flickable on the click event?
Write id for your Flickable
and also Try this code :
import QtQuick 2.12
import QtQuick.Window 2.12
FocusScope {
id: root
width: 640
height: 480
Flickable {
id:flickable
width: parent.width
height: parent.height
contentHeight: mColumnId.implicitHeight
onActiveFocusChanged: console.log("Work!")
Column{
id : mColumnId
anchors.fill: parent
Rectangle {
color: "red"
width: parent.width
height: 200
Text {
anchors.centerIn: parent
text: "Element 1"
font.pointSize: 30
color : "white"
}
}
Rectangle {
color: "blue"
width: parent.width
height: 200
Text {
anchors.centerIn: parent
text: "Element 2"
font.pointSize: 30
color : "white"
}
}
Rectangle {
color: "yellow"
width: parent.width
height: 200
Text {
anchors.centerIn: parent
text: "Element 3"
font.pointSize: 30
color : "white"
}
}
}
MouseArea {
anchors.fill: parent
onClicked: {
flickable.forceActiveFocus()
mouse.accepted = false
preventStealing: true
}
}
}
}

QML How to dynamically access ListView items

I have a ListView which has dynamically added Items, and what I kinda want to know is how I could access items for example by index. Specifically, I want to have the color of the item rectangle change when I change the color using the Color Dialog. I guessed it should be maybe possible to first set a variable to the current item before calling the color dialog and then in the onAccepted method change the color of that item using the variable, but I don't know how to achieve anything of this in QML, because I am rather new to QML. Maybe you can offer even a cleaner way to change the color of the item's rectangle when the color dialog was closed (onAccepted). Thx for any help! :)
import QtQuick 2.0
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
import QtQuick.Dialogs 1.2
import QtQuick.Controls.Styles 1.4
Rectangle {
id: listViewContainer
width: parent.width/10*9;
height: 50
Behavior on height {
NumberAnimation {
duration: 100;
}
}
gradient: Gradient {
GradientStop {position: 0.0; color: "white" }
GradientStop {position: 1.0; color: "silver" }
}
radius: 5
ColorDialog {
id: colorDialog
title: "Please choose a color"
onAccepted: {
console.log("You chose: " + colorDialog.color)
Qt.quit()
}
onRejected: {
console.log("Canceled")
Qt.quit()
}
}
Component {
id: playerDelegate
Item {
anchors.left: parent.left
anchors.right: parent.right
height: 50
Column {
Text { text: '<b>Name:</b> ' + name }
Row {
MouseArea {
width: 20
height: 20
onClicked: {
colorDialog.visible = true;
playerColor = colorDialog.color;
//open color dialog
}
Rectangle {
radius: 3
anchors.fill: parent
color: playerColor
}
}
}
}
}
}
ListView {
id: playerListView
anchors.fill: parent
model:
ListModel {
id: playerListViewModel;
ListElement {
name: "Bill Smith"
playerColor: "red"
}
}
delegate: playerDelegate
}
Button {
id: addPlayerButton
anchors.top: playerListView.bottom
anchors.left: playerListView.left
anchors.right: playerListView.right
style: ButtonStyle {
label: Text {
text: "Add new player"
horizontalAlignment: Text.Center
}
}
onClicked: {
root.addnewPlayer(playerListView); //dont worry about this method
playerListViewModel.append({name: "Billy", playerColor: "blue"});
listViewContainer.height += 50;
}
}
}
Here is a sure fire way to make a working colorDialog --
in playerDelegate
Component {
id: playerDelegate
Item {
anchors.left: parent.left
anchors.right: parent.right
height: 50
Column {
Text {
text: '<b>Name:</b> ' + name
}
/* Object to store value from color selector */
Item {
id: colorSelector
property color color: "#000000"
onColorChanged: { playerColor = color; }
}
/* box to display color */
Rectangle {
//Layout.fillWidth: true
height: 120
width: 120
anchors.left: button.right
//Layout.alignment: Qt.AlignHCenter
color: colorSelector.color
border.width: 1
border.color: "#000000"
}
/* button to open dialog -- can be mousearea or other clickable object */
Button {
id: button
text: "Browse..."
onClicked: {
colorDialog.color = colorSelector.color
colorDialog.open()
}
}
/* actual color dialog for this delegate */
ColorDialog {
id: colorDialog
modality: Qt.ApplicationModal
title: "Please choose a color"
onAccepted: colorSelector.color = currentColor
}
}
}
}

How to Correctly Clear Qml ListView Selection

If I have the following:
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
ApplicationWindow {
title: qsTr("Hello World")
width: 800
height: 700
visible: true
property var myArray: [1, 2, 3, 4, 5, 6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
menuBar: MenuBar {
Menu {
title: qsTr("&File")
MenuItem {
text: qsTr("&Open")
onTriggered: messageDialog.show(qsTr("Open action triggered"));
}
MenuItem {
text: qsTr("E&xit")
onTriggered: Qt.quit();
}
}
}
Rectangle {
id: myButton
anchors.top: parent.top
anchors.topMargin: 5
color: "yellow"
width: 100
height: 25
radius: 3
anchors.horizontalCenter: parent.horizontalCenter
Text {
text: "Clear Selection"
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
MouseArea {
anchors.fill: parent
onClicked: {
myListView.currentIndex = -1
}
}
}
ListView {
id: myListView
width: 300
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: myButton.bottom
anchors.topMargin: 5
anchors.bottom: parent.bottom
currentIndex: -1
//highlightFollowsCurrentItem: false
highlight: Rectangle {
color: "pink"
radius: 3
width: parent.width - 10
height: 25
//y: myListView.currentItem.y
anchors.horizontalCenter: parent.horizontalCenter
}
clip: true
model: myArray
delegate: Rectangle {
width: parent.width - 10
height: 25
color: "transparent"
border.color: "cyan"
anchors.horizontalCenter: parent.horizontalCenter
Text {
text: myArray[index]
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
anchors.fill: parent
}
MouseArea {
anchors.fill: parent
onClicked: myListView.currentIndex = index
}
}
}
MessageDialog {
id: messageDialog
title: qsTr("May I have your attention, please?")
function show(caption) {
messageDialog.text = caption;
messageDialog.open();
}
}
}
When clicking the Clear Selection button I receive the following:
qrc:/main.qml:67: TypeError: Cannot read property of null
qrc:/main.qml:64: TypeError: Cannot read property of null
How can I clear the selection without getting the error? It doesn't appear to crash the application but I have a list view that changes based on another list view selection and the error occurs several times, cluttering up the debug output in Qt Creator. I have noticed this in Qt 5.4 and 5.5
The documentation for ListView says:
An instance of the highlight component is created for each list. The geometry of the resulting component instance is managed by the list so as to stay with the current item, unless the highlightFollowsCurrentItem property is false.
So you don't need to try to manage the position of the highlight item yourself. If you want to position the highlight, create an intermediate parent item instead:
highlight: Item {
Rectangle {
color: "pink"
radius: 3
width: parent.width - 10
height: 25
anchors.horizontalCenter: parent.horizontalCenter
}
}
As for why it happens, it's likely because the highlight item is reparented, leaving it in a state where its parent property is null. You can test this out with the following code:
anchors.horizontalCenter: { print(parent); parent.horizontalCenter }
The problem in general is that if you have a foo, which is supposed to have a bar, then you reference it as foo.bar, however, if foo was not properly initialized, then it cannot have a bar, since it does not exist (yet). In your case it seems that parent is not properly initialized, so it does not have a width and horizontalCenter (in the delegate, maybe), respectively. The solution is to initialize properly the object whose members are to be used, in our case, parent.
I had asked this question over on the Qt forum (https://forum.qt.io/topic/62328/clearing-a-qml-listview-selection) as well, but stack was quicker with a response. Checking the parent value works:
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
ApplicationWindow {
title: qsTr("Hello World")
width: 800
height: 700
visible: true
property int myMargin: 5
menuBar: MenuBar {
Menu {
title: qsTr("&File")
MenuItem {
text: qsTr("&Open")
onTriggered: messageDialog.show(qsTr("Open action triggered"));
}
MenuItem {
text: qsTr("E&xit")
onTriggered: Qt.quit();
}
}
}
Rectangle {
id: myButton
anchors.top: parent.top
anchors.topMargin: myMargin
color: "yellow"
width: 100
height: 25
radius: 3
anchors.horizontalCenter: parent.horizontalCenter
Text {
text: "Clear Selection"
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
MouseArea {
anchors.fill: parent
onClicked: {
myListView.currentIndex = -1
}
}
}
Rectangle {
width: 300
anchors.top: myButton.bottom
anchors.topMargin: myMargin
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
ListView {
id: myListView
anchors.fill: parent
currentIndex: -1
spacing: 3
highlightMoveDuration: 25
highlight: Rectangle {
width: parent ? parent.width - 10 : 0
height: parent ? 25 : 0
color: "pink"
radius: 3
anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined
}
clip: true
model: ListModel {
id: myArray
Component.onCompleted: {
for (var i = 1; i < 46; i++)
append({number: i})
}
}
delegate: Rectangle {
width: parent ? parent.width - 10 : 0
height: parent ? 25 : 0
color: "transparent"
border.color: "cyan"
anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined
Text {
text: number
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
anchors.fill: parent
}
MouseArea {
anchors.fill: parent
onClicked: {
myListView.currentIndex = index
}
}
}
}
}
MessageDialog {
id: messageDialog
title: qsTr("May I have your attention, please?")
function show(caption) {
messageDialog.text = caption;
messageDialog.open();
}
}
}

grid of MouseArea in Qt QML

I have made an Item in QT QML which contains a MouseArea element.
Here is the code,
import QtQuick 1.0
Rectangle {
id: base
width: 240
height: 320
x:0; y:0
color: "#323138"
/////////////////////// MAIN FOCUSSCOPE //////////////////////
FocusScope {
id: mainfocus
height: base.height; width: base.width
focus: true
/////////////////////// MAIN GRID ///////////////////////////
GridView {
id: maingrid
width: base.width-10; height: base.height-titlebar.height-10
x: 5; y: titlebar.height+5;
cellHeight: maingrid.height/3; cellWidth: maingrid.width/3-1
Component {
id: myicon
Rectangle {
id: wrapper
height: maingrid.cellHeight-10; width: maingrid.cellWidth-10
radius: 8; smooth: true
color: GridView.isCurrentItem ? "#c0d0c0" : "transparent"
focus: true
MouseArea {
id: clickable
anchors.fill: wrapper
hoverEnabled: true
//onClicked: func()
}
Image {
id: iconpic
source: "./ui6.svg"
anchors.centerIn: wrapper
}
Text {
id: iconname
color: wrapper.GridView.isCurrentItem ? "black" : "#c8dbc8"
anchors.top: iconpic.bottom; anchors.horizontalCenter: iconpic.horizontalCenter
text: name
}
}
}
model: 4
delegate: myicon
focus: true
}
}
//////////////////////// TITLEBAR ///////////////////////
Rectangle {
id: titlebar
x:base.x
y:base.y
height: 25; width: base.width
color : "#356f47"
Text {
color: "#fdfdfd"
anchors.centerIn: titlebar
text: "title"
}
}
}
I want to make a grid of such Items so that it gives me a grid of custom made click-able Items that I created which I can use for different functions.
Using the GridView element, I was able to make such a grid which used number of my custom made Items as a template.
The problem is that when I click anyone of these Items it executes a single function since there was only one MouseArea element in my Item. I am able to detect a click on an Item, but not able to uniquely determine which Item was clicked. How do I achieve this ?
Of course, I might be doing it wrong, so other suggestions are also welcome.
Thanks
When the GridView item creates the instances they inherit the index variable. This identifies the unique item.
MouseArea {
id: clickable
anchors.fill: wrapper
hoverEnabled: true
onClicked: {
maingrid.currentIndex=index;
switch (index)
{
case 0:
//Function or method to call when clicked on first item
break;
case 1:
//Function or method to call when clicked on second item
break;
default:
//Function or method to call when clicked on another item
break;
}
}
}
I hope it helps you!