Qt:如何在笔记本电脑触控板上用两个手指手势在 QGraphicsScene 中实现 Panning/Zooming (win/mac)?

Qt: How to implement Panning/Zooming in QGraphicsScene with two finger gestures on laptop trackpad (win/mac)?

我有一个使用 QGraphicsScene 的 Qt 6.2 应用程序 (Windows/Mac),我想在我的笔记本电脑的触摸板上使用 2 个手指进行平移 - 就像许多其他应用程序一样。

缩放 in/out 工作正常,但使用 2 根手指平移总是会导致缩小。

我找到了一些问题和一些零碎的样本。但没有半途而废的例子:

正确的做法是什么?

到目前为止我尝试了什么(在 Windows 上):

1)

MyGraphicsView::MyGraphicsView(...) : QGraphicsView()
{
    viewport()->setAttribute(Qt::WA_AcceptTouchEvents);

...
bool MyGraphicsView::viewportEvent ( QEvent * event )
{
     switch (event->type())
    {
    case QEvent::TouchBegin:
    case QEvent::TouchUpdate:
    case QEvent::TouchEnd:
        {
        // never called
        }
MyDocWin::MyDocWin(...) : CMDIAppDocWin(),
{
    setAttribute(Qt::WA_AcceptTouchEvents);
...
bool MyDocWin::event(QEvent *event)
{
    switch (event->type())
    {
    case QEvent::TouchBegin:
    case QEvent::TouchUpdate:
    case QEvent::TouchEnd:
        {
            // never called
        }
...
std::vector<Qt::GestureType> sgGestureTypes = {Qt::TapGesture, Qt::TapAndHoldGesture,Qt::PanGesture       ,Qt::PinchGesture     ,Qt::SwipeGesture         };
    
    
    MyGraphicsView::MyGraphicsView(...) : QGraphicsView()
    {
       for(Qt::GestureType gesture : sgGestureTypes)
            grabGesture(gesture);
    ...
    bool MyGraphicsView::event(QEvent *event)
    {
      switch (event->type())
        {
        case QEvent::Gesture:
        case QEvent::NativeGesture:
                    // never called
    MyDocWin::MyDocWin(...) : CMDIAppDocWin(),
    {
    for (Qt::GestureType gesture : sgGestureTypes)
        grabGesture(gesture);
...
    bool MyDocWin::event(QEvent *event)
    {
        switch (event->type())
        {
        case QEvent::Gesture:
        case QEvent::NativeGesture:
                // never called

我终于完成了这项工作。我发现了什么:

平移手势(在 Qt 中)被转换为鼠标滚轮消息,它可以有一个 y 和一个 x 偏移量。这对我来说似乎很奇怪,因为没有带有水平滚轮的鼠标。 更令人困惑的是,根据 MS 定义,Pan 事件被转换为 WM_VSCROLL/WM_HSCROLL 事件 (https://docs.microsoft.com/en-us/windows/win32/wintouch/windows-touch-gestures-overview)

Qt 可以很好地处理其中的大部分(即平移),但不是全部:

  • 似乎无法区分触控板上的手势事件和鼠标上的真实滚轮事件。我最初想始终使用鼠标滚轮进行缩放并使用触摸板平移手势。这种组合似乎是不可能的。我现在使用 Ctrl/Shift 进行鼠标滚轮缩放。这解决了问题

我不得不在 Mac 和 Windows 上以不同方式处理两根手指的缩放手势:

  • 在 windows 上发送一个带有“(event->modifiers() & Qt::ControlModifier) == true”的车轮事件。就mac 不行。所以我写道:
    void myGraphicsView::wheelEvent(QWheelEvent* event)
    {
    if(event->modifiers() & (Qt::ControlModifier | Qt::ShiftModifier))
    myZoomFunction(event, 0);
    else
    QGraphicsView::wheelEvent(event);
    }
    
  • 在 MacOs 上,我们必须收听 QEvent::NativeGesture - 但在 Windows 上没有调用:
    bool myGraphicsView::viewportEvent ( QEvent * event )
    {
    switch (event->type())
    {
    case QEvent::NativeGesture:
    auto nge = dynamic_cast<QNativeGestureEvent*>(event);
    if (nge)
    {
    if(nge->gestureType() == Qt::ZoomNativeGesture)
  • 在 MacOs 时,滚动 up/down 在 angleDelta().x() 中发送,而不是在 angleDelta().y() 中发送。出于任何原因交换两个值。