如何使用 Qt 防止 QCursor::setPos() 上的 mouseMoveEvent?
How to prevent mouseMoveEvent on QCursor::setPos() using Qt?
我目前正在开发图像查看器应用程序。在此应用程序中,我有一个所谓的 "pan-zoom" 功能。这意味着,当按住某个鼠标按钮时,用户可以通过前后平移来缩放图像。
它工作正常,但随着使用该功能,鼠标(自然地)在屏幕上上下移动,并会在某个点到达屏幕边界,这将使其停止。相反,我想要一种鼠标保持静止并且只有图像放大倍率发生变化的行为。
我试图通过在 QWidget::mouseMoveEvent
中调用 QCursor::setPos
来实现这一点,并在处理完移动后将鼠标重置到初始位置。它的工作原理是鼠标几乎保持静止(它来回摆动)。但是,这将导致再次调用鼠标移动事件,从而有效地取消我刚刚所做的调整。这将导致 "wiggling" 效果。每一次调整都会立即撤销。
这里是一段代码,所以你可以了解我在做什么:
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
时防止鼠标移动事件发生?
我会有一个标志来禁用事件,默认情况下为 false。
在事件内部检查标志是否为假,然后执行缩放操作,将标志设置为真并重置光标。
然后该事件将再次被调用并且标志将为真,因此您将标志设置为假并且您将准备好处理下一个事件。
您只需确保在从 setCursor 调用接收事件之前,您没有两次或多次调用从实际鼠标触发的鼠标事件。
假设您没有调用基 class mouseMoveEvent
,您应该 accept the event 将其标记为正在处理。默认情况下,当您重新实现该事件时,它们会被接受,但明确表示会更清楚。呼叫e->accept( )
。
还建议如果您处理任何鼠标事件,you should handle all,鼠标双击可能除外。
这是一个保持鼠标静止不动的示例,尽管在 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
调用,当光标位于小部件外部且按住鼠标按钮时,它仍会接收移动事件。
不过,缩放时可能会有更好的用户体验hiding the cursor。
不要在鼠标事件中使用 event->pos(),改用 QCursor::pos() 并检查它是否发生了变化。像这样:
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;
}
我目前正在开发图像查看器应用程序。在此应用程序中,我有一个所谓的 "pan-zoom" 功能。这意味着,当按住某个鼠标按钮时,用户可以通过前后平移来缩放图像。
它工作正常,但随着使用该功能,鼠标(自然地)在屏幕上上下移动,并会在某个点到达屏幕边界,这将使其停止。相反,我想要一种鼠标保持静止并且只有图像放大倍率发生变化的行为。
我试图通过在 QWidget::mouseMoveEvent
中调用 QCursor::setPos
来实现这一点,并在处理完移动后将鼠标重置到初始位置。它的工作原理是鼠标几乎保持静止(它来回摆动)。但是,这将导致再次调用鼠标移动事件,从而有效地取消我刚刚所做的调整。这将导致 "wiggling" 效果。每一次调整都会立即撤销。
这里是一段代码,所以你可以了解我在做什么:
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
时防止鼠标移动事件发生?
我会有一个标志来禁用事件,默认情况下为 false。
在事件内部检查标志是否为假,然后执行缩放操作,将标志设置为真并重置光标。
然后该事件将再次被调用并且标志将为真,因此您将标志设置为假并且您将准备好处理下一个事件。
您只需确保在从 setCursor 调用接收事件之前,您没有两次或多次调用从实际鼠标触发的鼠标事件。
假设您没有调用基 class mouseMoveEvent
,您应该 accept the event 将其标记为正在处理。默认情况下,当您重新实现该事件时,它们会被接受,但明确表示会更清楚。呼叫e->accept( )
。
还建议如果您处理任何鼠标事件,you should handle all,鼠标双击可能除外。
这是一个保持鼠标静止不动的示例,尽管在 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
调用,当光标位于小部件外部且按住鼠标按钮时,它仍会接收移动事件。
不过,缩放时可能会有更好的用户体验hiding the cursor。
不要在鼠标事件中使用 event->pos(),改用 QCursor::pos() 并检查它是否发生了变化。像这样:
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;
}