I'm trying to learn QML and at this moment I'm having some problems with understanding of rowSpan and columnSpan, so sorry if this question may sound stupid for some of you.
WHAT I LEARNED:
Correct me if I'm wrong but in a GridLayout should be like this:
Layout.row - indicates the line where the object is located;
Layout.column - indicates the column in which the object is located;
Layout.rowSpan - indicates how many lines should be stretched object;
Layout.columnSpan - indicates how many columns should be stretched
object;
WHAT I'M TRYING TO DO:
Well, in this case, I'm trying to recreate this layout over here
This layout, in theory, should have the followings:
The actual GridLayout should be composed out of 24 columns and 9 rows
RED shape should be at -> col 0, row 1 -> colSpan 3, rowSpan 7
BLUE shape should be at -> col 3, row 1 -> colSpan 8, rowSpan 1
PURPLE shape should be at -> col 3, row 4 -> colSpan 6, rowSpan 3
Or at least that's what I've understood so far.
THE PROBLEM:
After I've coded the QML with the col, row accordantly, and also colSpan and rowSpan I've obtained this instead.
MY CODE:
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.1
Item {
width: 1366
height: 512
GridLayout {
id: grid
columns: 24
rows: 9
anchors.fill: parent
Rectangle {
property var rowSpan: 7
property var columSpan: 3
Layout.column: 0
Layout.row: 1
Layout.preferredWidth: (parent.width / parent.columns) * columSpan
Layout.preferredHeight: (parent.height / parent.rows) * rowSpan
Layout.columnSpan: columSpan
Layout.rowSpan: rowSpan
color: "red"
}
Rectangle {
property var rowSpan: 1
property var columSpan: 8
Layout.column: 3
Layout.row: 1
Layout.preferredWidth: (parent.width / parent.columns) * columSpan
Layout.preferredHeight: (parent.height / parent.rows) * rowSpan
Layout.columnSpan: columSpan
Layout.rowSpan: rowSpan
color: "blue"
}
Rectangle {
property var rowSpan: 3
property var columSpan: 6
Layout.column: 4
Layout.row: 3
Layout.preferredWidth: (parent.width / parent.columns) * columSpan
Layout.preferredHeight: (parent.height / parent.rows) * rowSpan
Layout.columnSpan: columSpan
Layout.rowSpan: rowSpan
color: "purple"
}
}
}
Could anyone explain to me what I'm doing wrong or which part of GridLayout I didn't get it right?
You seem to want to use the GridLayout as if the given space is divided into the given column/row count and each cell is a fixed size. However, the idea behind the GridLayout is that it adjusts each column and each row to the needs of the items in the cells.
So what happens is that you leave some cells empty, however the GridLayout will make these rows/columns 0 pixels high/wide, leading to a chaotic result far from your expectation.
In order to make GridLayout play nice with your setup you can put empty Item's in between, with the preferredWidth/Height set similar to your code, leading to quite some unused QML, and an unreadable piece of code.
In order to have a better setup, you could create your own layout item. The following should work:
import QtQuick 2.0
import QtQuick.Layouts 1.3
Item {
id: layout
property int columns: 1
property int rows: 1
onChildrenChanged: updatePreferredSizes()
onWidthChanged: updatePreferredSizes()
onHeightChanged: updatePreferredSizes()
onColumnsChanged: updatePreferredSizes()
onRowsChanged: updatePreferredSizes()
function updatePreferredSizes()
{
if(layout.children.length === 0)
{
return
}
var cellWidth = layout.width / columns;
var cellHeight = layout.height / rows;
for(var i=0;i<layout.children.length;++i)
{
var obj = layout.children[i]
var c = obj.Layout.column
var r = obj.Layout.row
var cs = obj.Layout.columnSpan
var rs = obj.Layout.rowSpan
obj.x = c * cellWidth;
obj.y = r * cellHeight;
obj.height = cs * cellHeight;
obj.width = rs * cellWidth;
}
}
}
Btw, your main code can be reduced to this (where MyGrid is the above QML):
MyGrid {
id: grid
columns: 24
rows: 9
anchors.fill: parent
Rectangle {
Layout.column: 0
Layout.row: 1
Layout.columnSpan: 7
Layout.rowSpan: 3
color: "red"
}
Rectangle {
Layout.column: 3
Layout.row: 1
Layout.columnSpan: 1
Layout.rowSpan: 8
color: "blue"
}
Rectangle {
Layout.column: 4
Layout.row: 3
Layout.columnSpan: 3
Layout.rowSpan: 6
color: "purple"
}
}
Related
I want to design a ruler as shown in the image below:
Which approach is the best possible way to design a ruler with these small and big lines(scale divisions) as shown in the image.
Also text and numbers will be added with the scale divisions.
There is one knob which i can slide from left to right and vice versa. Can this be achieved using Slider component?
Try using the QtQuick.Extras module it has a Gauge QML Type. For tick marks use the tickmark and minorTickmark properties from the GaugeStyle QML Type. Then add to this what you want.
import QtQuick 2.15
import QtQuick.Window 2.12
import QtQuick.Extras 1.4
Window {
visible: true
width: 640
height: 480
color: "gray"
x: (Screen.width - width) / 2
y: (Screen.height - height) / 2
Gauge {
minimumValue: 0
value: 50
maximumValue: 100
anchors.centerIn: parent
orientation: Qt.Horizontal
}
}
Item {
width: parent.width
height: 8
anchors.bottom: parent.bottom
property real spacing: 33.3
Repeater {
model: parent.width / (parent.spacing + 1) - 1
delegate: Rectangle {
x: index * (rowLayout.spacing + 4)
y: parent.height - height
implicitWidth: major ? 2 : 1
implicitHeight: major ? 18 : 9
color: "grey"
readonly property bool major: index % 6 == 0
}
}
}
You can greatly customize the Slider in QtQuick.Controls 2.x. Here is a start for you
Slider {
id: control
width: parent.width
height: 50
background: Canvas {
x: control.leftPadding + (control.horizontal ? handle.width * 0.5 : (control.availableWidth - width) / 2)
y: control.topPadding + (control.horizontal ? (control.availableHeight - height) / 2 : 0)
implicitWidth: control.horizontal ? 200 : control.width
implicitHeight: control.horizontal ? control.height : 200
width: control.horizontal ? control.availableWidth - handle.width : implicitWidth
height: control.horizontal ? implicitHeight : control.availableHeight - handle.height
onPaint: {
var ctx = getContext("2d")
ctx.clearRect(0, 0, width, height)
ctx.strokeStyle = Qt.rgba(1, 0, 0, 0.4)
ctx.lineWidth = 1
ctx.beginPath()
ctx.moveTo(0, 0)
ctx.lineTo(width, 0)
ctx.lineTo(width, height)
ctx.lineTo(0, height)
ctx.lineTo(0, 0)
for(var x=0;x < width;x += 40) //assuming 40 is unit of measurement
{
ctx.moveTo(x, height)
if(x % 120 == 0)
ctx.lineTo(x, height * 0.3)
else
ctx.lineTo(x, height * 0.6)
}
ctx.stroke();
}
}
handle: Canvas {
id: handle
x: control.leftPadding + (control.horizontal ? control.visualPosition * (control.availableWidth - width) : 0)
y: control.topPadding + (control.horizontal ? 0 : control.visualPosition * (control.availableHeight - height))
implicitWidth: control.height
implicitHeight: 28
onPaint: {
var ctx = getContext("2d")
ctx.clearRect(0, 0, width, height)
ctx.strokeStyle = Qt.rgba(1, 0, 0, 0.4)
ctx.fillStyle = "white"
ctx.lineWidth = 1
ctx.beginPath()
ctx.moveTo(0, 0)
ctx.lineTo(width, 0)
ctx.lineTo(width, height - width * 0.5)
ctx.lineTo(width * 0.5, height)
ctx.lineTo(0, height - width * 0.5)
ctx.lineTo(0, 0)
ctx.fill()
ctx.stroke()
}
}
}
Part of the code was taken from QtQuick.Controls.Material. I only tested the horizontal slider, vertical will fail (especially the handle)
I have a Canvas with the image, that I load via filedialog, how can I get the pixel array of this image?
I need convert it to grayscale by converting every pixel using formula and load it back to the Canvas.
Here the code:
import QtQuick 2.0
import QtQuick.Controls 2.1
import QtQuick.Controls.Material 2.1
import QtQuick.Layouts 1.2
import QtQuick.Dialogs 1.0
ApplicationWindow {
id: window
visible: true
width: 1000
height: 750
Material.theme: Material.Dark
Material.background: "#2C303A"
Material.accent: "#65B486"
Material.foreground: "#efefef"
GridLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: 9
columns: 4
rows: 3
rowSpacing: 10
columnSpacing: 10
Canvas {
id: canvas
height: window.height - 15
Layout.columnSpan: 4
Layout.fillWidth: true
property bool loaded: false
property var filepath: ''
onDrawChanged: requestPaint()
onFilepathChanged: {
loadImage(filepath)
}
onImageLoaded: {
loaded = true
requestPaint()
}
onPaint: {
if (loaded) {
var ctx = getContext("2d");
ctx.drawImage(filepath, 0, 0, width, height)
}
if (to_grayscale) {
var ctx = getContext("2d");
var ar = ctx.getImageData(0, 0, width, height).data
for(var i in ar){
print(i)
}
}
}
}
FileDialog {
id: fileDialog
title: "Please choose a file"
nameFilters: ["Image files (*.jpg *.png *.jpeg)"]
onAccepted: {
console.log("You chose: " + fileDialog.fileUrls)
canvas.filepath = fileDialog.fileUrls
canvas.requestPaint()
}
onRejected: {
console.log("Canceled")
}
}
Drawer {
id: drawer
visible: true
modal: false
width: 0.33 * window.width
height: window.height
GridLayout {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: 9
columns: 2
rows: 3
rowSpacing: 10
columnSpacing: 10
Button {
text: 'Load image'
onClicked: fileDialog.visible = true
}
Button {
text: 'RGB to Grayscale'
onClicked: canvas.draw = true
}
}
}
}
}
I'm trying to get ImageData, but here's empty
I read that Canvas contain PixelArray, but I don't know how to get it.
Thank you.
To access the rgba values
var ar = ctx.getImageData(0, 0, width, height);
for( var x=0; x < ar.data.length; x=x+4 )
{
// To read RGBA values
var red = ar.data[x];
var green = ar.data[x + 1];
var blue = ar.data[x + 2];
var alpha = ar.data[x + 3];
console.log(red + ", " + green + ", " + blue + ", " + alpha );
// To convert to grey scale, modify rgba according to your formula
ar.data[x] = 0.2126 *ar.data[x] + 0.7152* ar.data[x+1] + 0.0722 *ar.data[x+2];
ar.data[x+1] = 0.2126 *ar.data[x] + 0.7152* ar.data[x+1] + 0.0722 *ar.data[x+2];
ar.data[x+2] = 0.2126 *ar.data[x] + 0.7152* ar.data[x+1] + 0.0722 *ar.data[x+2];
ar.data[x+3] = 255;
}
// update the canvas with new data
ctx.drawImage(ar.data, 0, 0);
You have to requestPaint() in onClicked slot of Button
I want to create a reusable component where I could pass a model i.e.
["red", "green", "blue", "black", "orange", "pink", "gray", "navy", "magenta"]
And it would fill Grid with rectangles of model data. And if there are more than let's say 6 items in model it would then fill other "page".
That's how it should look like:
Currently I use StackLayout have 2 Grid items and Repeater inside of them and I divided my model into 2:
model: ["red", "green", "blue", "black", "orange", "pink"]
model: ["gray", "navy", "magenta"]
To fill each "page" with rectangles.
Writing logic to dynamically separate model into separate parts for each page seems overly complicated.
I have tried GridView but I couldn't find important properties like in Grid:
topPadding: 10
bottomPadding: 10
leftPadding: 20
rightPadding: 20
spacing: 10
columns: 2
Source of my example:
import QtQuick 2.6
import QtQuick.Window 2.2
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.0
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Rectangle {
id: mainArea
width: 400
height: 400
color: "beige"
StackLayout {
id: stackLayout
anchors.fill: parent
currentIndex: 0
Grid {
anchors.fill: parent
topPadding: 10
bottomPadding: 10
leftPadding: 20
rightPadding: 20
spacing: 10
columns: 2
property int maxRows: 3
Repeater {
model: ["red", "green", "blue", "black", "orange", "pink"]
Rectangle {
width: (parent.width - parent.leftPadding - parent.rightPadding - parent.spacing) / parent.columns
height: (parent.height - parent.topPadding - parent.bottomPadding - (parent.maxRows - 1) * parent.spacing) / parent.maxRows
color: modelData
}
}
}
Grid {
anchors.fill: parent
topPadding: 10
bottomPadding: 10
leftPadding: 20
rightPadding: 20
spacing: 10
columns: 2
property int maxRows: 3
Repeater {
model: ["gray", "navy", "magenta"]
Rectangle {
width: (parent.width - parent.leftPadding - parent.rightPadding - parent.spacing) / parent.columns
height: (parent.height - parent.topPadding - parent.bottomPadding - (parent.maxRows - 1) * parent.spacing) / parent.maxRows
color: modelData
}
}
}
}
}
Button {
anchors.bottom: mainArea.verticalCenter
anchors.bottomMargin: 5
anchors.left: mainArea.right
text: "<"
onClicked: stackLayout.currentIndex = 0
}
Button {
anchors.top: mainArea.verticalCenter
anchors.topMargin: 5
anchors.left: mainArea.right
text: ">"
onClicked: stackLayout.currentIndex = 1
}
}
For a simple array, you can use the method array.slice(from, to) to create models for each page.
property int page: 0
Button {
text: "up"
onClicked: page++
}
Grid {
y: 100
rows: 2
columns: 2
Repeater {
model: ["red", "green", "blue", "black", "orange", "pink", "gray", "navy", "magenta", "yellow", "cyan", "brown", "lightblue", "darkred"].slice(page * 4, (page + 1) * 4)
Rectangle {
width: 100
height: 100
color: modelData
}
}
}
For QAbstractItemModel-descendents, you can use the method explained here if you want to have a QML-only solution.
Otherwise you might implement a faster filter model in C++ utilizing the QSortFilterProxyModel or maybe the QIdentityProxyModel
See this implementation by GrecKo for a possible way, how to get the SortFilterProxyModel working in QML.
You could try filtering the model to show only specific indices.
Or even simpler, you can simply set the delegate visibility depending on the index and items per page:
ApplicationWindow {
id: main
visible: true
width: 640
height: 480
color: "darkgray"
property int maxRows: 3
property int page: 0
property int iperp: 2 * maxRows
Grid {
anchors.fill: parent
topPadding: 10
bottomPadding: 50
leftPadding: 20
rightPadding: 20
spacing: 10
columns: 2
Repeater {
id: rep
model: ["red", "green", "blue", "black", "orange", "pink", "gray", "navy", "magenta", "yellow", "cyan", "brown", "lightblue", "darkred"]
Rectangle {
width: (parent.width - parent.leftPadding - parent.rightPadding - parent.spacing) / parent.columns
height: (parent.height - parent.topPadding - parent.bottomPadding - (maxRows - 1) * parent.spacing) / maxRows
color: modelData
visible: {
var i = page * iperp
return index >= i && index < i + iperp
}
Text {
anchors.centerIn: parent
text: index
}
}
}
}
Row {
anchors.horizontalCenter: main.contentItem.horizontalCenter
anchors.bottom: main.contentItem.bottom
Button {
text: "<<"
enabled: page
onClicked: --page
}
Button {
text: ">>"
enabled: page < rep.count / iperp - 1
onClicked: ++page
}
}
}
In a QML application I have an item that is moving around the screen (not rotating). I want to display an indicator that rotates around this item, pointing away from the center of the screen, a fixed distance away from the center of the item.
The following simplified QML application performs this goal, by making the indicator a child of the item, and translating it to the desired location. However, when I try to rotate the indicator (the commented-out code) I cannot find any values for origin.x and .y that work. It feels like the QML scene graph calculates X/Y positioning in a way unlike any I've experienced.
import QtQuick 2.7
import QtQuick.Window 2.2
Window {
id: win
visible:true; width:600; height:300
property real padding: 50
property real angle: 0
property real _rads: angle * Math.PI/180
Timer {
interval:50; running:true; repeat:true
onTriggered:win.angle = (new Date/50) % 360
}
Rectangle {
id:object; color:'blue'
width:50; height:width
property real xOffset: Math.cos(_rads)
property real yOffset: Math.sin(_rads)
x: win.width/2 + xOffset * (win.width/2 - padding*2)
y: win.height/2 + yOffset * (win.height/2 - padding*2)
Rectangle {
id:indicator; color:'red'
property real centerOffset: 40
width:10; height:width*2
x: object.width/2 + object.xOffset * centerOffset - width/2
y: object.height/2 + object.yOffset * centerOffset - height/2
// transform: Rotation { origin.x:0; origin.y:0; angle:win.angle }
}
}
}
I've tried making the indicator not be a child of the item. I've tried using Translate in the transform stack instead of X/Y positions. All of them result in amusing-but-incorrect rotations.
How can I simply rotate the indicator around its own center, or otherwise achieve my goal?
You might think of it as a clock and build yourself a clockhand.
import QtQuick 2.7
import QtQuick.Window 2.2
Window {
id: win
visible:true; width:600; height:300
property real padding: 50
property real angle: 0
property real _rads: angle * Math.PI/180
Timer {
interval:50; running:true; repeat:true
onTriggered:win.angle = (new Date/50) % 360
}
Rectangle {
id:object; color:'blue'
width:50; height:width
property real xOffset: Math.cos(_rads)
property real yOffset: Math.sin(_rads)
x: win.width/2 + xOffset * (win.width/2 - padding*2)
y: win.height/2 + yOffset * (win.height/2 - padding*2)
Text {
width: 250
height: 250
x: -100
y: -100
text: '▲'
color: 'red'
font.pixelSize: 20
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignTop
transform: Rotation {
angle: win.angle + 90
origin.x: 125
origin.y: 125
}
}
Text {
x: 15
y: -125
width: 20
height: 20
text: '▲'
color: 'red'
font.pixelSize: 20
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter
transform: Rotation {
angle: win.angle + 90
origin.x: 10
origin.y: 150
}
}
Rectangle {
id: clockhand
width: 1
height: 100
color: 'black'
anchors {
centerIn: parent
}
rotation: win.angle + 90
Text {
text: '▲'
color: 'red'
anchors {
horizontalCenter: parent.horizontalCenter
bottom: parent.top
bottomMargin: -5
}
font.pixelSize: 20
}
}
}
}
Just turn the Clockhand into an Item and remove the color, to make it invisible.
Similar to #derM I have a solution that makes use of Item.rotation. However, with regard to the rest, I have generalized it by avoiding cos and sin since they are not required.
To demonstrate I create 3 SVG images crosshairs.svg, marker.svg, and triangle.svg. I placed crosshairs.svg in the center of the screen. I animate marker.svg by making it bounce around the screen "pong" style. Now, the secret sauce is the placement and orientation of triangle.svg.
To place an offset a triangle relative to the marker. I put the triangle Image inside an Item component. The Item component has no area, it merely has x, y, and rotation set. The Image component is placed relative to the Item and we need to compute its relative placement.
Because the triangle.svg is 16x16, I placed it at (20, -8) relative to the marker. If I had chosen (-8, -8) the SVG would sit on top of the marker. Because I put it at (20, -8) it puts it beyond the marker. Lastly, I compute the rotation using Math.atan2() on the vector between the marker and the crosshairs:
Item {
x: marker.x
y: marker.y
rotation: Math.atan2(
marker.y - crosshairs.y,
marker.x - crosshairs.x
) * 180 / Math.PI
Image {
source: "triangle.svg"
x: 20
y: -8
//cache: false
}
}
Here's a full working demo:
import QtQuick 2.15
import QtQuick.Controls 2.15
Page {
Timer {
interval: 50
running: true
repeat: true
onTriggered: marker.animate()
}
Rectangle {
id: frame
anchors.centerIn: parent
width: parent.width / 2
height: parent.height / 2
color: "#ffe"
border.color: "grey"
clip: true
Image {
id: crosshairs
anchors.centerIn: parent
source: "crosshair.svg"
//cache: false
}
Item {
id: marker
x: parent.width/2
y: parent.height/2
property int dx: 2
property int dy: 2
property int size: 20
Image {
anchors.centerIn: parent
source: "marker.svg"
//cache: false
}
function animate() {
x += dx;
y += dy;
if (x + size / 2 >= parent.width || x - size / 2 <= 0) {
dx = -dx;
x += dx;
x += dx;
}
if (y + size / 2 >= parent.height || y - size / 2 <= 0) {
dy = -dy;
py += dy;
py += dy;
}
}
}
Item {
x: marker.x
y: marker.y
rotation: Math.atan2(
marker.y - crosshairs.y,
marker.x - crosshairs.x
) * 180 / Math.PI
Image {
source: "triangle.svg"
x: 20
y: -8
//cache: false
}
}
}
}
//crosshair.svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 12"><path stroke="grey" d="M6 0L6 12M 0 6L 12 6"/></svg>
//marker.svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path stroke="grey" fill="#ffe" d="M0 0 L20 0 L20 20 L0 20 z"/></svg>
//triangle.svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path stroke="grey" fill="red" d="M16 8 L0 0 L 0 16z"/></svg>
You can Try it Online!
I have simple scene with only 2 Rectangles. The difference is that first one uses absolute coordinates and second one uses anchors. In this case both of rectangles are placed on the same place. But I get different coordinates at all.
import QtQuick 2.4
import QtQuick.Window 2.2
Window {
visible: true
width: 600
height: 600
Rectangle {
id: rec1
x: 200
y: 200
width: 200
height: 200
color: "green"
opacity: 0.5
Component.onCompleted: console.log("rec1: " + rec1.x + "," + rec1.y);
}
Rectangle {
id: rec2
anchors.centerIn: parent
width: 200
height: 200
color: "blue"
opacity: 0.5
Component.onCompleted: console.log("rec2: " + rec2.x + "," + rec2.y);
}
}
The output:
qml: rec2: -100,-100
qml: rec1: 200,200
Yes, I know that it's not really "wrong" result, but how can I get real item coordinates relative to its parent for both of rectangles, i.e. (200,200)?
The documentation of Item proposes the mapToItem function:
Maps the point (x, y) or rect (x, y, width, height), which is in this
item's coordinate system, to item's coordinate system, and returns an
object with x and y (and optionally width and height) properties
matching the mapped coordinate.
If item is a null value, this maps the point or rect to the coordinate
system of the root QML view.
Since the coordinate must be in item' system, the correct way to call the function in your case would be:
<item_id>.mapToItem(<parent_id>, 0, 0)
where (0, 0) is the origin of <item_id> coordinates system.
Since in this case the parent is not an Item itself, we can exploit the null version of the method described by documentation and write:
<item_id>.mapToItem(null, 0, 0)
That's the theory. However, in this particular case (as noted by others), the layout management has not set the coordinate properties yet and thus the methods fail. That seems to be related to the non-consistent state in which items fall during initialisation. Indeed, if we use the function in the onDestruction handler, i.e. when we are sure that initialisation has finished, they give the expected results. See your modified code below:
import QtQuick 2.4
import QtQuick.Window 2.2
import QtQuick.Controls 1.3
Window {
visible: true
width: 600
height: 600
Rectangle {
id: rec1
x: 200
y: 200
width: 200
height: 200
color: "green"
opacity: 0.5
}
Rectangle {
id: rec2
width: 200
height: 200
anchors.centerIn: parent
color: "blue"
opacity: 0.5
}
Component.onCompleted: {
console.info("NOPE! :(")
var cords = rec1.mapToItem(null, 0, 0)
console.info("rec1: " + cords.x + " " + cords.y)
cords = rec2.mapToItem(null, 0, 0)
console.info("rec2: " + cords.x + " " + cords.y)
}
Component.onDestruction: {
console.info("YES! :)")
var cords = rec1.mapToItem(null, 0, 0)
console.info("rec1: " + cords.x + " " + cords.y)
cords = rec2.mapToItem(null, 0, 0)
console.info("rec2: " + cords.x + " " + cords.y)
cords = rec2.mapToItem(null, 100, 100) // (100, 100) of second rec is...
console.info("rec2: " + cords.x + " " + cords.y) // correctly (300, 300) !!
}
}
Output:
qml: NOPE! :(
qml: rec1: 200 200
qml: rec2: -100 -100
qml: YES! :)
qml: rec1: 200 200
qml: rec2: 200 200
qml: rec2: 300 300
Both rectangles have same coordinates but on different time:
import QtQuick 2.4
import QtQuick.Window 2.2
Window {
visible: true
width: 600
height: 600
Rectangle {
id: rec1
x: 200
y: 200
width: 200
height: 200
color: "green"
opacity: 0.5
Component.onCompleted: console.log("rec1: " + rec1.x + "," + rec1.y);
}
Rectangle {
id: rec2
anchors.centerIn: parent
width: 200
height: 200
color: "blue"
opacity: 0.5
Component.onCompleted: console.log("rec2: " + rec2.x + "," + rec2.y);
onXChanged: console.log("rec2.x: " + rec2.x);
onYChanged: console.log("rec2.y: " + rec2.y);
}
}