PDA

View Full Version : Gestures and QGraphicsScene



estel
12th June 2010, 03:45
Hello,
I want to use gesture framework, but at the begining I have some problems.
I have QGraphicsView and QGraphicsScene
view->addScene(myScene);
At the myScene threre are few icons(QPixmapItem) . I try recognize QSwipeGesture( click somewhere on gaphicsScene and drag) and after recognizon start some animation (QtKinetic)
I have done:

view->grabGesture(Qt::SwipeGesture);
I had hoepe that event would propagate to QGraphicsScene and i have done in myScene

virtual bool myScene::event(QEvent *event)
{
if (event->type() == QEvent::Gesture)
do something
return QGraphicsScene::event(event);
}
unfortunaltely program does not go to line "do something".
What I do wrong??

wysota
13th June 2010, 13:53
First of all you should be grabbing the gesture on the view's viewport, not on the view itself.

estel
15th June 2010, 02:06
I modified my code. Now I run grab gestures on viewport and I try to catch QGesture event on object that inherits QGraphicsObject. Unfortunatelly it seems that there doesn't apper any gestureEvent. I have code everithing similar to example given by Qt.
I found the same problem in this and another forum, but there isn't any solve. So maybe is here anyone who menage to run application witch QGestures?

stretchtiberius
16th June 2010, 21:31
I have the same problem. I can get QGestureEvents from the Viewport but not from a QGraphicsObject. The just do not seem to be there. Anyone know why? :confused:

Here is a example of what I am trying.


class GestureTest : QGraphicsObject {
Q_OBJECT

public:

GestureTest() {
grabGesture(Qt::PinchGesture);
}

bool sceneEvent(QEvent* pEvent) {

if (pEvent->type() == QEvent::Gesture) {
std::cout << "Gesture Received!" << std::endl;
}

return QGraphicsObject::sceneEvent(pEvent);
}
};

wysota
16th June 2010, 22:43
I would assume gesture events might not be propagated to items. It's still a new api in Qt, it might not be complete.

stretchtiberius
17th June 2010, 05:37
I would assume gesture events might not be propagated to items.


That could be the case. However, QGraphicsObject has a grabGesture() function. Therefore, there must be a way to make the gesture events propagate. Unless the planned API is not fully implemented.

wysota
17th June 2010, 09:42
Unless the planned API is not fully implemented.
That might be the case. Maybe you should try some Qt 4.7 snapshot.

Luc4
17th June 2010, 10:26
Sorry for disturbing, but I tried gesture recognition without success as well: is gesture classes only supported by some platforms or are all platforms supported?

wysota
17th June 2010, 10:59
That might be the case. Maybe you should try some Qt 4.7 snapshot.

The docs in 4.6 seem to suggest gestures work for graphic view's objects too.

stretchtiberius
17th June 2010, 18:58
is gesture classes only supported by some platforms or are all platforms supported?
From what I understand, multi-touch gestures are only supported on some platforms such as Windows 7.


The docs in 4.6 seem to suggest gestures work for graphic view's objects too.
That is what confuses me. I am using Qt 4.6.3 and yet I get no QGestureEvents from my QGraphicsObject.

Here is a full QGraphicsObject to test gestures with. Take a look and see if I am missing something. If someone else could test test it themselves that would be great! I just added it to a standard QGraphicsScene. I am compiling 4.7 beta now and will give that a try.



#ifndef ___TOUCHOBJECT___
#define ___TOUCHOBJECT___

#include <QtGui>
#include <iostream>

class TouchObject : public QGraphicsObject {
Q_OBJECT
public:
TouchObject(QGraphicsItem* pParent = NULL) : QGraphicsObject(pParent) {
grabGesture(Qt::PinchGesture);
grabGesture(Qt::PanGesture);
grabGesture(Qt::SwipeGesture);
}

QRectF boundingRect() const {
return QRectF(-WIDTH / 2, -HEIGHT / 2, WIDTH, HEIGHT);
}

QPainterPath shape() const {
QPainterPath path;
path.addEllipse(boundingRect());
return path;
}

void paint(QPainter *painter, const QStyleOptionGraphicsItem *pOption, QWidget *pWidget) {
pOption;
pWidget;
painter->setBrush(Qt::blue);
painter->drawEllipse(boundingRect());
}

bool sceneEvent(QEvent* pEvent) {
case QEvent::Gesture:
std::cout << "Gesture Event Received from sceneEvent()" << std::endl;
}

return QGraphicsObject::sceneEvent(pEvent);
}

