RED SOFT ADAIR
RED SOFT ADAIR

Reputation: 12238

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

I have a Qt 6.2 Application (Windows/Mac) using QGraphicsScene and want to use 2 fingers on the touch pad of my laptop for panning - as many other applications do.

Zooming in/out works fine, but using 2 fingers for panning always results in zoom out.

I found a number of questions and some fragmentary samples. But no half way complete example:

What is the right way to do this?

What i tried so far (on 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

Upvotes: 4

Views: 2330

Answers (1)

RED SOFT ADAIR
RED SOFT ADAIR

Reputation: 12238

I finally manged to get this work. What i found out:

Pan Gestures (in Qt) are converted to Mouse Wheel messages which can have a y and also a x offset. This seems strange to me, as there is no Mouse with a horizontal Wheel. Even more confusing, by MS definition Pan events are converted to WM_VSCROLL/WM_HSCROLL events (https://learn.microsoft.com/en-us/windows/win32/wintouch/windows-touch-gestures-overview)

Most of this (i.e panning) is handled quite well by Qt, but not all:

  • It seems impossible to distinguish between a gesture event on the track pad and a real wheel event on the mouse. I originally wanted to use the Mouse Wheel always for Zoom AND use the Touch Pads Pan gesture. This combination seems to be impossible. I now use Ctrl/Shift for mouse wheel zoom. This solved the problem

The zoom gesture with two fingers i had to handle differently on Mac and Windows:

  • On windows a wheel event is sent with “(event->modifiers() & Qt::ControlModifier) == true”. On the mac not. So i wrote:
    void myGraphicsView::wheelEvent(QWheelEvent* event)
    {
    if(event->modifiers() & (Qt::ControlModifier | Qt::ShiftModifier))
    myZoomFunction(event, 0);
    else
    QGraphicsView::wheelEvent(event);
    }
    
  • On MacOs we have to listen to a QEvent::NativeGesture - but thats not called on 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)
  • On MacOs scrolling up/down is sent in angleDelta().x(), instead of angleDelta().y(). Both values are swapped for any reason.

Upvotes: 4

Related Questions