How to transform the center of a QQuickItem to a new center - qt

I have a Qt QML application. Following is the complete code of the application:
Code:
import QtQuick 2.9
import QtQuick.Window 2.2
Window {
id: app_main_window
visible: true
width: 800
height: 600
title: qsTr("Hello QML")
Rectangle {
id: my_item_1
x: 100
y: 100
width: 100
height: 100
color: "grey"
visible: true
z: 1
}
Rectangle {
id: my_item_2
x: 400
y: 400
width: 100
height: 100
color: "grey"
visible: true
z: 1
MouseArea {
anchors.fill: parent
onClicked: {
// How can I change the center of my_item_1 to some arbitrary new center. lets say app_main_window's center. this involves another question. how can I get app_main_window's center?
}
}
}
}
Question:
My question is simple. How can change the center of any QQuickitem to a new center? So in above case how can change the center of my_item_1 to a new center (Qt.point(some_x_center, some_y_center)) when my_item_2 gets a click event.
Additionally, is possible to get another item's center? Like app_main_window or my_item_2's center to apply to the target my_item_1?
PS:
I have made the code simple to make the question objective. I have quite a complicated logic in my actual code where I need to realign something like my_item_1 to a new center without usage of anchors as the QQuickitem I am trying to do that with is scaled and panned into a new point.

If anchors can't be used, you have to calculate manually the center and assign it.
Quick example:
Item
{
anchors.fill: parent
Rectangle
{
id: nonParentOrSibling
width: 200
height: 200
x: 350
y: 240
color: "red"
}
}
Rectangle
{
id: rectToMove
width: 100
height: 100
y: 200
color: "blue"
MouseArea
{
anchors.fill: parent
onClicked:
{
var itemCenter = Qt.point(nonParentOrSibling.x + nonParentOrSibling.width / 2, nonParentOrSibling.y + nonParentOrSibling.height / 2)
rectToMove.x = itemCenter.x - rectToMove.width / 2
rectToMove.y = itemCenter.y - rectToMove.height / 2
}
}
}
Note that this is a one time moving only, and the rectangle won't move if the target is moved.
To make it follow the target you have to rebind it with Qt.binding.
If rectToMove is not in the same coordinate system as nonParentOrSibling, you can use Item.mapToItem() and mapFromItem() to adapt the coordinates.

Related

qml components disappearing after enabeling layers

I have a Component for an sddm theme. At the moment I use the theme dark sugar as the base theme. The component looks like the following:
Item {
id: hexagon
property color color:"yellow"
property int radius: 30
//layer.enabled: true
//layer.samples: 8
Shape {
//... Here some Positioning and other Stuff
ShapePath {
//... Here some Options and Pathlines
}
}
}
This works fine, but as soon as I uncomment both layer settings the component disappears. Does this happen, because I load the component like this:
Pane {
...
Item {
...
MyComponent {
z: 1
}
}
}
Nor the Pane or the Item use layer but most Components in the Item use the z: 1 property.
As iam_peter says, the default width and height properties of any Item are 0, and layer.enabled sets the size of the offscreen texture to the item size. By default, the scene graph doesn't do any clipping: a child item can populate scene graph nodes outside its parent's bounds. But when you confine the children's rendering to a specific offscreen texture, anything that doesn't fit is clipped. Here's a more interactive example to play with this:
import QtQuick
import QtQuick.Controls
Rectangle {
width: 640
height: 480
Column {
CheckBox {
id: cbLE
text: "layer enabled"
}
Row {
spacing: 6
TextField {
id: widthField
text: layerItem.width
onEditingFinished: layerItem.width = text
}
Label {
text: "x"
anchors.verticalCenter: parent.verticalCenter
}
TextField {
id: heightField
text: layerItem.height
onEditingFinished: layerItem.height = text
}
}
}
Rectangle {
id: layerItem
x: 100; y: 100
border.color: "black"; border.width: 2
layer.enabled: cbLE.checked
Rectangle {
width: 100
height: 100
color: "tomato"
opacity: 0.5
}
Text {
text: "this text will get clipped even when layer size is defined"
}
}
}
You can use renderdoc to see how the rendering is done; for example you can see the texture that is created by enabling the layer.
This is a small reproducible example:
import QtQuick
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Item {
//width: 200
//height: 200
//layer.enabled: true
Rectangle {
width: 100
height: 100
color: "red"
}
}
}
I suspect that if you don't set a size on the Item on which you want to enable the layer (layer.enabled: true), it will have a size of 0. Hence the offscreen buffer has a size of 0.
As a side note, this works without layer, because the clip property of an Item by default is set to false. So it won't clip to the bounds of its parent.

