QMouseEvent,用于在QWidget上进行单次移动

时间:2018-10-22 07:57:57

标签: c++ qt qmouseevent

为什么QMouseEvent在QWidget上传递单个事件的多个事件?

我正在实现简单的拖动效果,但是结果不是我期望的。

以下代码会将小部件移到新位置,但立即将其移回到原始位置。

customwidget.h

#ifndef CUSTOMWIDGET_H
#define CUSTOMWIDGET_H

#include <QWidget>
#include <fstream>

class CustomWidget : public QWidget
{
    Q_OBJECT
public:
    explicit CustomWidget(QWidget *parent = nullptr);
    ~CustomWidget();

protected:
    // define the painting agorithm to see the area of this widget
    void paintEvent(QPaintEvent* ev);

    // handle the pressing event to initialize the dragging algorithm
    // and to track the start of moving event
    void mousePressEvent(QMouseEvent* ev);

    // implement the dragging algorithm
    void mouseMoveEvent(QMouseEvent* ev);

    // handle the releasing event to track the end of moving event
    void mouseReleaseEvent(QMouseEvent* ev);

private:
    std::ofstream fout; // open file "debug.txt"
    QPoint prev; // to save the previous point of cursor.
};

#endif // CUSTOMWIDGET_H

customwidget.cpp

#include "customwidget.h"
#include <QMouseEvent>
#include <QPaintEvent>
#include <QPainter>
#include <QBrush>

CustomWidget::CustomWidget(QWidget *parent) : QWidget(parent)
{
    // open file for output
    fout.open("debug.txt");

    // set the widget size and position
    setGeometry(0, 0, 100, 100);
}

CustomWidget::~CustomWidget()
{
    // close file when program ended
    fout.close();
}

void CustomWidget::paintEvent(QPaintEvent *ev)
{
    // draw the area with blue color
    QPainter painter(this);
    QBrush brush(Qt::GlobalColor::blue);
    painter.setBrush(brush);
    painter.setBackground(brush);
    painter.drawRect(ev->rect());
}

void CustomWidget::mousePressEvent(QMouseEvent *ev)
{
    ev->accept();

    // debug output
    fout << "pressed at (" << ev->x() << ',' << ev->y() << ')' << std::endl;

    // initialize the dragging start point
    prev = ev->pos();
}

void CustomWidget::mouseMoveEvent(QMouseEvent *ev)
{
    ev->accept();

    // get the cursor position of this event
    const QPoint& pos = ev->pos();

    // debug output
    fout << "moved from (" << prev.x() << ',' << prev.y() << ") to ("
         << pos.x() << ',' << pos.y() << ')' << std::endl;

    // calculate the cursor movement
    int dx = pos.x() - prev.x();
    int dy = pos.y() - prev.y();

    // move the widget position to match the direction of the cursor.
    move(geometry().x() + dx, geometry().y() + dy);

    // update the cursor position for the next event
    prev = pos;
}

void CustomWidget::mouseReleaseEvent(QMouseEvent *ev)
{
    ev->accept();
    fout << "released at (" << ev->x() << ',' << ev->y() << ')' << std::endl;
}

main.cpp

#include "customwidget.h"
#include <QApplication>
#include <QMainWindow>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    // generate simple main window.
    QMainWindow w;

    // set the size of the window.
    w.setGeometry(0, 0, 800, 800);

    // generate the CustomWidget
    CustomWidget *widget = new CustomWidget(&w);

    // display the window containing the widget
    w.show();

    return a.exec();
}

并且光标一动,debug.txt的结果就是

CustomWidget pressed at (79,83)
CustomWidget moved from (79,83) to (79,83)
CustomWidget moved from (79,83) to (80,83)
CustomWidget moved from (80,83) to (79,83)
CustomWidget released at (80,83)

结果是将小部件移到新位置一会儿,然后再将其移回到其原始位置。

该程序的外观几乎看起来像是该部件永远不会被移动,无论您如何拖动该部件。

我的理论是事件管理器在您移动光标时传递事件。但 在处理完第一个事件后,管理器将传递另一个与小部件的新位置和光标当前位置有关的事件。然后,该过程会将小部件移回原来的位置。

尽管我可以更改从中获取光标位置的方法

ev->pos()

ev->globalPos()

解决问题。

但是仍然想知道为什么事件管理器会那样做。

1 个答案:

答案 0 :(得分:0)

您必须执行以下操作:

  • 在鼠标按下事件中,存储相对于小部件的鼠标光标偏移量,
  • 移动小部件,以便鼠标光标将始终保留初始的非零偏移量,
  • 重置鼠标释放事件的偏移量。

代码(草稿)可能类似于:

void CustomWidget::mousePressEvent(QMouseEvent* event)
{
    // m_offset is a member variable of CustomWidget
    m_offset = event->globalPos() - pos();
    QWidget::mousePressEvent(event);
}

void CustomWidget::mouseMoveEvent(QMouseEvent* event)
{
    if (!m_offset.isNull()) {
        move(event->globalPos() - m_offset);
    }
    QWidget::mouseMoveEvent(event);
}

void CustomWidget::mouseReleaseEvent(QMouseEvent* event)
{
    // Reset the offset value to prevent the movement.
    m_offset = QPoint();
    QWidget::mouseReleaseEvent(event);
}