Measure the time for a component movement in QML - qt

In this simple code, the user can drag the racket up or downwards. We want to know the time for the racket movement (i.e, each y changes of the racket caught by onYChanged) . If the user moves it fast the time for each y change is littler than the time they move it slowly, naturally.
I went for this, but it always writes "Time = 0"! Is there any way for doing this simple task please?
main.qml:
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
id: window
visible: true
width: 700; height: 500
color: "gray"
Rectangle {
id: table
width: window.width / 1.15; height: window.height / 1.15
y: 10
anchors.horizontalCenter: parent.horizontalCenter
color: "royalblue"
}
Racket {
id: racket
x: table.width - 10
y: table.height / 2
}
}
Racket.qml:
import QtQuick 2.12
Rectangle {
width: 15; height: 65
property int oldY: y
property bool yUwards: false
property bool yDwards: false
property double colTime
onYChanged: {
colTime = new Date().getTime()
if (y > oldY)
yDwards = true
else if (y < oldY)
yUwards = true
oldY = y
console.log("Time = ", colTime - new Date().getTime())
}
MouseArea {
anchors.fill: parent
anchors.margins: -parent.height
drag.target: parent
drag.axis: Drag.YAxis
drag.minimumY: table.y
drag.maximumY: table.height - parent.height + 10
}
}

If you want to measure the change time, you must do the same procedure as with Y, save the last time in memory:
import QtQuick 2.12
Rectangle {
width: 15; height: 65
property bool yUwards: false
property bool yDwards: false
property real oldY: y
property double last_time: new Date().getTime()
onYChanged: {
var current_time = new Date().getTime()
console.log("Time = ", current_time - last_time)
if (y > oldY)
yDwards = true
else if (y < oldY)
yUwards = true
oldY = y
last_time = current_time
}
MouseArea {
anchors.fill: parent
anchors.margins: -parent.height
drag.target: parent
drag.axis: Drag.YAxis
drag.minimumY: table.y
drag.maximumY: table.height - parent.height + 10
}
}

Related

QML: How to scale rotated Item around mouse point

I need scale and rotate a Rectangle around mouse point. When the Rectangle is not rotated my solution works fine, but if I apply Rotation transform I face the problem - my Rectangle move to an unexpected point. In my solution I use a MouseArea for drag the Rectangle, Scale and Rotation transforms for scale and rotate.
import QtQuick 2.0
Rectangle {
id: root
color: "gray"
Rectangle {
color: "black"
width: 360
height: 200
opacity: 0.5
x: 500
y: 350
}
Rectangle {
id: sample
color: "green"
width: 360
height: 200
opacity: 0.5
x: 500
y: 350
property real currX: 0
property real currY: 0
property real currZoom: 1
property real maxZoom: 5
property real minZoom: 0.5
transform: [
Scale {
id: scaler
origin.x: sample.currX
origin.y: sample.currY
xScale: sample.currZoom
yScale: sample.currZoom
},
Rotation{
id: rotation
origin.x: 180
origin.y: 100
angle: 30
}
]
MouseArea{
id: mouseArea
anchors.fill: parent
drag.target: sample
onClicked: mouse => {
zoom(true, mouse.x, mouse.y)
}
onWheel: (wheel) => {
var isIn = wheel.angleDelta.y > 0
zoom(isIn, wheel.x, wheel.y)
}
function zoom(isIn, x, y) {
var prevZoom = sample.currZoom
var prevX = sample.currX
var prevY = sample.currY
sample.currX = x
sample.currY = y
sample.currZoom = calculateZoom(isIn, prevZoom)
sample.x = sample.x + (prevX - sample.currX) * (1 - prevZoom)
sample.y = sample.y + (prevY - sample.currY) * (1 - prevZoom)
printSamplePostion()
}
function calculateZoom(isIn, prevZoom) {
var newZoom = isIn ? prevZoom + 0.1 : prevZoom - 0.1
if (newZoom > mouseArea.maxZoom)
newZoom = mouseArea.maxZoom
if (newZoom < mouseArea.minZoom)
newZoom = mouseArea.minZoom
return newZoom
}
function printSamplePostion() {
console.log("== x: 500 y: 350 ======")
console.log("-- x: " + sample.x)
console.log("-- y: " + sample.y)
console.log("=======================")
}
}
}
}
Thanks in advance