QML: Move the rectangle outside the window

Is it possible to move the rectangle outside the window? The only thing I came up with is to write custom logic that will resize the top window when moving the rectangle outside the window.
Current behavior (imgur .gif):
Current behavior
Desired behavior (imgur .png):
Desired behavior
main.qml
import QtQuick 2.15
import QtQuick.Window 2.15
Window {
id: root
width: 300
height: 500
visible: true
flags: Qt.ToolTip | Qt.FramelessWindowHint | Qt.WA_TranslucentBackground
color: "#00000000"
Rectangle {
id: draggable
color: "blue"
x: 100
y: 100
width: 100
height: 100
MouseArea {
anchors.fill: parent
property real lastMouseX: 0
property real lastMouseY: 0
onPressed: {
lastMouseX = mouseX
lastMouseY = mouseY
}
onMouseXChanged: {
draggable.x += (mouseX - lastMouseX)
}
onMouseYChanged: {
draggable.y += (mouseY - lastMouseY)
}
}
}
Rectangle {
color: "blue"
x: 100
y: 300
width: 100
height: 100
// ...
}
}
Windows can be children of other Windows. The Window behavior is still subject to certain platform-dependent behavior, but on a Desktop environment child Windows should still be able to move outside the parent Window. So simply changing your Rectangle to be a Window will give you the desired effect.
Window {
id: root
Window {
id: draggable
...
}
}

QML: Show object over non siblings

I have a somehow very hard to solve problem in my QML code. I will summarize it the best I can since it is very long code..
I write a color picker qml file that is called when the user wants to pick a color. This is done in a big rectangle with little rectangles in it evenly distributed that have flat colors to choose from.
I have a parent rectangle, 1 outer repeater and nested in this repeater is another inner repeater that creates little rectangle in a row. The outer repeater places the inner repeaters under another so it fills the rectangle with little rectangles fully, preferably with different colors.
Every little rectangle also has a function that highlights itself with an animation. This animation is a circle that gets bigger than the rectangle itself. This is done so when the user clicks a color from e.g. a color history on the right, it should highlight the corresponding colors rectangle if is there.
Now, the problem:
No matter what z values I use, this animation won't show above the other rectangles. It will get blocked by neighboring rectangles. I have researched and it seems that z values don't account for non siblings, just for all items in a single parent.
Here's some code that leaves out all the unnecessary junk.
To note is that every rectangle has its own animation and mousearea.
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
visible: true
color: 'black'
width: 640
height: 480
title: qsTr("Hello World")
Rectangle {
id: parentRectangle
width: 400
height: 400
property int numberOfBoxesInARow: 5
property int numberOfBoxesInAColumn: 5
Repeater {
id: outerRepeater
model: parentRectangle.numberOfBoxesInARow
Repeater {
id: innerRepeater
model: parentRectangle.numberOfBoxesInAColumn
y: parentRectangle.height / parentRectangle.numberOfBoxesInAColumn * outerIndex
x: 0
height: parent.height / parentRectangle.numberOfBoxesInAColumn
width: parent.width
property int outerIndex: index
Rectangle {
id: individualRectangle
color: Qt.rgba(1 / (outerIndex + 1), 0, 1 / (index + 1), 1)
x: parentRectangle.width / parentRectangle.numberOfBoxesInARow * index
y: outerIndex * parentRectangle.height / parentRectangle.numberOfBoxesInAColumn
width: parentRectangle.width / parentRectangle.numberOfBoxesInARow
height: parent.height / parentRectangle.numberOfBoxesInAColumn
Component.onCompleted: {
console.log("Rectangle at " + outerIndex + "|" + index + " created, width / height: " + width.toFixed(2) + "| " + height.toFixed(2))
}
MouseArea {
anchors.fill: parent
onClicked: {
highlightAnimation.running = true
}
}
Rectangle {
id: highlightCircle
visible: highlightAnimation.running
color: 'white'
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
property real size: 0
width: size
height: size
radius: size/2
}
PropertyAnimation {
id: highlightAnimation
target: highlightCircle
property: 'size'
from: 200
to: 0
duration: 500
}
}
}
}
}
}
Ok, to paint an item over another one you have at least 2 ways:
z (for siblings items only)
creating order (the last created is the highest)
I guess that the second way is preferable for you. So you just need to create the circle item after all others. For example:
Repeater {
id: outerRepeater
Repeater {
id: innerRepeater
...
MouseArea {
anchors.fill: parent
onClicked: {
highlightCircle.item = individualRectangle;
highlightAnimation.running = true;
}
}
}
}
}
Rectangle {
id: highlightCircle
property var item
...
anchors.horizontalCenter: item ? item.horizontalCenter : undefined
anchors.verticalCenter: item ? item.verticalCenter : undefined
}
PropertyAnimation {
id: highlightAnimation
...
}

