QCustomPlot and multitouch zoom



  • Hi everybody.

    I use QCustomPlot library and I would like use my application on tablet.
    But I have some trouble to interact with 2 touchs for zoom.

    I try to write this:

    bool CustomPlot::event(QEvent* event)
    {
    if(event->type() == QEvent::TouchBegin ||
    event->type() == QEvent::TouchUpdate ||
    event->type() == QEvent::TouchEnd ){
    QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event);
    QListQTouchEvent::TouchPoint touchPoints = touchEvent->touchPoints();

        if(touchPoints.count() == 1 && touchEvent->touchPointStates().testFlag(Qt::TouchPointReleased))
            _release2touch = false;
    
        if (touchPoints.count() == 1 && !_release2touch)
        {
            switch (event->type()) {
            case QEvent::TouchBegin:
            {
                QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event);
                QTouchEvent::TouchPoint touchPoints = touchEvent->touchPoints().first();
                QMouseEvent *e = new QMouseEvent(QEvent::MouseButtonPress,
                                                 touchPoints.pos(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
    
                emit mousePressEvent(e);
                return true;
    
            }break;
    
            case QEvent::TouchUpdate:
            {
                QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event);
                QTouchEvent::TouchPoint touchPoints = touchEvent->touchPoints().first();
                QMouseEvent *e = new QMouseEvent(QEvent::MouseMove,
                                                 touchPoints.pos(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
    
                emit mouseMoveEvent(e);
                return true;
    
            }break;
    
            case QEvent::TouchEnd:{
                QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event);
                QTouchEvent::TouchPoint touchPoints = touchEvent->touchPoints().first();
                QMouseEvent *e = new QMouseEvent(QEvent::MouseButtonRelease,
                                                 touchPoints.pos(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
    
                emit mouseReleaseEvent(e);
                return true;
    
            }break;
    
            default:
                return false;
                break;
            }
        }else if (touchPoints.count() == 2) {
            _release2touch = true;
            // determine scale factor
            const QTouchEvent::TouchPoint &touchPoint0 = touchPoints.first();
            const QTouchEvent::TouchPoint &touchPoint1 = touchPoints.last();
            double currentScaleFactor =
                    QLineF(touchPoint0.pos(), touchPoint1.pos()).length() /
                    QLineF(touchPoint0.lastPos(), touchPoint1.lastPos()).length();
    
            QPointF centreZoom = QPointF((touchPoint0.pos().x()+ touchPoint1.pos().x())/2 ,
                                         (touchPoint0.pos().y()+ touchPoint1.pos().y())/2);
            QPointF lastCenterZoom = QPointF((touchPoint0.lastPos().x()+ touchPoint1.lastPos().x())/2 ,
                                             (touchPoint0.lastPos().y()+ touchPoint1.lastPos().y())/2);
    
            if (touchEvent->touchPointStates().testFlag(Qt::TouchPointReleased))
                currentScaleFactor = 1;
    
            if(currentScaleFactor<1)
                currentScaleFactor = currentScaleFactor + (1-currentScaleFactor)/8;
            else
                currentScaleFactor = currentScaleFactor+(currentScaleFactor-1)/8;
    
            currentScaleFactor =1/currentScaleFactor;
    
            double diffX = this->xAxis->pixelToCoord(lastCenterZoom.x())
                    - this->xAxis->pixelToCoord(centreZoom.x());
    
            double diffY = this->yAxis->pixelToCoord(lastCenterZoom.y())
                    - this->yAxis->pixelToCoord(centreZoom.y());
    
            if(!touchEvent->touchPointStates().testFlag(Qt::TouchPointReleased)){
                this->xAxis->moveRange(diffX);
                this->yAxis->moveRange(diffY);
                this->xAxis->scaleRange(currentScaleFactor,this->xAxis->pixelToCoord(centreZoom.x()));
                this->yAxis->scaleRange(currentScaleFactor,this->yAxis->pixelToCoord(centreZoom.y()));
                this->replot();
            }
            return true;
        }
    }else{
        return QWidget::event(event);
    }
    return false;  // a ajouter ?
    

    }

    When I was in 32 bits on Qt 5.2 this code works fine...
    I upgrade my code to 64 bits with Qt 5.4, and I have some trouble, the interaction is not running fluid.

    Someone can hlep me ? I'm not sure with my methode?


  • Lifetime Qt Champion

    Hi,

    The change of architecture should not have any influence on the matter but you might be hitting a regression. What difference are you seeing ?



  • @SGaist Hi, I think is come from Windows 8.
    My tablet run under windows 8.1 and simulate the touch point by mouse action. I have make some modification like that :

    if(_touchDevice)
    {
    if(event->type() == QEvent::MouseButtonDblClick ||
    event->type() == QEvent::MouseButtonPress ||
    event->type() == QEvent::MouseButtonRelease ||
    event->type() == QEvent::MouseMove ||
    event->type() == QEvent::MouseTrackingChange)
    {
    event->ignore();
    return true;
    }
    }

    And with this, it work very well and it's fluid. But now it doesn't work on PC ... Because I block mouse even .


  • Lifetime Qt Champion

    You should take a look at the bug report system to see if it's something known



  • @Franckynos @SGaist
    Hello,
    I have used your function. I got these errors...

    1. _release2touch was not declared in this scope...I hope it is of type bool ,so i have declared a member variable bool release2touch. May i know the use of it?
    2. error: cannot call member function 'virtual bool QWidget::event(QEvent*)' without object
      return QWidget::event(event); ....At the return statement it is there...What should i do to remove this error?
    3. How should i make use of this function ? I mean when does this function is called ?How can I call this function esp from QML if you don't know qml atleast give me an example in C+++.thanks a lot.


  • @vishnu said:

    May i know the use of it?

    1. yes it's a bool at false in constructor
    2. you have forget event in prototype :
      'virtual bool QWidget::event(QEvent*)' without object in => 'virtual bool QWidget::event(QEvent* !!! event !!! )' without object
    CustomPlot::CustomPlot(QWidget *parent)
        :QCustomPlot(parent)
    {
        setAttribute(Qt::WA_AcceptTouchEvents);
        _release2touch = false;
        _touchDevice = false;
    }
    
    bool CustomPlot::event(QEvent* event)
    {
        if(_touchDevice)
        {
            if(event->type() == QEvent::MouseButtonDblClick ||
                    event->type() == QEvent::MouseButtonPress ||
                    event->type() == QEvent::MouseButtonRelease ||
                    event->type() == QEvent::MouseMove ||
                    event->type() == QEvent::MouseTrackingChange)
            {
                event->ignore();
                return true;
            }
    
            if(event->type() == QEvent::Wheel)
                _touchDevice = false;
        }
    
        if(event->type() == QEvent::TouchBegin ||
                event->type() == QEvent::TouchUpdate ||
                event->type() == QEvent::TouchEnd ){
    
            if(!_touchDevice)
                _touchDevice = true;
    
            QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event);
            QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints();
    
            if(touchPoints.count() == 1 && touchEvent->touchPointStates().testFlag(Qt::TouchPointReleased))
                _release2touch = false;
    
            if (touchPoints.count() == 1 && !_release2touch)
            {
                switch (event->type()) {
                case QEvent::TouchBegin:
                {
                    QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event);
                    QTouchEvent::TouchPoint touchPoints = touchEvent->touchPoints().first();
                    QMouseEvent *e = new QMouseEvent(QEvent::MouseButtonPress,
                                                     touchPoints.pos(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
    
                    mousePressEvent(e); //==> meilleure methode
                }break;
    
                case QEvent::TouchUpdate:
                {
                    QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event);
                    QTouchEvent::TouchPoint touchPoints = touchEvent->touchPoints().first();
                    QMouseEvent *e = new QMouseEvent(QEvent::MouseMove,
                                                     touchPoints.pos(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
    
                    mouseMoveEvent(e);
                }break;
    
                case QEvent::TouchEnd:{
                    QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event);
                    QTouchEvent::TouchPoint touchPoints = touchEvent->touchPoints().first();
                    QMouseEvent *e = new QMouseEvent(QEvent::MouseButtonRelease,
                                                     touchPoints.pos(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
    
                    mouseReleaseEvent(e);
                }break;
    
                default:
                    break;
                }
            }else if (touchPoints.count() == 2) {
                _release2touch = true;
                // determine scale factor
                const QTouchEvent::TouchPoint &touchPoint0 = touchPoints.first();
                const QTouchEvent::TouchPoint &touchPoint1 = touchPoints.last();//   touchPoints.last();
    
                double currentScaleFactor =
                        QLineF(touchPoint0.pos(), touchPoint1.pos()).length() /
                        QLineF(touchPoint0.lastPos(), touchPoint1.lastPos()).length();
    
                QPointF centreZoom = QPointF((touchPoint0.pos().x()+ touchPoint1.pos().x())/2 ,
                                             (touchPoint0.pos().y()+ touchPoint1.pos().y())/2);
                QPointF lastCenterZoom = QPointF((touchPoint0.lastPos().x()+ touchPoint1.lastPos().x())/2 ,
                                                 (touchPoint0.lastPos().y()+ touchPoint1.lastPos().y())/2);
    
                if (touchEvent->touchPointStates().testFlag(Qt::TouchPointReleased))
                    currentScaleFactor = 1;
    
    
                if(currentScaleFactor<1)
                    currentScaleFactor = currentScaleFactor + (1-currentScaleFactor)/8;
                else
                    currentScaleFactor = currentScaleFactor+ (currentScaleFactor-1)/8;
    
                currentScaleFactor =1/currentScaleFactor;
    
                double diffX = this->xAxis->pixelToCoord(lastCenterZoom.x())
                        - this->xAxis->pixelToCoord(centreZoom.x());
    
                double diffY = this->yAxis->pixelToCoord(lastCenterZoom.y())
                        - this->yAxis->pixelToCoord(centreZoom.y());
    
                if(!touchEvent->touchPointStates().testFlag(Qt::TouchPointReleased)){
                    this->xAxis->moveRange(diffX);
                    this->yAxis->moveRange(diffY);
                    this->xAxis->scaleRange(currentScaleFactor,this->xAxis->pixelToCoord(centreZoom.x()));
                    this->yAxis->scaleRange(currentScaleFactor,this->yAxis->pixelToCoord(centreZoom.y()));
                    this->replot();
                }
            }
            return true;
        }
        return QWidget::event(event);
    }
    

Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.