if the program is maximized and I minimize it and then click back to the program it is in windowed mode?

My program is starting by default in windowed mode.
My problem is if I start it and then press on maximize, then on minimize and then click on it in the taskbar, it is in windowed mode and not maximized.
To be honest I made that whole new window because I like programs that have a nice clear design. I don't know if you can change the top of a normal Window like the icon of the close button or the color of it.
main.qml:
/***********************************************************************************************************/
/*********************************************** S T A R T *************************************************/
/***********************************************************************************************************/
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.3
import QtGraphicalEffects 1.0
import QtQuick.Controls.Universal 2.0
import QtQuick.Controls.Imagine 2.3
import QtQuick.Controls.Material 2.0
import QtQuick.Dialogs.qml 1.0
import QtQuick.Extras 1.4
import QtQuick.Templates 2.5
import QtQuick.LocalStorage 2.0
ApplicationWindow {
id: mainWindow
visible: true
width: 900
height: 600
title: qsTr("Test")
color: "#2F3136"
flags: Qt.Window | Qt.FramelessWindowHint
property int _max: 0
property int _min: 0
property int _resizeRightVar: 0
property int _resizeLeftVar: 0
property int _resizeTopVar: 0
property int _resizeBottomVar: 0
property bool _resizeRight: true
property bool _resizeLeft: true
property bool _resizeTop: true
property bool _resizeBottom: true
property int _rRCursor: Qt.SizeHorCursor
property int _rLCursor: Qt.SizeHorCursor
property int _rTCursor: Qt.SizeVerCursor
property int _rBCursor: Qt.SizeVerCursor
property bool _moveWindow: true
property int previousX
property int previousY
///////////////////////////////////////////////////////////
/// TOP RECTANGLE WITH TITLE, MINIMIZE, MAXIMIZE, CLOSE ///
///////////////////////////////////////////////////////////
Rectangle {
id: rectangle
width: parent.width
height: 23
color: "#202225"
anchors.top: parent.top
//////////////////////////////////
/// TITLE IN THE TOP RECTANGLE ///
//////////////////////////////////
Text {
leftPadding: 6
topPadding: 1
opacity: 0.75
text: mainWindow.title
font.pixelSize: 14
font.family: "Dodge"
color: "white"
}
///////////////////////////////////////
/// MOUSE AREA IN THE TOP RECTANGLE ///
///////////////////////////////////////
MouseArea {
anchors.fill: parent
enabled: mainWindow._moveWindow
onPressed: {
previousX = mouseX
previousY = mouseY
}
onMouseXChanged: {
var dx = mouseX - previousX
mainWindow.setX(mainWindow.x + dx)
}
onMouseYChanged: {
var dy = mouseY - previousY
mainWindow.setY(mainWindow.y + dy)
}
onDoubleClicked: {
//mainWindow.visibility = "Maximized"
mainWindow._max ++
if(mainWindow._max == 1){
mainWindow.visibility = "Maximized"
//mainWindow.showMaximized()
mainWindow._moveWindow = false
mainWindow._rRCursor = Qt.ArrowCursor
mainWindow._rLCursor = Qt.ArrowCursor
mainWindow._rTCursor = Qt.ArrowCursor
mainWindow._rBCursor = Qt.ArrowCursor
mainWindow._resizeRight = false
mainWindow._resizeLeft = false
mainWindow._resizeTop = false
mainWindow._resizeBottom = false
} else if(mainWindow._max == 2){
mainWindow.visibility = "Windowed"
//mainWindow.showNormal()
mainWindow._max = 0
mainWindow._moveWindow = true
mainWindow._rRCursor = Qt.SizeHorCursor
mainWindow._rLCursor = Qt.SizeHorCursor
mainWindow._rTCursor = Qt.SizeVerCursor
mainWindow._rBCursor = Qt.SizeVerCursor
mainWindow._resizeRight = true
mainWindow._resizeLeft = true
mainWindow._resizeTop = true
mainWindow._resizeBottom = true
}
}
}
/////////////////////////////////////////
/// CLOSE BUTTON IN THE TOP RECTANGLE ///
/////////////////////////////////////////
Rectangle {
id: close_window
width: 27
height: 22.5
anchors.top: parent.top
anchors.topMargin: 0
anchors.right: parent.right
anchors.rightMargin: 0
color: "#202225"
Image {
id: closeImage
source: "close_window.png"
anchors.fill: parent
opacity: 0.6
fillMode: Image.PreserveAspectFit
}
MouseArea {
id: close_windowMouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
mainWindow.close()
}
onEntered: {
cursorShape: Qt.PointingHandCursor
close_window.color = "#F04747"
closeImage.opacity = 1
}
onExited: {
cursorShape: Qt.ArrowCursor
close_window.color = "#202225"
closeImage.opacity = 0.6
}
}
}
////////////////////////////////////////////
/// MAXIMIZE BUTTON IN THE TOP RECTANGLE ///
////////////////////////////////////////////
Rectangle {
id: maximize_window
width: 27
height: 22.5
anchors.top: parent.top
anchors.topMargin: 0
anchors.right: parent.right
anchors.rightMargin: 29
color: "#202225"
Image {
id: maximizeImage
source: "maximize_window.png"
anchors.fill: parent
opacity: 0.6
fillMode: Image.PreserveAspectFit
}
MouseArea {
id: maximize_windowMouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
mainWindow._max ++
if(mainWindow._max == 1){
mainWindow.visibility = "Maximized"
//mainWindow.showMaximized()
mainWindow._moveWindow = false
mainWindow._rRCursor = Qt.ArrowCursor
mainWindow._rLCursor = Qt.ArrowCursor
mainWindow._rTCursor = Qt.ArrowCursor
mainWindow._rBCursor = Qt.ArrowCursor
mainWindow._resizeRight = false
mainWindow._resizeLeft = false
mainWindow._resizeTop = false
mainWindow._resizeBottom = false
} else if(mainWindow._max == 2){
mainWindow.visibility = "Windowed"
//mainWindow.showNormal()
mainWindow._max = 0
mainWindow._moveWindow = true
mainWindow._rRCursor = Qt.SizeHorCursor
mainWindow._rLCursor = Qt.SizeHorCursor
mainWindow._rTCursor = Qt.SizeVerCursor
mainWindow._rBCursor = Qt.SizeVerCursor
mainWindow._resizeRight = true
mainWindow._resizeLeft = true
mainWindow._resizeTop = true
mainWindow._resizeBottom = true
}
}
onEntered: {
maximize_window.color = "#2B2D30"
maximizeImage.opacity = 1
}
onExited: {
maximize_window.color = "#202225"
maximizeImage.opacity = 0.6
}
}
}
////////////////////////////////////////////
/// MINIMIZE BUTTON IN THE TOP RECTANGLE ///
////////////////////////////////////////////
Rectangle {
id: minimize_window
width: 27
height: 22.5
anchors.top: parent.top
anchors.topMargin: 0
anchors.right: parent.right
anchors.rightMargin: 57
color: "#202225"
Image {
id: minimizeImage
source: "minimize_window.png"
anchors.fill: parent
opacity: 0.6
fillMode: Image.PreserveAspectFit
}
MouseArea {
id: minimize_windowMouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
mainWindow._min ++
if(mainWindow._min >= 1){
mainWindow._min = 0
//mainWindow.showMinimized()
mainWindow.visibility = "Minimized"
//if(mainWindow._max == 1){
// mainWindow.showMaximized()
// mainWindow.visibility = "Maximized"
//}
}
}
onEntered: {
minimize_window.color = "#2B2D30"
minimizeImage.opacity = 1
}
onExited: {
minimize_window.color = "#202225"
minimizeImage.opacity = 0.6
}
}
}
}
///////////////////////////
/// RIGHT RESIZE WINDOW ///
///////////////////////////
MouseArea {
id: rightResize
width: 5
enabled: mainWindow._resizeRight
cursorShape: mainWindow._rRCursor
anchors {
right: parent.right
top: parent.top
bottom: parent.bottom
}
onEntered: {
if(mainWindow._resizeRight == true){
mainWindow._rRCursor = Qt.SizeHorCursor
} else if(mainWindow._resizeRight == false){
mainWindow._rRCursor = Qt.ArrowCursor
}
}
onPressed: previousX = mouseX
onMouseXChanged: {
var dx = mouseX - previousX
mainWindow.setWidth(parent.width + dx)
}
}
//////////////////////////
/// LEFT RESIZE WINDOW ///
//////////////////////////
MouseArea {
id: leftResize
width: 5
enabled: mainWindow._resizeLeft
cursorShape: mainWindow._rLCursor
anchors {
left: parent.left
top: parent.top
bottom: parent.bottom
}
onEntered: {
if(mainWindow._resizeLeft == true){
mainWindow._rLCursor = Qt.SizeHorCursor
} else if(mainWindow._resizeLeft == false){
mainWindow._rLCursor = Qt.ArrowCursor
}
}
onPressed: previousX = mouseX
onMouseXChanged: {
var dx = mouseX - previousX
mainWindow.setX(mainWindow.x + dx)
mainWindow.setWidth(mainWindow.width - dx)
}
}
/////////////////////////
/// TOP RESIZE WINDOW ///
/////////////////////////
MouseArea {
id: topResize
height: 5
enabled: mainWindow._resizeTop
cursorShape: mainWindow._rTCursor
anchors {
top: parent.top
left: parent.left
right: parent.right
}
onEntered: {
if(mainWindow._resizeTop == true){
mainWindow._rTCursor = Qt.SizeVerCursor
} else if(mainWindow._resizeTop == false){
mainWindow._rTCursor = Qt.ArrowCursor
}
}
onPressed: previousY = mouseY
onMouseYChanged: {
var dy = mouseY - previousY
mainWindow.setY(mainWindow.y + dy)
mainWindow.setHeight(mainWindow.height - dy)
}
}
////////////////////////////
/// BOTTOM RESIZE WINDOW ///
////////////////////////////
MouseArea {
id: bottomResize
height: 5
enabled: mainWindow._resizeBottom
cursorShape: mainWindow._rBCursor
anchors {
bottom: parent.bottom
left: parent.left
right: parent.right
}
onEntered: {
if(mainWindow._resizeBottom == true){
mainWindow._rBCursor = Qt.SizeVerCursor
} else if(mainWindow._resizeBottom == false){
mainWindow._rBCursor = Qt.ArrowCursor
}
}
onPressed: previousY = mouseY
onMouseYChanged: {
var dy = mouseY - previousY
//mainWindow.setY(mainWindow.y + dy)
mainWindow.setHeight(mainWindow.height + dy)
}
}
////////////////////////////
/// TEXT INPUT IN MIDDLE ///
////////////////////////////
Rectangle{
id: textInputBG
}
}
/***********************************************************************************************************/
/************************************************** E N D **************************************************/
/***********************************************************************************************************/
Here's a hacky way to solve this:
Add property int saved_state to your ApplicationWindow
Then add the following code:
onVisibilityChanged: {
if(saved_state === 4 && visibility === 2) {
showMaximized()
saved_state = -1
}
}
Then isnide your MouseArea minimize_sindowMouseArea add the following line:
saved_state = mainWindow.visibility //NEW LINE
mainWindow.visibility = "Minimized" //Existing line
Explanation: Save the state of your window right before you minimize, then restore it to the save_state when restored.
I don't know of any cleaner way, but that should do it :)

