QML: How to set coordinates inside Repeater - qt

I have an issue with setting coordinates inside Repeater:
import QtQuick
Window {
id: mainWindow
property int wi: 640
property int he: 500
width: wi
height: he
visible: true
title: qsTr("Game")
Rectangle {
id: gameWindow
width: wi/1.6
height: he
anchors.right: parent.right
visible: true
color: "black"
clip: true
Grid {
id: gameGrid
columns: 25
spacing: 0
rows: 32
anchors.fill: parent
Repeater {
model: 600
Rectangle {
width: wi/40
height: 20
border.width: 2
color: "grey"
}
}
}
Grid {
id: sGrid
columns: gameGrid.columns
spacing: gameGrid.spacing
rows: gameGrid.rows
anchors.fill: gameGrid
Repeater {
model: 5
Rectangle {
// anchors.horizontalCenter: sGrid.horizontalCenter
// anchors.verticalCenter: sGrid.verticalCenter
// x: (wi/2) + (index * (wi/40) )
// y: he/2
width: wi/40
height: 20
border.width: 1
color: "red"
}
}
}
}
}
Whole code above, but my question is about the second Repeater with 5 Rectangles.
I have tried to solve that with many ways. Most obvious seemed to me placing coordinates inside Repeater, but now I know it does not work like this - I have to place coordinates somehow inside Rectangle. I have commented code, where are the ways I have tried to solve this.
Anchors work very well - it places the first element exactly where I am expecting.
Problem appears with the next elements. They are placing inside the same element of Grid. I do not understand why the coordinates does not working. Documentation shows I could use "index", don't know, maybe the point is that's "read only" property? I have tried to set Rectangle with prefix "delegate:" with the same result as well.

In your question, you mention you have Grid + Repeater + Rectangle. I am not sure what you want to achieve, but, it feels like you may have better luck by going GridView + Rectangle because GridView supports a model.
Since you want coordinate control of your Rectangles, it is possible to do this alone with Repeater + Rectangle. No need for Grid since the Grid will impact the coordinate system of your Rectangle.
Below illustrates how you can use a simple ListModel to control the placement of your Rectangles:
import QtQuick
import QtQuick.Controls
Page {
Repeater {
model: ListModel {
ListElement { p:100; q:100; w:50; h:50; c:"red"; o:0 }
ListElement { p:200; q:100; w:50; h:50; c:"green"; o:15 }
ListElement { p:300; q:200; w:50; h:50; c:"blue"; o:30 }
ListElement { p:300; q:300; w:50; h:50; c:"orange"; o:45 }
ListElement { p:200; q:400; w:50; h:50; c:"purple"; o:60 }
}
delegate: Rectangle {
x: p
y: q
width: w
height: h
color: c
rotation: o
}
}
}
You can Try it Online!
[EDIT]
With the following, it shows how you could use index in 10 delegates to place your rectangles using a formula:
import QtQuick
import QtQuick.Controls
Page {
Repeater {
model: 10
delegate: Rectangle {
x: 100 + (index % 4) * 100
y: 100 + Math.floor(index / 4) * 100
width: 50
height: 50
color: ["green","red","orange","blue","purple"][index%5]
rotation: index * 10
Text {
anchors.centerIn: parent
text: index
color: "white"
}
}
}
}
You can Try it Online!

Related

Looking for alternate function to QML ListView's itemAtIndex due to version conflict

