QMouseEvent 的行为与普通鼠标单击不同?
我目前正在努力解决几年前编写的触摸屏驱动程序的几个错误,以支持此应用程序中的触摸屏,该应用程序在没有本机触摸屏支持的操作系统上运行。我的驱动程序只是直接从 /dev/input
中的设备读取事件,并生成 QMouseEvents 来模拟触摸屏功能。如果重要的话,最初的操作系统是 Scientific Linux 6.4,我们目前在 RedHat 8.4 上运行它。
此后,我们已经迁移到支持触摸屏的更新操作系统,但我们不想重写我们的应用程序以使用本机触摸驱动程序,除非必须这样做,因为这是付出很大的努力却收效甚微。因此,我只是禁用了本机触摸驱动程序,这样它就不会在我的驱动程序生成的基础上生成额外的触摸事件。然而,有一种特殊的行为困扰着我。
我们的应用程序中有一个滑块,其顶部/底部有 +/- 按钮,用于按单个刻度递增。当您用鼠标单击这些时,它只会向上或向下移动 1 个刻度。但是,如果您用触摸屏点击它,它会递增,然后快速向上或向下滑动到另一端,就像您按住鼠标按钮一样。
我已经使用日志文件验证了 QEvent::MouseButtonPress
和 QEvent::MouseButtonRelease
事件正在生成,并且针对同一位置的同一小部件。
QT 对待 QMouseEvent 的方式与本机系统鼠标事件的方式不同吗?或者这种行为还有其他解释吗?下面是我如何生成和分派事件的示例:
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);
}
}
然后 touchRelease 方法是同样的事情,但没有焦点线并使用“QEvent::MouseButtonRelease”而不是
QEvent: :按下鼠标按钮```。我从函数头中识别目标小部件的方式是一个辅助函数,该函数将单击位置的小部件动态转换为触摸功能中涉及的各种小部件,如果转换的对象不为空,我知道它是什么小部件,并且调用哪个触摸函数。
有什么想法吗?
编辑:好的,所以通过修改方法以使用QApplication::sendEvent()
而不是QApplication::postEvent()
解决了问题。但现在存在一个问题,虽然我的图像处理方法有效,但当我点击按钮时,应用程序因分段错误而冻结或崩溃,并且 GDB 显示以下错误:
QWidget::repaint: Recursive repaint detected
QBackingStore::endPaint() called with an active painter; did you forget to destroy it or call QPainter::end() on it?
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 of
QEvent::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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
听起来你的
paintEvent
除了绘制之外还做了其他事情。例如调用此touchPress
,并且您的mousePressEvent
直接或间接执行repaint()
。当你使用
postEvent
时,这个无限触发的鼠标按下循环会经过事件循环,你会得到重复点击的效果。当您使用sendEvent
时,会直接调用而不经过事件循环,并且您会收到您所说的错误(如果 Qt 绘制代码没有,您会从无界递归中得到堆栈溢出那个检查)。解决方案是确保您的
paintEvent
不会直接触发任何其他事件。如果没有看到所有相关代码,很难说你应该做什么。如果你幸运的话,修复就是“什么都不做”,这意味着你现在在某个地方有一些额外的调用/事件,你只需要找到它并删除它。It sounds like your
paintEvent
does something else besides paint. Such as call thistouchPress
, and yourmousePressEvent
doesrepaint()
, 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 usesendEvent
, 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.