QMouseEvent для одиночного движения на QWidget
Почему 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 ответ
Вы должны сделать следующее:
- При событии нажатия мыши сохранить смещение курсора мыши относительно виджета,
- Переместите свой виджет так, чтобы курсор мыши всегда сохранял исходное ненулевое смещение,
- Сбросить смещение при отпускании мыши.
Код (черновик) может выглядеть так:
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);
}