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;
}