Qt复杂控件eventFilter中触摸事件转鼠标事件异常解决问询
完全可以通过eventFilter实现这两类复合控件的触摸事件转鼠标事件功能,你当前遇到的两个问题都是复合控件的子控件事件过滤不完整导致的,具体原因和修复方案如下:
问题原因
- QComboBox的下拉列表是延迟创建的弹出式独立控件,不属于QComboBox的静态子控件树,你在调用
setTouchFilter遍历子控件时,下拉列表还未创建,自然无法为其安装事件过滤器;同时下拉列表继承自QListView,其内部接收点击事件的是viewport()视口部件,仅给QListView本身装过滤器不会生效。 - QDialogButtonBox的内部按钮是控件初始化完成后才动态添加的子部件,你调用
setTouchFilter时按钮还未被加入子控件树,因此不会被遍历到,也就没有安装事件过滤器。
修复方案
1. 补全QComboBox特殊处理逻辑,补充弹出时的动态安装逻辑
放开你代码中注释的QComboBox处理段,新增弹出信号绑定,在下拉列表弹出时为其视口安装触摸转换过滤器:
// 放在setTouchFilter的子控件遍历逻辑中 if (auto wi = qobject_cast<QWidget*>(children.at(i))) { nh_log(" Class: %s Name: %s", children.at(i)->metaObject()->className(), children.at(i)->objectName().toUtf8().constData()); installTouchFilter(wi); // 放开注释并补充弹出时的动态处理 if (auto cb = qobject_cast<QComboBox*>(wi)) { connect(cb, &QComboBox::showPopup, cb, [=](){ // 下拉列表的视口才是真正接收触摸事件的部件 setTouchFilter(cb->view()->viewport()); setTouchFilter(cb->view()); }, Qt::UniqueConnection); } }
2. 增加QDialogButtonBox的动态子控件监听
在installTouchFilter函数中,当检测到目标控件是QDialogButtonBox时,额外安装一个子控件新增监听过滤器,动态为新增的按钮安装触摸转换过滤器:
static void installTouchFilter(QWidget *w) { if (!w->property(touchFilterSet).isValid()) { w->setProperty(touchFilterSet, QVariant(true)); w->setAttribute(Qt::WA_AcceptTouchEvents); auto ef = new TouchFilter(w); w->installEventFilter(ef); // 新增QDialogButtonBox子控件监听逻辑 if (auto bb = qobject_cast<QDialogButtonBox*>(w)) { bb->installEventFilter(new QObject(bb) { protected: bool eventFilter(QObject *o, QEvent *e) override { if (e->type() == QEvent::ChildAdded) { auto child = static_cast<QChildEvent*>(e)->child(); if (auto childWidget = qobject_cast<QWidget*>(child)) { setTouchFilter(childWidget); } } return false; } }); } } }
3. 补充异常兼容逻辑
你当前的eventFilter中仅处理了单触点场景,建议增加触点数量判断,避免多点触摸时出现数组越界异常:
bool TouchFilter::eventFilter(QObject *obj, QEvent *event) { auto widget = qobject_cast<QWidget*>(obj); if (!widget) { return false; } auto type = event->type(); if (type == QEvent::TouchBegin || type == QEvent::TouchUpdate || type == QEvent::TouchEnd) { event->accept(); auto touchEvent = static_cast<QTouchEvent*>(event); // 新增触点数量判断,仅处理单指操作 if (touchEvent->touchPoints().count() != 1) { return false; } auto tp = touchEvent->touchPoints().at(0); // 原有鼠标事件转换逻辑保持不变 ... } return false; }
验证
修改后重新编译运行,QComboBox下拉列表即可响应触摸选择,QDialogButtonBox的内部按钮也可以正常响应触摸点击。
内容的提问来源于stack exchange,提问作者Sherman Perry
相关产品推荐
相关产品推荐