bool event(QEvent* pEvent) {
switch (pEvent->type()) {
case QEvent::Gesture:
std::cout << "Gesture Event Received from event()" << std::endl;
}

return QGraphicsObject::event(pEvent);
}

private:
static const int WIDTH = 80;
static const int HEIGHT = 80;
};

#endif

wysota
17th June 2010, 19:34
Pan and swipe gestures don't require multi-touch.

stretchtiberius
17th June 2010, 21:25
I just tested using QGraphicObject with Qt 4.7.0 beta 1. Still did not work. I am beginning to think that this might be a complete oversight by the Qt developers. Maybe passing gesture events to a QGraphicsObject is unknowingly unfinished.

wysota
18th June 2010, 01:09
Do gesture-related examples bundled with Qt work for you?

stretchtiberius
18th June 2010, 01:51
Do gesture-related examples bundled with Qt work for you?
Yes the gesture example and the multi-touch examples work. However, there is no example that has a QGraphicsObject receive gestures. I think this is a major oversight.

stretchtiberius
18th June 2010, 06:16
After playing with it for a little longer I made some interesting observations. If I do not call setAcceptTouchEvents(true) none of the QGestureRecognizers receive any QTouchEvents. If I call setAcceptTouchEvents(true) from my QGraphicsObject, the appropriate QGestureRecognizer class receives events of type QEvent::TouchBegin. However, it never receives any TouchUpdate or TouchEnd events. Because most of the recognition is in TouchUpdate none of the gestures are recognized and therefore, no QGestureEvents are created. I have no idea how to get around this problem.

Thanks for you help.

stretchtiberius
18th June 2010, 16:28
After getting some help by sending a message to the qt4-preview-feedback@trolltech.com, I learned that you have to call setAcceptTouchEvents(true) and in the sceneEvent() acccept TouchStartedEvents and call grabGesture on the viewport as well as within the QGraphicObject. With all this you still cannot receive QPanEvents (likely because the hotspot is not defined in QPanGestureRecognizer). Here is my previous example with the necessary changes.

Within the GraphicsView

viewport()->grabGesture(Qt::PinchGesture);

TouchObject.h


#ifndef ___TOUCHOBJECT___
#define ___TOUCHOBJECT___

#include <QtGui>
#include <QGesture>
#include <iostream>

class TouchObject : public QGraphicsObject {
Q_OBJECT
public:
TouchObject(QGraphicsItem* pParent = NULL) : QGraphicsObject(pParent) {

grabGesture(Qt::PinchGesture);
setAcceptTouchEvents(true);
}

QRectF boundingRect() const {
return QRectF(-WIDTH / 2, -HEIGHT / 2, WIDTH, HEIGHT);
}

QPainterPath shape() const {
QPainterPath path;
path.addEllipse(boundingRect());
return path;
}

void paint(QPainter *painter, const QStyleOptionGraphicsItem *pOption, QWidget *pWidget) {
pOption;
pWidget;
painter->setBrush(Qt::blue);
painter->drawEllipse(boundingRect());
}


bool sceneEvent(QEvent* pEvent) {
switch (pEvent->type()) {
case QEvent::TouchBegin:
pEvent->accept();
return true;
case QEvent::Gesture:
std::cout << "Gesture Event Received from sceneEvent()";
QGestureEvent* pGestureEvent = static_cast<QGestureEvent*>(pEvent);
if(QGesture *pinch = pGestureEvent->gesture(Qt::PinchGesture)) {
std::cout << " Pinch Gesture" << std::endl;
}
else {
std::cout << " not a pinch gesture." << std::endl;
}
break;
}

return QGraphicsObject::sceneEvent(pEvent);
}

private:
static const int WIDTH = 160;
static const int HEIGHT = 160;
};

#endif


I hope they fix these problems in Qt 4.7 and the documentation improves. Thank you for your help.

Oliver Knoll
4th January 2011, 00:59
Did you try this example with Qt 4.7.1? This still does not seem to work for me:

