Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to rotate a qml rectangle by dragging?

Tags:

touch

qt

qml

I am creating a clock timer where the time can be set by dragging the clock hand (using touch input or mouse). For this purpose I have defined a AnalogClockHand element as shown below,

AnalogClockHand.qml

Rectangle {
    id: hand

    property alias rotationAngle: handRotation.angle

    x: (parent.width / 2) - (width / 2); y: (parent.height / 2) - height; z: 2
    width: units.gu(1); height: units.gu(14);
    radius: units.gu(1)
    color: Constants.coolGrey
    antialiasing: true

    transform: Rotation {
        id: handRotation

        origin { x: hand.width / 2; y: hand.height }    
        Behavior on angle {
            SpringAnimation { spring: 2; damping: 0.3; modulus: 360 }
        }
    }
}

In the main qml file, I used this element and add a mouseArea to it as shown below,

Main Qml File

AnalogClockHand {
        id: secondHand

        z: parent.z - 1;
        height: units.gu(17); width:  units.gu(0.5)
        rotationAngle: seconds * 6;
        antialiasing: true;

        // Implements touch support
        MouseArea {
            id: timerbackmousearea

            property real truex: mouseX - parent.width/2
            property real truey: parent.height/2 - mouseY
            property real angle: Math.atan2(truex, truey)
            property real strictangle: parseInt(angle * 180 / Math.PI)
            property real modulo: strictangle % 6

            anchors.fill: parent
            preventStealing: true

            onPositionChanged: if (timerbackmousearea.angle < 0) {
                                   secondHand.rotationAngle = strictangle - modulo + 360;
                                   timerValue = parseInt(secondHand.rotationAngle/6);
                                   seconds = timerValue;
                               }
                               else {
                                   secondHand.rotationAngle = strictangle - modulo + 6;
                                   timerValue = parseInt(secondHand.rotationAngle/6);
                                   seconds = timerValue;
                               }
        }
    }

This logic is however not working properly and is very flaky. So one cannot set the time as smoothly. At the end of the day, I am trying to implement something as shown in the image below. The user should be able to move the hour, minute or seconds hand to set the time.

Is there a better code logic that I could implement ?

Note 1: I do realise that the second hand is very small in the image, but that should be fixed soon enough.

enter image description here

like image 934
Nik Avatar asked Jun 24 '13 12:06

Nik


1 Answers

I would do it like this (i did a simpler code as I don't have Ubuntu Touch Components), but the rotation logic is here and the angle to second conversion too :

import QtQuick 2.0

Rectangle{
    id: root;
    width: 720;
    height: 480;
    color: "black";

    Item {
        id: container;
        width: 250;
        height: width;
        anchors.centerIn: parent;

        property real centerX : (width / 2);
        property real centerY : (height / 2);

        Rectangle{
            id: rect;
            color: "white";
            transformOrigin: Item.Center;
            radius: (width / 2);
            antialiasing: true;
            anchors.fill: parent;

            Rectangle {
                id: handle;
                color: "red";
                width: 50;
                height: width;
                radius: (width / 2);
                antialiasing: true;
                anchors {
                    top: parent.top;
                    margins: 10;
                    horizontalCenter: parent.horizontalCenter;
                }

                MouseArea{
                    anchors.fill: parent;
                    onPositionChanged:  {
                        var point =  mapToItem (container, mouse.x, mouse.y);
                        var diffX = (point.x - container.centerX);
                        var diffY = -1 * (point.y - container.centerY);
                        var rad = Math.atan (diffY / diffX);
                        var deg = (rad * 180 / Math.PI);
                        if (diffX > 0 && diffY > 0) {
                            rect.rotation = 90 - Math.abs (deg);
                        }
                        else if (diffX > 0 && diffY < 0) {
                            rect.rotation = 90 + Math.abs (deg);
                        }
                        else if (diffX < 0 && diffY > 0) {
                            rect.rotation = 270 + Math.abs (deg);
                        }
                        else if (diffX < 0 && diffY < 0) {
                            rect.rotation = 270 - Math.abs (deg);
                        }
                    }
                }
            }
        }
        Text {
            text: "%1 secs".arg (Math.round (rect.rotation / 6));
            font {
                pixelSize: 20;
                bold: true;
            }
            anchors.centerIn: parent;
        }
    }
}

Works fine !


Output for the above example

enter image description here

like image 179
TheBootroo Avatar answered Sep 28 '22 06:09

TheBootroo