Qt 6.2中如何在Windows/Mac笔记本触控板上通过双指手势实现QGraphicsScene的平移功能
解决Qt 6.2 QGraphicsView双指触控板平移(避免触发缩放)的问题
首先得说清楚你遇到的核心问题:在Windows平台,精准触控板的双指操作默认会被系统转换为原生手势事件(QNativeGestureEvent)而非直接的QTouchEvent,所以你之前监听QTouchEvent或者标准Qt手势(比如Qt::PanGesture)的代码根本不会被触发。再加上QGraphicsView默认可能把某些原生手势映射成了缩放,才会出现你想平移却触发缩放的情况。
下面是完整的可落地实现方案:
1. 基础配置:开启手势支持
在你的MyGraphicsView构造函数里,得正确配置视图属性并抓取需要的原生手势:
MyGraphicsView::MyGraphicsView(...) : QGraphicsView() { // 允许viewport接收触摸相关事件 viewport()->setAttribute(Qt::WA_AcceptTouchEvents); // 关键:让系统把触摸事件转换为原生手势事件(Windows精准触控板必须开这个) viewport()->setAttribute(Qt::WA_TouchNativeGesture); // 抓取缩放和平移对应的原生手势 grabGesture(Qt::NativeGestureZoom); grabGesture(Qt::NativeGesturePan); // 可选:关闭QGraphicsView默认的锚点缩放,避免和自定义手势冲突 setTransformationAnchor(QGraphicsView::NoAnchor); setResizeAnchor(QGraphicsView::NoAnchor); }
2. 重写event函数,区分处理缩放和平移
接下来在MyGraphicsView里重写event函数,专门处理原生手势事件,把缩放和平移的逻辑分开:
bool MyGraphicsView::event(QEvent* event) { if (event->type() == QEvent::NativeGesture) { QNativeGestureEvent* gestureEvent = static_cast<QNativeGestureEvent*>(event); switch (gestureEvent->gestureType()) { case Qt::NativeGestureZoom: { // 这里放你已有的正常缩放逻辑 qreal scaleFactor = gestureEvent->value(); scale(scaleFactor, scaleFactor); return true; // 标记事件已处理,避免传到父类触发其他逻辑 } case Qt::NativeGesturePan: { // 处理平移:根据手势的位移量移动视图 QPointF delta = gestureEvent->delta(); // 注意:如果视图有缩放,需要把像素位移转换成场景坐标的偏移 qreal currentScale = transform().m11(); translate(delta.x()/currentScale, delta.y()/currentScale); return true; } default: break; } } // 其他事件交给父类处理 return QGraphicsView::event(event); }
3. 额外处理:避免触控板滚轮事件干扰(可选)
如果你的触控板双指平移还是被识别成滚轮事件,可以重写wheelEvent,判断是否是触控板合成的滚轮事件,然后转成平移操作:
void MyGraphicsView::wheelEvent(QWheelEvent* event) { // 判断是否是Windows精准触控板合成的滚轮事件 if (event->source() == Qt::MouseEventSynthesizedBySystem) { QPoint delta = event->angleDelta(); qreal currentScale = transform().m11(); // 反向平移(因为滚轮事件的方向和手势位移方向可能相反) translate(-delta.x()/(120*currentScale), -delta.y()/(120*currentScale)); event->accept(); return; } // 普通滚轮事件交给父类处理(比如用滚轮缩放) QGraphicsView::wheelEvent(event); }
Mac平台适配补充
如果要兼容Mac平台,逻辑略有不同——Mac的触控板手势会直接触发Qt的标准手势(Qt::PinchGesture和Qt::PanGesture),所以可以在构造函数里额外抓取这些手势,再处理QGestureEvent:
// Mac平台构造函数添加 grabGesture(Qt::PinchGesture); grabGesture(Qt::PanGesture); // 处理标准手势事件 bool MyGraphicsView::event(QEvent* event) { if (event->type() == QEvent::Gesture) { QGestureEvent* gestureEvent = static_cast<QGestureEvent*>(event); // 处理缩放 if (QPinchGesture* pinch = static_cast<QPinchGesture*>(gestureEvent->gesture(Qt::PinchGesture))) { qreal scaleFactor = pinch->scaleFactor(); scale(scaleFactor, scaleFactor); return true; } // 处理平移 if (QPanGesture* pan = static_cast<QPanGesture*>(gestureEvent->gesture(Qt::PanGesture))) { QPointF delta = pan->delta(); qreal currentScale = transform().m11(); translate(delta.x()/currentScale, delta.y()/currentScale); return true; } } return QGraphicsView::event(event); }
这样就能在Windows和Mac平台分别实现双指平移和缩放的正确区分,不会再出现平移触发缩放的问题。
内容的提问来源于stack exchange,提问作者RED SOFT ADAIR
相关产品推荐
相关产品推荐