How can I get pixel array from qml canvas?

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

Offset rotation for QML Item

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!

QtQuick 2 - Side Panel example

Can someone help me to understand behaviour of this code? I wrote simple example of side panel menu (just template now) and there is problem to use onMenuVisibleChanged slot (but all I need actually works, just want to understand why another way don't). Logically it should change x of panel rectangle to specified values, but it didn't. Please help me ot understand correct approach for this thing.
main.qml
import QtQuick 2.3
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
ApplicationWindow {
title: qsTr("Hello World")
width: 640
height: 480
visible: true
menuBar: MenuBar{
Menu{
title: "File"
MenuItem{
text: "Exit"
onTriggered: Qt.quit()
}
}
}
SidePane{
id: sidePane
menuWidth: 350
z: 2
}
}
SidePane.qml
import QtQuick 2.3
import QtQuick.Window 2.2
Item {
id: screenItem
anchors.fill: parent
function show() {
rect.x = 0
menuVisible = true
}
function hide() {
rect.x = -rect.width
menuVisible = false
}
property int animationDuration: 200
property bool menuVisible: false
property int dragThreshold: 120
property int menuWidth: 300
Rectangle {
id: rect
width: menuWidth
x: -rect.width
height: Screen.height
color: "lightsteelblue"
Drag.active: menuDragArea.drag.active
Behavior on x {
NumberAnimation {
duration: animationDuration
easing.type: Easing.InOutQuad
}
}
MouseArea {
property int dragX: 0
property int startX: 0
property int diffX: 0
id: menuDragArea
hoverEnabled: true
height: rect.height
width: rect.width + 40
anchors.left: rect.left
drag.target: rect
drag.axis: Drag.XAxis
drag.minimumX: -rect.width
drag.maximumX: 0
onPressed: startX = rect.x + rect.width
onReleased: {
dragX = rect.x + rect.width
diffX = Math.abs(startX - dragX)
if ((diffX > dragThreshold) && (startX == 0)){
rect.x = 0
menuVisible = true
} else if ((diffX < dragThreshold) && (startX == 0)){
rect.x = -rect.width
menuVisible = false
}
if ((diffX > dragThreshold) && (startX == rect.width)){
rect.x = -rect.width
menuVisible = false
} else if ((diffX < dragThreshold) && (startX == rect.width)){
rect.x = 0
menuVisible = true
}
}
}
}
Rectangle{
id: shadowRect
anchors.left: rect.right
anchors.right: screenItem.right
opacity: (rect.x + rect.width) / (rect.width * 2.2)
color: "black"
height: screenItem.height
MouseArea{
id: shadowArea
anchors.fill: shadowRect
visible: menuVisible ? true : false
hoverEnabled: true
onClicked: {
if (menuVisible == true){
rect.x = -rect.width
menuVisible = false
}
}
}
Rectangle{
id: shadowRect2
color: "black"
anchors.left: parent.left
width: 5
opacity: (rect.x + rect.width) / (rect.width * 2)
height: screenItem.height
}
Rectangle{
id: shadowRect3
color: "black"
anchors.left: parent.left
width: 3
opacity: (rect.x + rect.width) / (rect.width * 1.9)
height: screenItem.height
}
}
onMenuVisibleChanged: menuVisible ? rect.x = 0 : rect.x = -rect.width
}
Appreciate any help. Just a QML beginner. The most purpose is to use this panel in android application. Feel free to use this code if you want.
The property drag make the x value draggable
if you implement it by mouseX onPressed/onReleased, rect.x will be 0 or -rect.width onMenuVisibleChanged
MouseArea {
property int dragX: 0
property int startX: 0
property int diffX: 0
id: menuDragArea
hoverEnabled: true
height: rect.height
width: rect.width + 40
anchors.left: rect.left
onPressed: {
startX = mouseX;
console.log(rect.x)
}
onReleased: {
diffX = Math.abs(startX - mouseX)
console.log("diff:"+diffX)
if ((diffX > dragThreshold) && (mouseX > startX) && (rect.x !=0 )){
rect.x = 0
menuVisible = true
} else if ((diffX > dragThreshold) && (mouseX < startX) && (rect.x == 0)){
rect.x = -rect.width
menuVisible = false
}
}
}
with visual drag ,sorry it's ugly:
MouseArea {
property int startX: 0
property int diffX: 0
property int startRectX: 0
property bool isPressed: false
id: menuDragArea
hoverEnabled: true
height: rect.height
width: rect.width + 40
anchors.left: rect.left
onPressed: {
startX = mouseX;
startRectX = rect.x
isPressed = true
console.log(rect.x)}
onMouseXChanged: {
if(isPressed)
rect.x = (mouseX>rect.width)? 0 : (mouseX-rect.width)
}
onReleased: {
isPressed = false
diffX = Math.abs(startX - mouseX)
console.log("diff:"+diffX)
if ((mouseX >= startX) && (startRectX == -rect.width )){
if(diffX > dragThreshold)
{
rect.x = 0
menuVisible = true
}
else
rect.x = startRectX
} else if ((mouseX <= startX) && (startRectX == 0)){
if(diffX > dragThreshold)
{
rect.x = -rect.width
menuVisible = false
}
else
rect.x = startRectX
}
else
rect.x = startRectX
}
}

Resources