Distinguishing direction of swipe and changing states accordingly in QML



  • This should be fairly simple but I am not sure how to complete it. Lets say I have several states that I want to switch between by swipe events so that when the user swipes to the left it goes back one state and when the user swipes to the right it goes forward one state. Any help would be appreciated. Thanks,

    Kyle



  • I assume you are using the GestureArea QML element, right?
    The onSwipe signal has an angle argument. You can use that to distinguish a direction. I don't know what the scale (degrees? rads?) or what the 0 point is (top? right?), but you should be able to figure that out yourself easily. Say that the scale are degrees and the top is 0, then you can interpret anything between 315 and 360 and between 0 and 45 as a swipe to the top, between 45 and 135 to the right, between 135 and 225 to the bottom, and between 225 and 315 to the left.

    The state system in QML is quite basic (there were discussions on integrating the much more powerful Qt statemachines into QML here or on the qml mailinglist before), but in principle, you can just change the qml state that controls in what state your application is on such a swipe.



  • I would like to do with with just a mousearea so I don't have to use a labs plugin. This will be necessary to move to my target device, openembedded linux. Any solutions with mousearea?



  • Well, in that case, you would basically have to make your own gesture recognition. For a very basic recognition, store the x and of the mouse when you receive the onPressed signal, and compare with the x and y when you get onReleased. If the x on release is (much) bigger than on pressed, and the y is about the same, you have a swipe to the right. You probably want to add the time it took into the picture, as well as detours along the way (a half circle is not the same as a swipe, even though they can start and end in the same place).

    Are you sure you can't use the one from labs somehow?



  • I believe I understand the concept, I am just not sure how to accomplish it in qml. Deploying plugins to openembedded has been a large nightmare in the past.



  • I have implemented the swipe gesture in my QML jewel-game. I'll paste the code (JavaScript) which handles the swipe gesture check for MouseArea component here. The code is my game specific, but I'm sure you'll get the idea :)
    @
    function handleSwipe(srcX, srcY, destX, destY) {
    var col = Math.floor(srcX / gameCanvas.blockSize);
    var row = Math.floor(srcY / gameCanvas.blockSize);
    if (col >= maxColumn || col < 0 || row >= maxRow || row < 0)
    return false;

    var deltax = destX - srcX;
    var deltay = destY - srcY;
    var success = false;
    if (Math.abs(deltax) > 50 || Math.abs(deltay) > 50) {
        if (deltax > 30 && Math.abs(deltay) < 30) {
            // swipe right
            success = trySwap(col, row, col + 1, row);
        } else if (deltax < -30 && Math.abs(deltay) < 30) {
            // swipe left
            success = trySwap(col, row, col - 1, row);
        } else if (Math.abs(deltax) < 30 && deltay > 30) {
            // swipe down
            success = trySwap(col, row, col, row + 1);
        } else if (Math.abs(deltax) < 30 && deltay < 30) {
            // swipe up
            success = trySwap(col, row, col, row - 1);
        }
        if (success) {
            shuffleDown();
            fillBoard();
            return true;
        }
    }
    return false;
    

    }
    @



  • Could you help me understand how your JavaScript integrated into your QML mousearea and where I would need to modify our JavaScript?

    How could I have the JavaScript tell my mousearea when a gesture is signaled. In other words, I would love to have my mouse area designed like:

    Mousearea{
    ...
    onGestureLeft:
    }



  • You can achieve that by creating your own QML component with the appropriate signals.
    Adapt the code example above to emit such a signal on the different swipes that it recognizes (see the inline comments on when that is).

    On the start of your mouse interaction, you store the begin coordinates xB and yB. If you want to recognize the swipe only when the interaction is over, you then use the onReleased signal of the mouseArea. If you want to do continuous recognition, use the onPositionChanged signal. When you get the required signal, run the code above using the xB and yB and the new coordinates that are passed with the signal.



  • Forgive my inexperience but could you give me an example of what that would look like?



  • From the top of my head, I did not try it out:

    @
    //in a file called MyGestureArea.qml (casing important!)

    MouseArea {
    signal swipeRight;
    signal swipeLeft;
    signal swipeUp;
    signal swipeDown;

    property int startX;
    property int startY;
    
    onPressed: {
        startX = mouse.x;
        startY = mouse.y;
    }
    
    onReleased: {
    var deltax = mouse.x - startX;
    var deltay = mouse.y - startY;
    
    if (Math.abs(deltax) > 50 || Math.abs(deltay) > 50) {
        if (deltax > 30 && Math.abs(deltay) < 30) {
            // swipe right
            swipeRight();
        } else if (deltax < -30 && Math.abs(deltay) < 30) {
            // swipe left
            swipeLeft();
        } else if (Math.abs(deltax) < 30 && deltay > 30) {
            // swipe down
            swipeDown();
        } else if (Math.abs(deltax) < 30 && deltay < 30) {
            // swipe up
            swipeUp();
        }
    }
    

    }
    @

    Then, you should be able to use a MyGestureArea instead of a MouseArea, and be able to use onSwipeRight and onSwipeDown event handlers. Again: I did not test the above. See it as pseudocode please :-)



  • That worked great but it does not play well with my other mouseareas on the page. I laid the gesture sensing mousearea over the whole page which contains mousareas for buttons.



  • Thank you guys, I was looking out for an example as this: I implemented it as below in my flip area

    @MouseArea{
    id:myFlipMouseArea
    anchors.fill: myFlip
    property int startX;
    property int startY;
    onPressed: {
    startX = mouse.x;
    startY = mouse.y;
    }

        onReleased: {
            var deltax = mouse.x - startX;
            var deltay = mouse.y - startY;
    
            if (Math.abs(deltax) > 40 || Math.abs(deltay) > 40) {
                if (deltax > 30 && Math.abs(deltay) < 30) {
                    // swipe right
                } else if (deltax < -30 && Math.abs(deltay) < 30) {
                    // swipe left
                    myFlip.flipped = !myFlip.flipped
                    console.log("swipeLeft");
                } else if (Math.abs(deltax) < 30 && deltay > 30) {
                    // swipe down
                } else if (Math.abs(deltax) < 30 && deltay < 30) {
                    // swipe up
                    console.log("swipeUp");
                    currentWord += 1;
                    flipWord.modifyContents();
                }
            }
        }
    }@

Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.