QMouseEvent для одиночного движения на QWidget - PullRequest
0 голосов
/ 22 октября 2018

Почему 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 голосов
/ 22 октября 2018

Вы должны сделать следующее:

  • При событии нажатия мыши сохранить смещение курсора мыши относительно виджета,
  • Переместить виджет так, чтобы курсор мыши всегда сохранялсяначальное ненулевое смещение,
  • Сброс смещения при событии отпускания мыши.

Код (черновик) может выглядеть следующим образом:

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