重新实现鼠标事件时对 QGraphicsView 的奇怪影响
Strange effect on QGraphicsView upon Reimplementation of Mouse Event
我使用这个源代码开始了一个小项目:
#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsRectItem>
#include <QGraphicsLineItem>
class CustomRectItem : public QGraphicsRectItem
{
public:
CustomRectItem (const QRectF& rect) : QGraphicsRectItem(rect) {
setFlag(QGraphicsItem::ItemIsMovable);
setFlag(QGraphicsItem::ItemSendsScenePositionChanges);
setAcceptHoverEvents(true);
}
void addLine(QGraphicsLineItem *line1, QGraphicsLineItem *line2) {
if (this->data(0).toString() == "_p1") {
this->leftLine = line1;
this->topLine = line2;
}
if (this->data(0).toString() == "_p2") {
this->topLine = line1;
this->rightLine = line2;
}
if (this->data(0).toString() == "_p3") {
this->rightLine = line1;
this->bottomLine = line2;
}
if (this->data(0).toString() == "_p4") {
this->bottomLine = line1;
this->leftLine = line2;
}
}
QPointF center(void) {
return QPointF((rect().x() + rect().width() / 2),
(rect().y() + rect().height() / 2));
}
QVariant itemChange(GraphicsItemChange change, const QVariant &value)
{
if (change == ItemPositionChange && scene()) {
// value is the new position.
QPointF newPos = value.toPointF();
moveLineToCenter(newPos, this->data(0).toString());
}
return QGraphicsItem::itemChange(change, value);
}
void moveLineToCenter(QPointF newPos, QString pointString) {
// Converts the polygon upper left position
// to the upper left "handle"-rect center position
qreal xOffset = rect().x() + rect().width()/2;
qreal yOffset = rect().y() + rect().height()/2;
QPointF newCenterPos = QPointF(newPos.x() + xOffset, newPos.y() + yOffset);
QPointF p1;
QPointF p2;
// upper-left point
if (pointString == "_p1") {
p1 = leftLine->line().p1();
p2 = newCenterPos;
leftLine->setLine(QLineF(p1, p2));
p1 = newCenterPos;
p2 = topLine->line().p2();
topLine->setLine(QLineF(p1, p2));
// upper-right point
} else if (pointString == "_p2") {
p1 = topLine->line().p1();
p2 = newCenterPos;
topLine->setLine(QLineF(p1, p2));
p1 = newCenterPos;
p2 = rightLine->line().p2();
rightLine->setLine(QLineF(p1, p2));
// lower-right point
} else if (pointString == "_p3") {
p1 = rightLine->line().p1();
p2 = newCenterPos;
rightLine->setLine(QLineF(p1, p2));
p1 = newCenterPos;
p2 = bottomLine->line().p2();
bottomLine->setLine(QLineF(p1, p2));
// lower-left point
} else if (pointString == "_p4") {
p1 = bottomLine->line().p1();
p2 = newCenterPos;
bottomLine->setLine(QLineF(p1, p2));
p1 = newCenterPos;
p2 = leftLine->line().p2();
leftLine->setLine(QLineF(p1, p2));
} else {
return;
}
}
/////////////////////////////////////////////////////
/* -- comment-in this block to observe problem -- //
/////////////////////////////////////////////////////
protected:
virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event) {
Q_UNUSED(event);
this->setCursor(Qt::SizeAllCursor);
}
virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) {
Q_UNUSED(event);
this->unsetCursor();
}
virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) {
Q_UNUSED(event);
this->setCursor(Qt::BlankCursor);
}
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
Q_UNUSED(event);
this->unsetCursor();
this->data(0).toString();
if (this->isUnderMouse()) {
this->setCursor(Qt::SizeAllCursor);
}
}
/////////////////////////////////////////////////////
// -- end of problem-causing block -- //
///////////////////////////////////////////////////// */
private:
QGraphicsLineItem *topLine;
QGraphicsLineItem *rightLine;
QGraphicsLineItem *bottomLine;
QGraphicsLineItem *leftLine;
};
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QGraphicsScene scene;
CustomRectItem *custRect1 = new CustomRectItem(QRectF(30, 30, 10, 10));
scene.addItem(custRect1);
custRect1->setData(0, "_p1");
CustomRectItem *custRect2 = new CustomRectItem(QRectF(70, 30, 10, 10));
scene.addItem(custRect2);
custRect2->setData(0, "_p2");
CustomRectItem *custRect3 = new CustomRectItem(QRectF(70, 70, 10, 10));
scene.addItem(custRect3);
custRect3->setData(0, "_p3");
CustomRectItem *custRect4 = new CustomRectItem(QRectF(30, 70, 10, 10));
scene.addItem(custRect4);
custRect4->setData(0, "_p4");
QGraphicsLineItem *topLine = scene.addLine(QLineF(custRect1->center(), custRect2->center()));
QGraphicsLineItem *rightLine = scene.addLine(QLineF(custRect2->center(), custRect3->center()));
QGraphicsLineItem *bottomLine = scene.addLine(QLineF(custRect3->center(), custRect4->center()));
QGraphicsLineItem *leftLine = scene.addLine(QLineF(custRect4->center(), custRect1->center()));
custRect1->addLine(leftLine, topLine);
custRect2->addLine(topLine, rightLine);
custRect3->addLine(rightLine, bottomLine);
custRect4->addLine(bottomLine, leftLine);
QGraphicsView view(&scene);
view.show();
return a.exec();
}
编译上面的代码你应该得到一个小的 window,它只包含 QGraphivsView、一个多边形和四个连接到多边形顶点的手柄。
现在使用鼠标移动手柄。再次移动它。
一切都应该像您对任何图形编辑器的期望一样。
接下来,在重新实现一些鼠标事件的代码块中添加注释,基本上只是在将鼠标悬停在手柄上并拖动手柄时更改光标。
重新编译并重新开始移动一个句柄。再次移动同一个手柄,然后……看看会发生什么!什么鬼?它跳回到它的初始位置。
有人知道如何解释这种行为以及如何解决它吗?
谢谢!
您需要为 mousePressEvent 和 mouseReleaseEvent 方法调用基础 class 实现:
QGraphicsRectItem::mousePressEvent (event);
和
QGraphicsRectItem::mouseReleaseEvent (event);
根据文档,基本实现处理鼠标抓取、移动和选择,因此您需要在这种情况下调用它们。我有点惊讶把手完全移动了,它们显然是移动的,但是项目的位置在内部没有得到正确处理。
确保在实施后调用基础 class 事件以确保保持正常功能。
virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event) {
this->setCursor(Qt::SizeAllCursor);
//
QGraphicsRectItem::hoverEnterEvent( event );
}
virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) {
this->unsetCursor();
//
QGraphicsRectItem::hoverLeaveEvent( event );
}
virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) {
this->setCursor(Qt::BlankCursor);
//
QGraphicsRectItem::mousePressEvent( event );
}
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
this->unsetCursor();
this->data(0).toString();
if (this->isUnderMouse()) {
this->setCursor(Qt::SizeAllCursor);
}
//
QGraphicsRectItem::mouseReleaseEvent( event );
}
我使用这个源代码开始了一个小项目:
#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsRectItem>
#include <QGraphicsLineItem>
class CustomRectItem : public QGraphicsRectItem
{
public:
CustomRectItem (const QRectF& rect) : QGraphicsRectItem(rect) {
setFlag(QGraphicsItem::ItemIsMovable);
setFlag(QGraphicsItem::ItemSendsScenePositionChanges);
setAcceptHoverEvents(true);
}
void addLine(QGraphicsLineItem *line1, QGraphicsLineItem *line2) {
if (this->data(0).toString() == "_p1") {
this->leftLine = line1;
this->topLine = line2;
}
if (this->data(0).toString() == "_p2") {
this->topLine = line1;
this->rightLine = line2;
}
if (this->data(0).toString() == "_p3") {
this->rightLine = line1;
this->bottomLine = line2;
}
if (this->data(0).toString() == "_p4") {
this->bottomLine = line1;
this->leftLine = line2;
}
}
QPointF center(void) {
return QPointF((rect().x() + rect().width() / 2),
(rect().y() + rect().height() / 2));
}
QVariant itemChange(GraphicsItemChange change, const QVariant &value)
{
if (change == ItemPositionChange && scene()) {
// value is the new position.
QPointF newPos = value.toPointF();
moveLineToCenter(newPos, this->data(0).toString());
}
return QGraphicsItem::itemChange(change, value);
}
void moveLineToCenter(QPointF newPos, QString pointString) {
// Converts the polygon upper left position
// to the upper left "handle"-rect center position
qreal xOffset = rect().x() + rect().width()/2;
qreal yOffset = rect().y() + rect().height()/2;
QPointF newCenterPos = QPointF(newPos.x() + xOffset, newPos.y() + yOffset);
QPointF p1;
QPointF p2;
// upper-left point
if (pointString == "_p1") {
p1 = leftLine->line().p1();
p2 = newCenterPos;
leftLine->setLine(QLineF(p1, p2));
p1 = newCenterPos;
p2 = topLine->line().p2();
topLine->setLine(QLineF(p1, p2));
// upper-right point
} else if (pointString == "_p2") {
p1 = topLine->line().p1();
p2 = newCenterPos;
topLine->setLine(QLineF(p1, p2));
p1 = newCenterPos;
p2 = rightLine->line().p2();
rightLine->setLine(QLineF(p1, p2));
// lower-right point
} else if (pointString == "_p3") {
p1 = rightLine->line().p1();
p2 = newCenterPos;
rightLine->setLine(QLineF(p1, p2));
p1 = newCenterPos;
p2 = bottomLine->line().p2();
bottomLine->setLine(QLineF(p1, p2));
// lower-left point
} else if (pointString == "_p4") {
p1 = bottomLine->line().p1();
p2 = newCenterPos;
bottomLine->setLine(QLineF(p1, p2));
p1 = newCenterPos;
p2 = leftLine->line().p2();
leftLine->setLine(QLineF(p1, p2));
} else {
return;
}
}
/////////////////////////////////////////////////////
/* -- comment-in this block to observe problem -- //
/////////////////////////////////////////////////////
protected:
virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event) {
Q_UNUSED(event);
this->setCursor(Qt::SizeAllCursor);
}
virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) {
Q_UNUSED(event);
this->unsetCursor();
}
virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) {
Q_UNUSED(event);
this->setCursor(Qt::BlankCursor);
}
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
Q_UNUSED(event);
this->unsetCursor();
this->data(0).toString();
if (this->isUnderMouse()) {
this->setCursor(Qt::SizeAllCursor);
}
}
/////////////////////////////////////////////////////
// -- end of problem-causing block -- //
///////////////////////////////////////////////////// */
private:
QGraphicsLineItem *topLine;
QGraphicsLineItem *rightLine;
QGraphicsLineItem *bottomLine;
QGraphicsLineItem *leftLine;
};
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QGraphicsScene scene;
CustomRectItem *custRect1 = new CustomRectItem(QRectF(30, 30, 10, 10));
scene.addItem(custRect1);
custRect1->setData(0, "_p1");
CustomRectItem *custRect2 = new CustomRectItem(QRectF(70, 30, 10, 10));
scene.addItem(custRect2);
custRect2->setData(0, "_p2");
CustomRectItem *custRect3 = new CustomRectItem(QRectF(70, 70, 10, 10));
scene.addItem(custRect3);
custRect3->setData(0, "_p3");
CustomRectItem *custRect4 = new CustomRectItem(QRectF(30, 70, 10, 10));
scene.addItem(custRect4);
custRect4->setData(0, "_p4");
QGraphicsLineItem *topLine = scene.addLine(QLineF(custRect1->center(), custRect2->center()));
QGraphicsLineItem *rightLine = scene.addLine(QLineF(custRect2->center(), custRect3->center()));
QGraphicsLineItem *bottomLine = scene.addLine(QLineF(custRect3->center(), custRect4->center()));
QGraphicsLineItem *leftLine = scene.addLine(QLineF(custRect4->center(), custRect1->center()));
custRect1->addLine(leftLine, topLine);
custRect2->addLine(topLine, rightLine);
custRect3->addLine(rightLine, bottomLine);
custRect4->addLine(bottomLine, leftLine);
QGraphicsView view(&scene);
view.show();
return a.exec();
}
编译上面的代码你应该得到一个小的 window,它只包含 QGraphivsView、一个多边形和四个连接到多边形顶点的手柄。 现在使用鼠标移动手柄。再次移动它。 一切都应该像您对任何图形编辑器的期望一样。 接下来,在重新实现一些鼠标事件的代码块中添加注释,基本上只是在将鼠标悬停在手柄上并拖动手柄时更改光标。 重新编译并重新开始移动一个句柄。再次移动同一个手柄,然后……看看会发生什么!什么鬼?它跳回到它的初始位置。 有人知道如何解释这种行为以及如何解决它吗?
谢谢!
您需要为 mousePressEvent 和 mouseReleaseEvent 方法调用基础 class 实现:
QGraphicsRectItem::mousePressEvent (event);
和
QGraphicsRectItem::mouseReleaseEvent (event);
根据文档,基本实现处理鼠标抓取、移动和选择,因此您需要在这种情况下调用它们。我有点惊讶把手完全移动了,它们显然是移动的,但是项目的位置在内部没有得到正确处理。
确保在实施后调用基础 class 事件以确保保持正常功能。
virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event) {
this->setCursor(Qt::SizeAllCursor);
//
QGraphicsRectItem::hoverEnterEvent( event );
}
virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) {
this->unsetCursor();
//
QGraphicsRectItem::hoverLeaveEvent( event );
}
virtual void mousePressEvent(QGraphicsSceneMouseEvent *event) {
this->setCursor(Qt::BlankCursor);
//
QGraphicsRectItem::mousePressEvent( event );
}
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
this->unsetCursor();
this->data(0).toString();
if (this->isUnderMouse()) {
this->setCursor(Qt::SizeAllCursor);
}
//
QGraphicsRectItem::mouseReleaseEvent( event );
}