- My QGraphicsView also grabs the Gestures in question
- in my QGraphicsObject subclasss I grab the same Gestures
- in my QGraphicsObject subclass I do call setAcceptTouchEvents(true)
- my boundingRect() method returns some ridiculous large rectangle (for testing)
- I do get the QEvent::TouchBegin and I accept this event as suggested, but...
- I still never get the desired QEvent::Gesture in QGraphicsObject#sceneEvent(QEvent *) method

However I do get Gesture events in my QGraphicsScene as expected. Unfortunately it seems that Pan events are "swallowed" when the mouse hovers over any item in the scene, see http://bugreports.qt.nokia.com/browse/QTBUG-16281

That's why my idea was to create an "invisible" (note: I do not call setVisible(false) on my QGraphicsObject item - in fact in my attempt I actually draw some rectangle, to make really sure the object is in the scene!) QGraphicsObject based "Gesture Controller", which would act as an event filter on all items added to the scene.


That is on a MacBook Pro running OS X 10.6.5. As I said, I do get Gesture events inside my QGraphicsScene (off course I disabled that code while testing my QGraphicsObject approach), so Gestures are definitelly supported on my platform.

Can anyone confirm whether you have a running example using Qt 4.7.1 and receive Gestures inside a QGraphicsObject based item in a QGraphicsScene?

Thanks, Oliver

stretchtiberius
4th January 2011, 06:47
Yes, I am using something similar in my code and it is still working with Qt 4.7.1. I'll double check this example tomorrow after work and let you know if I made any changes.

stretchtiberius
4th January 2011, 20:47
I confirmed that the code I posted previously (the TouchObject class) still receives gesture events with Qt 4.7.1 under Windows 7. I cannot test for OS X. However, I will attach the other little code pieces I use to get it running. I hope it helps. Let me know if I can do anything else for you.

main.cpp


#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsScene>
#include "TouchObject.h"

int main(int argc, char* argv[]){

QApplication app(argc, argv);
QGraphicsScene* pScene = new QGraphicsScene();
pScene->setSceneRect(-300, -300, 600, 600);
pScene->addItem(new TouchObject());
QGraphicsView view(pScene);

view.show();

return app.exec();
}


.pro file


TEMPLATE = app
CONFIG += qt warn_on no_keywords embed_manifest_exe
QT +=
TARGET = GraphicsObjectGestures
SOURCES = main.cpp
HEADERS = TouchObject.h
LIBS +=
CONFIG += console

# Treat warnings as errors
win32:QMAKE_CXXFLAGS += /WX


TouchObject.h is the same as before.

Oliver Knoll
10th January 2011, 10:50
I confirmed that the code I posted previously (the TouchObject class) still receives gesture events with Qt 4.7.1 under Windows 7. I cannot test for OS X. However, I will attach the other little code pieces I use to get it running. I hope it helps. Let me know if I can do anything else for you.
...

Thanks, I will stich your example together and try it out on Mac OS X and post my results here.

By the way - on a slightly different topic, "Gesture Pan Events swallowed" - does the example work for you on Windows 7: http://bugreports.qt.nokia.com/secure/attachment/19372/GraphicsViewGesture.zip

It seems that when the mouse cursor is placed over an item the "Pan" gesture gets "swallowed", only the gesture "Begin" event is delivered to the QGraphicsScene. Pinch events always work, regardless of where the mouse is placed.

Note that in the example you would only get debug output, and the mouse cursor changes to a cross in case of Pan events. And the cursor remains a cross when the mouse cursor was placed over an item (because no "End" Gesture event is received).


If that example worked for you on Windows 7 then I am facing a Mac OS X Cocoa specific issue (on a MacBook Pro).

Thanks!
Oliver

stretchtiberius
10th January 2011, 16:33
By the way - on a slightly different topic, "Gesture Pan Events swallowed" - does the example work for you on Windows 7: http://bugreports.qt.nokia.com/secur...iewGesture.zip

That code works under Windows 7 if one bug is fixed. Change the gestureEvent() function to match the following code.



