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
11 replies
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.
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 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.
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 :-)
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();
- }
- }
- }
- }
You must log in to post a reply. Not a member yet? Register here!




