Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QGraphicsView and Qt::WA_AcceptTouchEvents
Forum Updated to NodeBB v4.3 + New Features

QGraphicsView and Qt::WA_AcceptTouchEvents

Scheduled Pinned Locked Moved Unsolved General and Desktop
16 Posts 4 Posters 1.5k Views 4 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    Michael Lehn
    wrote on last edited by
    #1

    I have implemented a class MyView derived from QGraphicsView. It is supposed to

    • handle touch events like a "pinch" for zooming
    • and its screen should grow when now items are added of dragged to the outside of the current bounding rectangle.

    With my current implementation I have the following problem: When an item is dragged beyond the viewport the MyView object no longer receives any touch events.

    I have reproduced the issue with a simpler program shown below. On my MacBook I can reproduce the following effect:

    1. After the program was started I can do a "pinch" and get the debug message "2 finger touch event"
    2. Then I move the rectangle item to the bottom and beyond the viewport.
    3. Now I no longer receive any event in viewportEvent.

    Where is my error in reasoning?

    #include <QApplication>
    #include <QGraphicsRectItem>
    #include <QGraphicsScene>
    #include <QGraphicsView>
    #include <QMainWindow>
    #include <QTouchEvent>
    
    class MyView
        : public QGraphicsView
    {
        public:
            MyView(QWidget *parent = nullptr)
                : QGraphicsView{parent}
            {
                setScene(new QGraphicsScene);
                viewport()->setAttribute(Qt::WA_AcceptTouchEvents);
            }
    
            bool viewportEvent(QEvent *event) override
            {
                switch (event->type()) {
                    case QEvent::TouchBegin:
                    case QEvent::TouchUpdate:
                    case QEvent::TouchEnd:
                        {
                            auto *touchEvent = static_cast<QTouchEvent *>(event);
                            const auto touchPoints = touchEvent->points();
                            if (touchPoints.count() == 2) {
                                qDebug() << "2 finger touch event";
                            }
                        }
                        return true;
                    default:
                        return QGraphicsView::viewportEvent(event);
                }
            }
    };
    
    class MainWindow
        : public QMainWindow
    {
        public:
            MainWindow(QWidget *parent = nullptr)
                : QMainWindow{parent}
                , view{new MyView}
            {
                setCentralWidget(view);
                auto item = new QGraphicsRectItem{0, 0, 50, 50};
                view->scene()->addItem(item);
                item->setFlag(QGraphicsItem::ItemIsMovable);
            }
    
        private:
            QGraphicsView   *view = nullptr;
    
    };
    
    int
    main(int argc, char *argv[])
    {
        QApplication app(argc, argv);
        MainWindow mainWindow;
        mainWindow.setGeometry(100, 100, 800, 500);
        mainWindow.show();
        return app.exec();
    }
    
    Pl45m4P 1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      Which version of Qt are you using ?
      On which version of macOS ?

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      M 1 Reply Last reply
      0
      • SGaistS SGaist

        Hi,

        Which version of Qt are you using ?
        On which version of macOS ?

        M Offline
        M Offline
        Michael Lehn
        wrote on last edited by Michael Lehn
        #3

        @SGaist I am using Qt 6.5.2 on macOS Ventura 13.5.2

        Edit: ... and a MacBook Pro 2019, 2,3 GHz 8-Core Intel Core i9

        I used the installer qt-unified-macOS-x64-4.6.1-online.dmg from https://download.qt.io/archive/online_installers/4.6/

        1 Reply Last reply
        0
        • M Michael Lehn

          I have implemented a class MyView derived from QGraphicsView. It is supposed to

          • handle touch events like a "pinch" for zooming
          • and its screen should grow when now items are added of dragged to the outside of the current bounding rectangle.

          With my current implementation I have the following problem: When an item is dragged beyond the viewport the MyView object no longer receives any touch events.

          I have reproduced the issue with a simpler program shown below. On my MacBook I can reproduce the following effect:

          1. After the program was started I can do a "pinch" and get the debug message "2 finger touch event"
          2. Then I move the rectangle item to the bottom and beyond the viewport.
          3. Now I no longer receive any event in viewportEvent.

          Where is my error in reasoning?

          #include <QApplication>
          #include <QGraphicsRectItem>
          #include <QGraphicsScene>
          #include <QGraphicsView>
          #include <QMainWindow>
          #include <QTouchEvent>
          
          class MyView
              : public QGraphicsView
          {
              public:
                  MyView(QWidget *parent = nullptr)
                      : QGraphicsView{parent}
                  {
                      setScene(new QGraphicsScene);
                      viewport()->setAttribute(Qt::WA_AcceptTouchEvents);
                  }
          
                  bool viewportEvent(QEvent *event) override
                  {
                      switch (event->type()) {
                          case QEvent::TouchBegin:
                          case QEvent::TouchUpdate:
                          case QEvent::TouchEnd:
                              {
                                  auto *touchEvent = static_cast<QTouchEvent *>(event);
                                  const auto touchPoints = touchEvent->points();
                                  if (touchPoints.count() == 2) {
                                      qDebug() << "2 finger touch event";
                                  }
                              }
                              return true;
                          default:
                              return QGraphicsView::viewportEvent(event);
                      }
                  }
          };
          
          class MainWindow
              : public QMainWindow
          {
              public:
                  MainWindow(QWidget *parent = nullptr)
                      : QMainWindow{parent}
                      , view{new MyView}
                  {
                      setCentralWidget(view);
                      auto item = new QGraphicsRectItem{0, 0, 50, 50};
                      view->scene()->addItem(item);
                      item->setFlag(QGraphicsItem::ItemIsMovable);
                  }
          
              private:
                  QGraphicsView   *view = nullptr;
          
          };
          
          int
          main(int argc, char *argv[])
          {
              QApplication app(argc, argv);
              MainWindow mainWindow;
              mainWindow.setGeometry(100, 100, 800, 500);
              mainWindow.show();
              return app.exec();
          }
          
          Pl45m4P Offline
          Pl45m4P Offline
          Pl45m4
          wrote on last edited by
          #4

          @Michael-Lehn said in QGraphicsView and Qt::WA_AcceptTouchEvents:

          MyView(QWidget *parent = nullptr)
          : QGraphicsView{parent}
          {
          setScene(new QGraphicsScene);
          viewport()->setAttribute(Qt::WA_AcceptTouchEvents);
          }

          Does anything change if you set a static sceneRect (e.g. (0, 0, w, h)) here?
          Can you track the touchEvents and check where exactly they stop?


          If debugging is the process of removing software bugs, then programming must be the process of putting them in.

          ~E. W. Dijkstra

          M 1 Reply Last reply
          0
          • Pl45m4P Pl45m4

            @Michael-Lehn said in QGraphicsView and Qt::WA_AcceptTouchEvents:

            MyView(QWidget *parent = nullptr)
            : QGraphicsView{parent}
            {
            setScene(new QGraphicsScene);
            viewport()->setAttribute(Qt::WA_AcceptTouchEvents);
            }

            Does anything change if you set a static sceneRect (e.g. (0, 0, w, h)) here?
            Can you track the touchEvents and check where exactly they stop?

            M Offline
            M Offline
            Michael Lehn
            wrote on last edited by
            #5

            Is anyone able to reproduce the effect? I would like to rule out installation/platform issues.

            @Pl45m4 I made the following change:

                    MainWindow(QWidget *parent = nullptr)
                        : QMainWindow{parent}
                        , view{new MyView}
                    {
                        setCentralWidget(view);
            
                        view->scene()->setSceneRect(0, 0, 100, 100);
                        view->scene()->addItem(new QGraphicsRectItem{0, 0, 100, 100});
            
                        auto item = new QGraphicsRectItem{0, 0, 50, 50};
                        view->scene()->addItem(item);
                        item->setFlag(QGraphicsItem::ItemIsMovable);
                    }
            

            So now there is a rectangle indicating the sceneRect() area.

            Now I can observe tfor example he following effect:

            1. When I move the item to the right and outside the screenRect() at some point I no longer receive touch events. This does not happen when it is outside but still "close enough".
            2. If the item has not left the viewport() area and I move it back, i.e. close enough to the sceneRect() area I can again receive touch events
            3. Once the item has left the viewport() area I can no longer recover. That means after resizing the main widget so that I can grab the rectangle and moving it back has no observable effect.
            M 1 Reply Last reply
            0
            • M Michael Lehn

              Is anyone able to reproduce the effect? I would like to rule out installation/platform issues.

              @Pl45m4 I made the following change:

                      MainWindow(QWidget *parent = nullptr)
                          : QMainWindow{parent}
                          , view{new MyView}
                      {
                          setCentralWidget(view);
              
                          view->scene()->setSceneRect(0, 0, 100, 100);
                          view->scene()->addItem(new QGraphicsRectItem{0, 0, 100, 100});
              
                          auto item = new QGraphicsRectItem{0, 0, 50, 50};
                          view->scene()->addItem(item);
                          item->setFlag(QGraphicsItem::ItemIsMovable);
                      }
              

              So now there is a rectangle indicating the sceneRect() area.

              Now I can observe tfor example he following effect:

              1. When I move the item to the right and outside the screenRect() at some point I no longer receive touch events. This does not happen when it is outside but still "close enough".
              2. If the item has not left the viewport() area and I move it back, i.e. close enough to the sceneRect() area I can again receive touch events
              3. Once the item has left the viewport() area I can no longer recover. That means after resizing the main widget so that I can grab the rectangle and moving it back has no observable effect.
              M Offline
              M Offline
              Michael Lehn
              wrote on last edited by
              #6

              For better keeping track where the effect stats I made the following changes:

              1. Class MyRectItem that prints the position after it has changed:
              class MyRectItem
                  : public QGraphicsRectItem
              {
                  public:
                      MyRectItem(qreal x, qreal y, qreal width, qreal height,
                                 QGraphicsItem *parent = nullptr)
                          : QGraphicsRectItem{x, y, width, height, parent}
                      {
                          setFlag(QGraphicsItem::ItemSendsGeometryChanges);
                      }
              
                      QVariant itemChange(GraphicsItemChange change,
                                          const QVariant &value) override
                      {
                          if (change == ItemPositionHasChanged) {
                              qDebug() << "item pos:" << pos();
                          }
                          return QGraphicsRectItem::itemChange(change, value);
                      }
              
              };
              
              1. ... and this class is now used in the constructor of MainWindow:
              auto item = new MyRectItem{0, 0, 50, 50};
              view->scene()->addItem(item);
              

              Strangely I now never loose the touch events as long as the item is within the viewport() area. Even if it is outside the sceneRect() area.

              However, as before the touch evens are lost once the item was outside the viewport() area.

              M 1 Reply Last reply
              0
              • M Michael Lehn

                For better keeping track where the effect stats I made the following changes:

                1. Class MyRectItem that prints the position after it has changed:
                class MyRectItem
                    : public QGraphicsRectItem
                {
                    public:
                        MyRectItem(qreal x, qreal y, qreal width, qreal height,
                                   QGraphicsItem *parent = nullptr)
                            : QGraphicsRectItem{x, y, width, height, parent}
                        {
                            setFlag(QGraphicsItem::ItemSendsGeometryChanges);
                        }
                
                        QVariant itemChange(GraphicsItemChange change,
                                            const QVariant &value) override
                        {
                            if (change == ItemPositionHasChanged) {
                                qDebug() << "item pos:" << pos();
                            }
                            return QGraphicsRectItem::itemChange(change, value);
                        }
                
                };
                
                1. ... and this class is now used in the constructor of MainWindow:
                auto item = new MyRectItem{0, 0, 50, 50};
                view->scene()->addItem(item);
                

                Strangely I now never loose the touch events as long as the item is within the viewport() area. Even if it is outside the sceneRect() area.

                However, as before the touch evens are lost once the item was outside the viewport() area.

                M Offline
                M Offline
                Michael Lehn
                wrote on last edited by
                #7

                @Michael-Lehn said in QGraphicsView and Qt::WA_AcceptTouchEvents:

                However, as before the touch evens are lost once the item was outside the viewport() area.

                To be more precise: I have to move the item outside the viewport() area. Drop it there. Only then I loose the touch events.

                I do not loose the events if I keep holding the item while moving it outside the viewport and back.

                A 1 Reply Last reply
                0
                • M Michael Lehn

                  @Michael-Lehn said in QGraphicsView and Qt::WA_AcceptTouchEvents:

                  However, as before the touch evens are lost once the item was outside the viewport() area.

                  To be more precise: I have to move the item outside the viewport() area. Drop it there. Only then I loose the touch events.

                  I do not loose the events if I keep holding the item while moving it outside the viewport and back.

                  A Offline
                  A Offline
                  Asperamanca
                  wrote on last edited by
                  #8

                  @Michael-Lehn
                  The GraphicsView can only receive those touch event that are delivered to the parent widget of the viewport. In order to continue receiving events even when they happen outside of the widget area, you typically would grab the event (see e.g. QWidget::grabMouse or QGraphicsItem::grabMouse).

                  Unfortunately, I am not aware of a way to grab low-level touch events in QWidgets/QGraphicsView directly. You might need to go via QWidget::grabGesture or QGraphicsObject::grabGesture, which would require defining your gesture in terms of QGestureManager.

                  Alternatively, you could consider installing an application-level event filter, and handle the touch events on this low level, using your own logic to decide which widget (and thereby viewport) is supposed to receive which event.

                  Neither solution sounds very simple or satisfying, I'm afraid.

                  M 1 Reply Last reply
                  0
                  • A Asperamanca

                    @Michael-Lehn
                    The GraphicsView can only receive those touch event that are delivered to the parent widget of the viewport. In order to continue receiving events even when they happen outside of the widget area, you typically would grab the event (see e.g. QWidget::grabMouse or QGraphicsItem::grabMouse).

                    Unfortunately, I am not aware of a way to grab low-level touch events in QWidgets/QGraphicsView directly. You might need to go via QWidget::grabGesture or QGraphicsObject::grabGesture, which would require defining your gesture in terms of QGestureManager.

                    Alternatively, you could consider installing an application-level event filter, and handle the touch events on this low level, using your own logic to decide which widget (and thereby viewport) is supposed to receive which event.

                    Neither solution sounds very simple or satisfying, I'm afraid.

                    M Offline
                    M Offline
                    Michael Lehn
                    wrote on last edited by Michael Lehn
                    #9

                    @Asperamanca I am not sure if I described my problem accurately. I am not interested in touch events that happen outside of the viewport. The problem is that the viewport suddenly does not receive any touch events once an item has left its area. It still receives all other kind of events (mouse and key events).

                    IMHO this is a bug (either in my code or qt).

                    A 1 Reply Last reply
                    0
                    • M Michael Lehn

                      @Asperamanca I am not sure if I described my problem accurately. I am not interested in touch events that happen outside of the viewport. The problem is that the viewport suddenly does not receive any touch events once an item has left its area. It still receives all other kind of events (mouse and key events).

                      IMHO this is a bug (either in my code or qt).

                      A Offline
                      A Offline
                      Asperamanca
                      wrote on last edited by
                      #10

                      @Michael-Lehn
                      Do you receive touch events again after releasing and again touching into the viewport, after that mentioned item was moved out?

                      M 1 Reply Last reply
                      0
                      • A Offline
                        A Offline
                        Asperamanca
                        wrote on last edited by
                        #11

                        Ok, I tested your code on Windows (MSVC 2022 with Qt 6.5.2):
                        I can drag the item out and back into the window, all the while receiving touch events. This could be a Mac issue. Maybe take a look if you find something here: https://bugreports.qt.io/issues

                        1 Reply Last reply
                        0
                        • A Asperamanca

                          @Michael-Lehn
                          Do you receive touch events again after releasing and again touching into the viewport, after that mentioned item was moved out?

                          M Offline
                          M Offline
                          Michael Lehn
                          wrote on last edited by Michael Lehn
                          #12

                          @Asperamanca No, I do not. Once the item was dropped outside the viewport area I no longer receive any viewport event (but still mouse and key events).

                          Thanks for testing! When you drag it out and back: Did you drop it in-between? I mean drag it out, drop it, resize the window so that you can see it again, and then drag it back?

                          A 1 Reply Last reply
                          0
                          • M Michael Lehn

                            @Asperamanca No, I do not. Once the item was dropped outside the viewport area I no longer receive any viewport event (but still mouse and key events).

                            Thanks for testing! When you drag it out and back: Did you drop it in-between? I mean drag it out, drop it, resize the window so that you can see it again, and then drag it back?

                            A Offline
                            A Offline
                            Asperamanca
                            wrote on last edited by
                            #13

                            @Michael-Lehn
                            No, I tested with one long drag that goes beyond the window boundaries and back into the window. Is the other case something I should test, too?

                            M 1 Reply Last reply
                            0
                            • A Asperamanca

                              @Michael-Lehn
                              No, I tested with one long drag that goes beyond the window boundaries and back into the window. Is the other case something I should test, too?

                              M Offline
                              M Offline
                              Michael Lehn
                              wrote on last edited by
                              #14

                              @Asperamanca Yes, that would be great. Sorry for not stating this clear enough. Only when I drop the item outside the viewport I loose the viewport events. Without the drop everything is fine.

                              A 1 Reply Last reply
                              0
                              • M Michael Lehn

                                @Asperamanca Yes, that would be great. Sorry for not stating this clear enough. Only when I drop the item outside the viewport I loose the viewport events. Without the drop everything is fine.

                                A Offline
                                A Offline
                                Asperamanca
                                wrote on last edited by
                                #15

                                @Michael-Lehn Not sure the test setup is correct. I can move the item just as well with one finger (default move behavior, I guess), although I do not get into your viewport event handler then, of course.
                                I also added a timestamp to the qDebug() to see when I actually got events.

                                So....

                                • I can drag the item out of the window, and receive touch events until I release
                                • I can enlarge the window and see the item again
                                • I can start another drag operation on the item, and the viewport event recognizes it, and the item is dragged
                                M 1 Reply Last reply
                                0
                                • A Asperamanca

                                  @Michael-Lehn Not sure the test setup is correct. I can move the item just as well with one finger (default move behavior, I guess), although I do not get into your viewport event handler then, of course.
                                  I also added a timestamp to the qDebug() to see when I actually got events.

                                  So....

                                  • I can drag the item out of the window, and receive touch events until I release
                                  • I can enlarge the window and see the item again
                                  • I can start another drag operation on the item, and the viewport event recognizes it, and the item is dragged
                                  M Offline
                                  M Offline
                                  Michael Lehn
                                  wrote on last edited by
                                  #16

                                  Thanks, this helped me to understand better what actually goes wrong. I changed the code of MyView as follows:

                                  class MyView
                                      : public QGraphicsView
                                  {
                                      public:
                                          MyView(QWidget *parent = nullptr)
                                              : QGraphicsView{parent}
                                          {
                                              setScene(new QGraphicsScene);
                                              viewport()->setAttribute(Qt::WA_AcceptTouchEvents);
                                          }
                                  
                                          bool viewportEvent(QEvent *event) override
                                          {
                                              qDebug() << "MyView::viewportEvent(QEvent *event)";
                                              switch (event->type()) {
                                                  case QEvent::TouchBegin:
                                                  case QEvent::TouchUpdate:
                                                  case QEvent::TouchEnd:
                                                      qDebug() << "Some touch event";
                                                      return true;
                                                  default:
                                                      return QGraphicsView::viewportEvent(event);
                                              }
                                          }
                                  };
                                  

                                  So now I can distinguish between

                                  • getting any viewportEvent at all
                                  • and getting touch events in particular (here I no longer distinguish between 1 or 2 finger events)

                                  Now I did the what you described:

                                  @Asperamanca said in QGraphicsView and Qt::WA_AcceptTouchEvents:

                                  • I can drag the item out of the window, and receive touch events until I release
                                  • I can enlarge the window and see the item again
                                  • I can start another drag operation on the item, and the viewport event recognizes it, and the item is dragged

                                  First I get messages like

                                  MyView::viewportEvent(QEvent *event)
                                  Some touch event
                                  MyView::viewportEvent(QEvent *event)
                                  Some touch event
                                  ...
                                  

                                  when I move the item around. Once the item was dropped outside the viewport I just get

                                  MyView::viewportEvent(QEvent *event)
                                  MyView::viewportEvent(QEvent *event)
                                  ...
                                  

                                  So I actually still get viewport events. Except for touch events. It seems that touch events are now filtered out or no longer sent.

                                  Moving the item around was never the problem. The problem is that I use touch events gestures for zooming.

                                  1 Reply Last reply
                                  0

                                  • Login

                                  • Login or register to search.
                                  • First post
                                    Last post
                                  0
                                  • Categories
                                  • Recent
                                  • Tags
                                  • Popular
                                  • Users
                                  • Groups
                                  • Search
                                  • Get Qt Extensions
                                  • Unsolved