How to keep the top-right position of QML item when its size is changing?

I have a toolbar that can be moved (by drag). Depending on the context the content of this toolbar will change, and its size will change accordingly.
My problem is, when the size is changing, the top-left position remains the same and the right border is moving (default and normal behaviour). But I want the top-right position to remain the same and the left border to move instead.
From screen 1 to 2 the toolbar gets smaller, and is shown like the blue rectangle. I want it to be placed like the red rectangle.
How can I achieve this ? Without anchoring on the right of the screen, because the toolbar is movable.
The first thing that comes to mind would be to wrap the toolbar in an Item, and anchor the toolbar to the top right of the item.
import QtQuick 2.8
import QtQuick.Controls 2.3
ApplicationWindow {
id: window
width: 800
height: 800
visible: true
Slider {
id: slider
value: 200
to: 400
}
Item {
x: 600
ToolBar {
id: toolBar
anchors.top: parent.top
anchors.right: parent.right
implicitWidth: slider.value
MouseArea {
anchors.fill: parent
drag.target: toolBar.parent
}
}
}
}
The Item doesn't render anything itself, and has a "zero" size so that the ToolBar is anchored correctly.
Edit: thanks to #GrecKo for coming up with the MouseArea idea. :) This allows you to drag the ToolBar.
A simple solution is to readjust the position of the item when the width changes:
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.3
Window {
visible: true
width: 640
height: 480
Slider {
id: slider
value: 200
to: 400
}
Rectangle {
id: block
color: "red"
width: parseInt(slider.value)
height:50
x: 100
y: 50
readonly property int previousWidth: width
onWidthChanged: {
block.x += previousWidth - width
}
MouseArea {
anchors.fill: parent
drag.target: block
}
}
}
Since onWidthChanged is called before the previousWidth property change, you can easily adjust the x position from previous and new width values.
(Edit: improved my example using #Mitch Slider)
You can do that with Behavior and PropertyAction.
This relies on the feature that you can specify the point in a Behavior when its linked property actually change. You can then add some logic before and after this effective change:
import QtQuick 2.8
import QtQuick.Controls 2.3
ApplicationWindow {
id: window
width: 800
height: 800
visible: true
Slider {
id: slider
value: 200
to: 400
}
Rectangle {
id: rect
width: slider.value
y: 40
height: 40
color: "orange"
Behavior on width {
id: behavior
property real right
SequentialAnimation {
ScriptAction { script: behavior.right = rect.x + rect.width } // the width of the rectangle is the old one
PropertyAction { } // the width of the rectangle changes at this point
ScriptAction { script: rect.x = behavior.right - rect.width } // the width of the rectangle is the new one
}
}
MouseArea {
anchors.fill: parent
drag.target: parent
}
}
}

Creating a horizontal Tumbler or circular SwipeView in QML

I'd like to replace a SwipeView with an Tumbler in QML as I prefer the notion, that there is no first and no last Item.
The problem is, I can't find any other way to get this Tumbler tumble horizontally instead of vertically, but to rotate it by -90° and then rotate the Items back by +90°
This is my code so far, and works as expected:
import QtQuick 2.5
import QtQuick.Controls 2.0
import QtQuick.Window 2.2
Window {
id: root
visible: true
width: 640
height: 480
Row {
id: buttons
spacing: 2
Button {
text: '0'
onClicked: tumbl.currentIndex = 0
}
Button {
text: '1'
onClicked: tumbl.currentIndex = 1
}
Button {
text: '2'
onClicked: tumbl.currentIndex = 2
}
Button {
text: '3'
onClicked: tumbl.currentIndex = 3
}
}
Tumbler {
id: tumbl
rotation: -90 // <---- Rotate there
anchors {
top: buttons.bottom
left: buttons.left
right: buttons.right
bottom: parent.bottom
}
model: 4
delegate: Rectangle {
rotation: 90 // <---- Rotate back
color: 'red'
border.width: 15
Text {
anchors.centerIn: parent
text: index
}
}
visibleItemCount: 1
Component.onCompleted: contentItem.interactive = false
}
}
You can see the two lines, in which I do the rotation marked with a comment.
Does anybody know a way to either produce this circular behavior with a SwipeView or to change the tumble-orientation of the tumbler without this rotation trick?

Resources