'QMouseEvent behaving differently than normal mouse clicks?
I'm currently working on addressing a couple bugs with a touchscreen driver I wrote a couple years ago to support a touchscreen in this application that was running on an OS that didn't have native touchscreen support. My driver simply reads events directly from the device in /dev/input and generates QMouseEvents to simulate the touchscreen functionality. If it matters, the original OS was Scientific Linux 6.4, and we're currently running this on RedHat 8.4.
We have since moved to a newer operating system that DOES support touchscreens, but we don't want to rewrite our application to use the native touch driver unless we have to because it's a lot of effort for little gain. So I simply disabled the native touch driver so it doesn't generate extra touch events on top of what my driver generates. However, there's one particular behavior bothering me.
There is a slider in our application that has +/- buttons on the top/bottom that are used to increment it by single ticks. When you click these with the mouse, it just goes up or down by 1 tick. However, if you tap it with the touchscreen, it increments, then rapidly slides up or down to the other end as if you held down a mouse press on the button.
I've verified with log files that both the QEvent::MouseButtonPress and QEvent::MouseButtonRelease events are being generated and targeting the same widget in the same location.
Does QT treat QMouseEvent differently than native system mouse events? Or is there some other explanation for this behavior? Here is an example of how I'm generating and dispatching the events:
void InputHandler::touchPress(TouchPoint * tp, QWidget * widget) {
QPoint screenPos(tp->cx(), tp->cy());
QWidget * target = widget;
if(target == NULL) target = QApplication::widgetAt(screenPos);
if(target != NULL) {
QPoint local = target->mapFromGlobal(screenPos);
QMouseEvent * press = new QMouseEvent(QEvent::MouseButtonPress, local, screenPos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
QApplication::postEvent(target, press);
DBG(" -- touch press on: " << typeid(*widget).name());
// Check to see if the target is a QLineEdit or QComboBox, and if so, set focus on it.
QLineEdit * lineEdit = dynamic_cast<QLineEdit*>(target);
QComboBox * comboBox = dynamic_cast<QComboBox*>(target);
if(lineEdit) lineEdit->setFocus(Qt::MouseFocusReason);
if(comboBox) comboBox->setFocus(Qt::MouseFocusReason);
}
}
And then the touchRelease method is just the same thing, but without the focus lines and using ``QEvent::MouseButtonReleaseinstead ofQEvent::MouseButtonPress```. The way I identify the target widget from the function header is a helper function that does dynamic casts the widget at the click location to various widgets involved in the touch functionality and if the casted object isn't null, I know what widget it is and which touch function to call.
Any ideas?
EDIT: Ok, so the issue was solved by modifying the method to use QApplication::sendEvent() instead of QApplication::postEvent(). But now there's an issue where although my image manipulation methods work, when I tap buttons, the application freezes or crashes with a segmentation fault and GDB shows the following errors:
QWidget::repaint: Recursive repaint detected
QBackingStore::endPaint() called with an active painter; did you forget to destroy it or call QPainter::end() on it?
Solution 1:[1]
It sounds like your paintEvent does something else besides paint. Such as call this touchPress, and your mousePressEvent does repaint(), directly or indirectly.
When you use postEvent, this infinitely triggering mouse press loop goes through event loop and you get the repeating click effect. When you use sendEvent, there is direct call without going through the event loop, and you get the error you say (and you'd get stack overflow from unbounded recursion, if Qt paint code didn't have that check).
Solution is to make sure your paintEvent does not directly trigger any other events. What you should do, hard to say without seeing all the relevant code. If you're lucky, fix is to do "nothing", meaning you now have some extra call/event somewhere, and you just need to find it and remove it.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | hyde |
