PDA

View Full Version : Overriding QWidget::event does not work!



kinglui987
28th January 2013, 10:07
Hey there,

i am trying to override the default behavoiur of QWidget::event.
I am trying to implement some touch features.

On my widget i made sure to set setAttribute(Qt::WA_AcceptTouchEvents);

Now from the docs, i read that Qt generates for the first non-primary touchpoint also a mouse event.
I am simply trying to avoid this.
I am using a default example of QT. You can find it in the example/touch directory shipped with QT.

Here is my Code. Note that i am not calling the default behaviour of QWidget. I accept all touchevents and return true so clarify that i have handled the touchevent.



bool ScribbleArea::event(QEvent *event)
{
bool handleEvent = false;
QInputEvent* inPut = dynamic_cast<QInputEvent*>(event);
if(inPut)
{
switch (inPut ->type())
{
case QEvent::TouchBegin:
std::cout<<"ScribbleArea received TouchEvent BEGIN";
inPut->accept();
handleEvent=true;
break;
case QEvent::TouchUpdate:
//std::cout<<"ScribbleArea received TouchEvent UPDATE";
inPut->accept();
handleEvent=true;
break;
case QEvent::TouchEnd:
std::cout<<"ScribbleArea received TouchEvent END";
inPut->accept();
handleEvent=true;
break;
case QEvent::MouseButtonPress:
std::cout<<"ScribbleArea received MouseEvent PRESS";
break;
case QEvent::MouseButtonRelease:
std::cout<<"ScribbleArea received MouseEvent RELEASE";
break;
}
return handleEvent;
}
return true;
}


However, what i get is this, when i am simply touching the screen once.
Why is this? I dont want the mouse event to be generated by QT.



std::cout<<"ScribbleArea received TouchEvent";
std::cout<<"ScribbleArea received MouseEvent PRESS";
std::cout<<"ScribbleArea received TouchEvent END";
std::cout<<"ScribbleArea received MouseEvent RELEASE";


Thanks so far.

wysota
28th January 2013, 12:17
The mouse event is not generated inside the event() call.

kinglui987
28th January 2013, 12:33
Hey,

that was also my first consideration, but after having a look in QWidget::event, i found this:



....

case QEvent::TouchBegin:
case QEvent::TouchUpdate:
case QEvent::TouchEnd:
{
#ifndef Q_WS_MAC
QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event);
const QTouchEvent::TouchPoint &touchPoint = touchEvent->touchPoints().first();
if (touchPoint.isPrimary() || touchEvent->deviceType() == QTouchEvent::TouchPad)
break;

// fake a mouse event!
QEvent::Type eventType = QEvent::None;
switch (touchEvent->type()) {
case QEvent::TouchBegin:
eventType = QEvent::MouseButtonPress;
break;
case QEvent::TouchUpdate:
eventType = QEvent::MouseMove;
break;
case QEvent::TouchEnd:
eventType = QEvent::MouseButtonRelease;
break;
default:
Q_ASSERT(!true);
break;
}
if (eventType == QEvent::None)
break;

QMouseEvent mouseEvent(eventType,
touchPoint.pos().toPoint(),
touchPoint.screenPos().toPoint(),
Qt::LeftButton,
Qt::LeftButton,
touchEvent->modifiers());
(void) QApplication::sendEvent(this, &mouseEvent);
#endif // Q_WS_MAC
break;

...


I am on Windows7 with QT 4.8.3! Dont know if it changed later on, but in this case the mouse event gets generated inside QWidget.
Are my considerations wrong? Where is the mousevent generated?

Any suggestions?

wysota
28th January 2013, 13:10
If that's indeed the case then my guess is that you're simply handling the event for the wrong widget.

kinglui987
28th January 2013, 13:58
I am pretty sure to handle the event for the correct widget. The example application exists of a QMainWindow. Inside this QMainWindow lives my Scribblearea.
For this QWidget i would like to suppress the QMouseEvent. There should be no propagation, because the ScribbleArea should eat the TouchEvent by returning true.

This is indeed, the way i understood QTs event processing. But it simply does not work. Or maybe i am getting something wrong?

If someone could do me a favour and try out my piece of code on his or her machine, i would be greatfull.
Simply copy and paste my code in the ScribbleArea and try yourself.

Thanks in advance

wysota
28th January 2013, 14:11
Did you verify that your code indeed gets executed at all?

kinglui987
28th January 2013, 14:35
Hey,

when setting breakpoints, whether in the QTouchEvent case or in the QMouseEvent case, both are triggered.

Thats really strange, when simulating the same with QTabletEvents, it works as expected: When i do not accept the QTabletEvent, i also got a QMouseEvent (as expected).
When accepting the QTabletEvent i do not get a QMouseEvent (as expected).

Exactly the behaviour, i would like to have for QTouchEvents.

What else can be done?

wysota
28th January 2013, 14:45
Simplify the example even more. Get rid of the main window so that the scribble area is the only widget in the application. See if that changes anything. You can also try stepping through the code once the brekpoint in your event() implementation fires to see what happens later after event() returns.

d_stranz
28th January 2013, 16:38
I agree with Wysota - other widgets may be propagating the events up to your scribble widget, with the result that it appears as if the event is coming from the scribble area when it is not. Simplify to the point where the only widget present is the scribble widget and see if there is a difference.

kinglui987
29th January 2013, 07:57
Hey, i tried that.

I removed the ScribbleArea widget. Since the QMainWindow is also a widget, i moved the code above from the ScribbleArea to the QMainWindow.
Same behaviour here. Note the QMainWindow, does not override one of the specific eventhandlers.
Here is the headefile of the QMainWindow. It simply implements the event member function.



#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QList>
#include <QMainWindow>

//! [0]
class MainWindow : public QMainWindow
{
Q_OBJECT

public:
MainWindow();

protected:
bool event(QEvent*)
private:

};
//! [0]

#endif

wysota
29th January 2013, 10:48
QMainWindow is really a bunch of widgets. It's better to remove it and leave the scribble widget in your app for testing.

kinglui987
1st February 2013, 09:20
Hey,

when ever i had a little free time in the last couple of days, i tried to work on this.

I removed the QMainWindow, there is only a QWidget in my application. I studied the code of QWidget again and i am sure the QMouseEvent is generated inside QWidget, as i already showed.
That is also documented in the DOCs of QT under:


Event Delivery and Propagation
By default, QWidget::event() translates the first non-primary touch point in a QTouchEvent into a QMouseEvent.


http://qt-project.org/doc/qt-4.8/qtouchevent.html

However, i accept all TouchEvent, return true, but the MouseEvent still is getting fired.

There is nothing inside my widget, except the reimplementation of event(QEvent*) member function. Nothing else.

Thus, the only possible answer left is, that the MouseEvent must come from anywhere else?

Any ideas on this?

This is driving me crazy.

wysota
1st February 2013, 11:16
Take a debugger and step through the code.