I'm using Qt 5.12, so I can't access ListView's itemAtIndex which was introduced in Qt 5.13.
I can't upgrade Qt due to my project/platform related restrictions. Is there a way to find the item at a given index for ListView with the Qt versions prior to 5.13?
Otherwise, is there a way to get mouse positions of an item based on index?
I'm having a listview with adjacent items having different width(alternate items have same width). I'm trying to access listview's item which is of less width compared to the adjacent item. The space between two items in the above picture is also an item which is marked as dummy. I'm able to get the index of each item (both actual & dummy), but the x position I get seems to be incorrect as the rectangle cursor is not getting placed in the intended item's position.
Please suggest alternatives that gives the similar functionality as itemAtIndex. Thanks.
In the following example, I declare a MouseArea in each delegate. So, once the mouse hovers over that delegate, we trigger MouseArea.onEntered and can know which item, because that delegate will have the corresponding index value:
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Page {
background: Rectangle { color: "#848895" }
ColumnLayout {
anchors.fill: parent
ListView {
id: listView
Layout.fillWidth: true
Layout.preferredHeight: 150
model: 20
orientation: ListView.Horizontal
delegate: MyDelegate { }
ScrollBar.horizontal: ScrollBar {
height: 20
policy: ScrollBar.AlwaysOn
}
highlight: Item {
z: 2
Rectangle {
width: 10
height: parent.height
color: "lightsteelblue"
border.color: "black"
}
}
}
Item {
Layout.fillWidth: true
Layout.fillHeight: true
Frame {
anchors.centerIn: parent
background: Rectangle { }
Text {
text: qsTr("ListView.currentIndex = %1").arg(listView.currentIndex)
}
}
}
}
}
// MyDelegate.qml
import QtQuick
import QtQuick.Controls
Rectangle {
property ListView listView: ListView.view
width: 120
height: listView.height - 20
implicitWidth: width
implicitHeight: height
color: "transparent"
Rectangle {
border.color: "grey"
color: "white"
y: 20
height: parent.height - y * 2
width: parent.width
Text {
anchors.centerIn: parent
text: qsTr("Item %1").arg(modelData + 1)
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: listView.currentIndex = index
}
}
You can Try it Online!

Checkbox becomes big when clicked on in QML tableview

This code does produce checkboxes in a tableview but when I click on the checkbox it becomes big. I want it to remain of a constant size.
Please guide.
import QtQuick 2.0
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.1
Rectangle
{
id: rightside
anchors.fill: parent
height: parent.height
width: 1500
TableView
{
anchors.fill: parent
TableViewColumn
{
role: "selectall"
title: "Select All"
width: 100
delegate: CheckBox
{
anchors.fill: parent
checked: false
}
}
TableViewColumn {
role: "size"
title: "Size"
width: 100
}
TableViewColumn
{
role: "last_updated"
title: "Last Updated"
width: 100
delegate: Component
{
Rectangle
{
height: 100
width: 120
id: head
RowLayout
{
height: parent.height
width: parent.width
Rectangle
{
height: 20
width: 20
color: "red"
border.color: "black"
radius: 100
MouseArea
{
anchors.fill: parent
onClicked: parent.color = "grey"
}
}
}
}
}
}
model: ListModel
{
id: mymodel
ListElement { text: "Banana" }
ListElement { text: "Apple" }
ListElement { text: "Coconut" }
}
}
}
There are lots of way to solve your problem. But first, let's do proper distinction between Qt Qtuick Controls versions. To do it, use this import statement:
import QtQuick.Controls 1.4 as QC1
And respectively use all components that requires QC1, e.g.: QC1.TableView, QC1.TableViewColumn.
In your example you are getting overlapping of components. To avoid it in terms of QC1 you can define a higher row delegate for your TableView. But this discards the default style. Simple example of its usage with style goes here:
rowDelegate: Rectangle {
height: 30
SystemPalette {
id: myPalette
colorGroup: SystemPalette.Active
}
color: {
var baseColor = styleData.alternate ? myPalette.alternateBase : myPalette.base
return styleData.selected ? myPalette.highlight : baseColor
}
}
As result you'll get this:
Another option in terms of QC2 is to redefine indicator style of CheckBox. Below you'll find an example that could possibly fit your app, based on Customizing CheckBox documentation; so your CheckBox delegate will look like this:
delegate: CheckBox {
id: control
anchors.fill: parent
checked: false
indicator: Rectangle {
id: outer
readonly property int size: 18
implicitWidth: size
implicitHeight: size
x: control.leftPadding
y: parent.height / 2 - height / 2
radius: 4
border.color: control.down ? "orangered" : "orange"
Rectangle {
id: inner
anchors.centerIn: parent
width: outer.size/2
height: width
radius: 3
color: control.down ? "orangered" : "orange"
visible: control.checked
}
}
}
As result you'll get this:

Purpose of z property with real value in QML ListView

In the below sample code, I set z property for the highlight item and depending on the value, it shows up to the user. The z property can also be configured with real value.
It means z value can have fractional values such as 0.1 or 1.2, like that.
Can anyone explain the purpose of z value should be fractional or real value in QML ListView?
import QtQuick 2.8
import QtQuick.Window 2.2
Window {
visible: true
width: 640
height: 480
title: qsTr("Sample List View")
property var delHeight: 50
ListView {
id: listView
anchors.fill: parent
cacheBuffer: 100
footer: Rectangle {
width: (listView.orientation === ListView.Horizontal) ? 200 : parent.width
height: delHeight
color: "lightyellow"
Text {
anchors.centerIn: parent
font.pointSize: 20
text: "Footer"
}
}
header: Rectangle {
width: (listView.orientation === ListView.Horizontal) ? 200 : parent.width
height: delHeight
color: "lightblue"
Text {
anchors.centerIn: parent
font.pointSize: 20
text: "Header"
}
z: 2
}
headerPositioning: ListView.OverlayHeader
highlight: Rectangle {
color: "white"
opacity: 0.5
border.color: "blue"
border.width: 5
z: 1.2
Component.onCompleted: {
console.log ("Created hightlight component with z factor: " + z)
}
}
// highlightMoveDuration: 10000
// highlightRangeMode: ListView.ApplyRange
keyNavigationEnabled: true
model: 20
delegate: componentId
layoutDirection: Qt.RightToLeft
orientation: ListView.Vertical
snapMode: ListView.SnapOneItem
Component.onCompleted: {
currentIndex = 5
}
focus: true
onFocusChanged: {
console.log ("Focus: " + focus)
}
}
Component {
id: componentId
Rectangle {
width: (listView.orientation === ListView.Horizontal) ? 200 : parent.width
height: delHeight
color: "lightgreen"
border.color: "black"
border.width: (listView.currentIndex === index) ? 5 : 1
Text {
anchors.centerIn: parent
font.pointSize: 20
text: "Element: " + index
}
MouseArea {
anchors.fill: parent
onClicked: {
listView.currentIndex = index
}
}
Component.onCompleted: {
console.log ("Created component: " + index)
}
Component.onDestruction: {
console.log ("Destroyed component: " + index)
}
}
}
}
The z property of an item gives the stacking order to that item.
Meaning, if you are constructing two Rectangles one after the other than recently constructed rectangle will be stacked on top the previously constructed one.
Ex code:
Item {
Rectangle {
color: "red"
width: 100; height: 100
}
Rectangle {
color: "blue"
x: 50; y: 50; width: 100; height: 100
}
}
Here red rectangle stacked below blue rectangle.
Now QML gives you chance to change the stacking order through z property of the item.
in the above example if I assign z property of the red rectangle to have a value of anything above 0, I would see it on top of blue rectangle. So z property has changed the stacking order for the sibling item.
The purpose of the z property stays the same in case of ListView highlight. When you want to see the highlight item then you have to give it a value which is greater than the items which will be constructed. You can check this by just setting z property for the componentIds rectangle to some higher value than highlights z value.
NOTE: it only works for sibling items.
More explanation can be found here
Read about the real type here

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

Why does anchors.fill does not work in a QML ListView's delegate's subviews, and what is a nice solution?

I encountered this:
ListView {
id: listView
model: ["Lorem","Ipsum"]
delegate: Item {
height: 20
Text {
z: 2
text: modelData
anchors.fill: parent
}
Rectangle {
z: 1
color: "red"
// this does not work:
anchors.fill: parent
// this works, but I have mixed feelings about it:
// height: 20; width: listView.width
}
}
}
So, apparently, anchors do not work in a delegate's subitem (in this case, Rectangle is not displayed at all). I would like to understand the mechanism behind this. Also, I'd like to ask what is the preferred way to deal with this situation?
Thank You!
Item has an implicitWidth and implicitHeight of zero, so making your Rectangle and Text fill it will result in them having no size as well.
There are two things wrong with your code:
The ListView has no width or height specified.
Your delegate has no width specified.
Here's one way of doing it correctly:
import QtQuick 2.0
import QtQuick.Window 2.0
Window {
width: 300
height: 300
visible: true
ListView {
id: listView
anchors.fill: parent
model: ["Lorem","Ipsum"]
delegate: Item {
width: listView.width
height: textItem.implicitHeight
Text {
id: textItem
z: 2
text: modelData
width: parent.width
}
Rectangle {
z: 1
color: "red"
anchors.fill: parent
}
}
}
}
The documentation of ListView has more information.

Resources