C++/Qt: предотвратить `mouseMoveEvent` в`QCursor::setPos()`

В настоящее время я занимаюсь разработкой приложения для просмотра изображений. В этом приложении у меня есть так называемая функция панорамирования. Это означает, что, удерживая определенную кнопку мыши, пользователь может увеличивать изображение, перемещаясь вперед и назад.

Он работает нормально, но при использовании этой функции мышь (естественно) перемещается вверх и вниз по экрану и в какой-то момент достигнет границ экрана, что приведет к ее остановке. Вместо этого мне бы хотелось поведение, при котором мышь остается неподвижной и изменяется только увеличение изображения.

Я пытался добиться этого, вызывая QCursor::setPos внутри QWidget::mouseMoveEvent и вернуть мышь в исходное положение после того, как я обработал ход. Это работает настолько, что мышь остается почти неподвижной (шевелится вперед и назад). Однако это приведет к повторному вызову события перемещения мыши, что аннулирует только что выполненную настройку. Это приведет к эффекту "покачивания". Каждая настройка будет немедленно отменена.

Вот фрагмент кода, чтобы вы поняли, что я делаю:

void ImageView::mouseMoveEvent(QMouseEvent *e) {
    //some code
    if (_panZooming) {
        //some code here

        //doesn't work as expected because it invokes this event again
        QCursor::setPos(mapToGlobal(_initialMousePosition.toPoint()));
    }
}

Есть ли способ предотвратить событие перемещения мыши при использовании QCursor::setPos?

2 ответа

Решение

Предполагая, что вы не вызываете базовый класс mouseMoveEvent, вы должны принять событие, чтобы пометить его как обрабатываемое. По умолчанию они принимаются, когда вы повторно реализуете событие, но это более ясно, чтобы быть явным. Вызов e->accept( ),

Также рекомендуется, чтобы при обработке какого-либо из событий мыши вы обрабатывали все, кроме возможного двойного щелчка мышью.

Вот пример того, как держать мышь неподвижно, хотя в OS X иногда возникает мерцание, которое возникает из-за того, как Qt обрабатывает события

class MyWidget : public QWidget
{
    void mousePressEvent(QMouseEvent* e)
    {
        m_pos = e->globalPos();
        m_lastPos = m_pos;
        QWidget::mousePressEvent(e);
    }

    void mouseMoveEvent(QMouseEvent* e)
    {
       // Calculate  relative zoom factor
       // scaled down ( / 10 ) for image zooming

        m_zoomFactor += ((float)e->globalPos().y() - m_lastPos.y()) / 10;

        QCursor::setPos(m_pos);
        m_lastPos = m_pos;
        e->accept();

        qDebug() << m_zoomFactor << endl;
    }

    void mouseReleaseEvent(QMouseEvent* e)
    {
        QWidget::mouseReleaseEvent(e);
    }

private:
    QPoint m_pos;
    QPoint m_lastPos;

    float m_zoomFactor = 0; // C++ 11 initialisation
};

Если вам не нужно держать мышь неподвижно, выньте QCursor::setPos вызов, и он все равно будет получать события перемещения, когда курсор находится за пределами виджета, в то время как кнопка мыши удерживается нажатой.

Тем не менее, пользователь может лучше скрывать курсор при масштабировании.

У меня был бы флаг, чтобы отключить событие с будет ложным по умолчанию.

внутри события проверьте, если флаг равен false, затем выполните операцию масштабирования, установите флаг в значение true и сбросьте курсор.

тогда событие будет вызвано снова, и флаг будет истинным, поэтому вы установите флаг в ложь, и вы будете готовы обработать следующее событие.

Вам просто нужно убедиться, что у вас нет двух или более вызовов для вызова события мыши с фактической мыши, прежде чем получить событие от вызова setCursor.

Не используйте event->pos() в событиях мыши, используйте QCursor::pos() intead и проверьте, изменилось ли оно. Как это:

void MyWidget::mousePressEvent(QMouseEvent *)
{
    mPrevPos=QCursor::pos();
    mMoving=false;
}

void MyWidget::mouseMoveEvent(QMouseEvent *)
{
    auto cursorPos=QCursor::pos();
    if(mPressedPos==cursorPos){
        return;
    }
    if(!mMoving
        && (cursorPos-mPrevPos).manhattanLength()>QApplication::startDragDistance()){
        mMoving=true;
    }
    if(mMoving){
        auto diff=cursorPos-mPrevPos;

        // move something using diff

        QCursor::setPos(mPrevPos);
    }
}

void MyWidget::mouseReleaseEvent(QMouseEvent *)
{
    mMoving=false;
}
void MyWidget::leaveEvent(QEvent *)
{
    mMoving=false;
}
Другие вопросы по тегам