bool GestureGraphicsScene::gestureEvent(const QGestureEvent *event)
{
bool result = false;
if (QGesture *pan = event->gesture(Qt::PanGesture)) {
result = panTriggered(static_cast<QPanGesture *>(pan));
}
if (QGesture *pinch = event->gesture(Qt::PinchGesture)) {
result = pinchTriggered(static_cast<QPinchGesture *>(pinch));
}

return result;
}


For an explanation, take a look at this: http://doc.qt.nokia.com/4.7/gestures-overview.html#handling-events.

From the documentation:

As one target object can subscribe to more than one gesture type, the QGestureEvent can contain more than one QGesture, indicating several possible gestures are active at the same time. It is then up to the widget to determine how to handle those multiple gestures and choose if some should be canceled in favor of others.

Oliver Knoll
13th January 2011, 09:52
Thanks, I will stich your example together and try it out on Mac OS X and post my results here.

Unfortunatelly it really seems that on Mac (MacBook Pro with touchpad, Mac OS 10.6.6) the QGraphicsObject based items do not receive Gesture events :(

I took your example and adapted it slightly:

- use qDebug instead of stdout, so I actually see the debug statements also in Qt Creator
- explicitly also grab gestures for the viewport! You mentioned that in your posts, but I don't see that in your actual example code (probably it is there in your real code, as you say "Within the GraphicsView", and in the example code there is no derived class of QGraphicsView)

Anyway, just for the record:

TouchObject.h:


#ifndef ___TOUCHOBJECT___
#define ___TOUCHOBJECT___

#include <QtGui>
#include <QGesture>
#include <iostream>

class TouchObject : public QGraphicsObject {
Q_OBJECT
public:
TouchObject(QGraphicsItem* pParent = NULL) : QGraphicsObject(pParent) {

grabGesture(Qt::PinchGesture);
setAcceptTouchEvents(true);
}

QRectF boundingRect() const {
return QRectF(-WIDTH / 2, -HEIGHT / 2, WIDTH, HEIGHT);
}

QPainterPath shape() const {
QPainterPath path;
path.addEllipse(boundingRect());
return path;
}

void paint(QPainter *painter, const QStyleOptionGraphicsItem *pOption, QWidget *pWidget) {
Q_UNUSED(pOption)
Q_UNUSED(pWidget)
painter->setBrush(Qt::blue);
painter->drawEllipse(boundingRect());
}


bool sceneEvent(QEvent* pEvent) {
QGestureEvent* pGestureEvent ;
switch (pEvent->type()) {
case QEvent::TouchBegin:
pEvent->accept();
qDebug("Touch Event Received from sceneEvent()");
return true;
case QEvent::Gesture:
qDebug("Gesture Event Received from sceneEvent()");
pGestureEvent = static_cast<QGestureEvent*>(pEvent);
if(QGesture *pinch = pGestureEvent->gesture(Qt::PinchGesture)) {
qDebug(" Pinch Gesture: state: %d", pinch->state());
}
else {
qDebug(" not a pinch gesture.");
}
break;
default:
break;

}

return QGraphicsObject::sceneEvent(pEvent);
}

private:
static const int WIDTH = 160;
static const int HEIGHT = 160;
};

#endif


main.cpp:


#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsScene>
#include "TouchObject.h"

int main(int argc, char* argv[]){

QApplication app(argc, argv);
QGraphicsScene* pScene = new QGraphicsScene();
pScene->setSceneRect(-300, -300, 600, 600);
pScene->addItem(new TouchObject());
QGraphicsView view(pScene);
view.viewport()->grabGesture(Qt::PinchGesture);
view.show();

return app.exec();
}


GraphicsObjectGesture.pro:


TEMPLATE = app
CONFIG += qt warn_on no_keywords
QT +=
TARGET = GraphicsObjectGestures
SOURCES = main.cpp
HEADERS = TouchObject.h
LIBS +=
CONFIG += console

# Treat warnings as errors
win32:QMAKE_CXXFLAGS += /WX


The only event I really receive is the QEvent::TouchBegin (so yes, the QGraphicsObject seems to receive touch events) - but never a QEvent::Gesture event, as it seems...

I will open a Qt issue for that and post my own example code there as well...

Cheers, Oliver

Added after 24 minutes:

I created an issue for that: http://bugreports.qt.nokia.com/browse/QTBUG-16618