问题背景
我有一个派生自QGraphicsObject
的类,这个类其实就是同时继承了QGraphicsItem
和QObject
的类
相当于在QGraphicsItem
的基础上增加了事件消息的功能
我派生出来的这个类主要是实现了由多个点组成的多边形
现在想实现一个功能,拖动其中的某个点,改变多边形的形状
目标点已获得
只需要重写mousePressEvent
、mouseMoveEvent
、mouseReleaseEvent
实现具体逻辑就可以了
问题
hoverMoveEvent
、mousePressEvent
都可以正常触发,但是mouseMoveEvent
、mouseReleaseEvent
怎么都触发不了
原因
先看看原本的代码,尤其关注mousePressEvent
cpp
void TriangleItem::mousePressEvent(QGraphicsSceneMouseEvent* evt)
{
_handleIndex = _activeIndex;
QGraphicsObject::mousePressEvent(evt);
}
void TriangleItem::mouseMoveEvent(QGraphicsSceneMouseEvent* evt)
{
if (!_isFinished || _handleIndex < 0) {
QGraphicsObject::mouseMoveEvent(evt);
return;
}
QPointF p = evt->pos();
// 相关处理逻辑
// ...
QGraphicsObject::mouseMoveEvent(evt);
}
void TriangleItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* evt)
{
_handleIndex = -1;
QGraphicsObject::mouseReleaseEvent(evt)
}
我在mousePressEvent
逻辑实现完后,直接调用了父类的事件处理函数QGraphicsObject::mousePressEvent(evt)
,把事件交由父类处理,没有accept
在看Qt GraphicsItem mousePressEvent文档中的描述
翻译后大概意思:
对于事件事件,可以重新实现此事件处理程序以接收此项目的鼠标按下事件。鼠标按下事件仅传递给接受按下的鼠标按钮的项目。默认情况下,一个项目接受所有鼠标按钮,但您可以通过调用
setAcceptedMouseButtons()
来更改这一点。 鼠标按下事件决定哪个项目应该成为鼠标抓取器(请参阅QGraphicsScene::mouseGrabberItem()
)。如果不重新实现此功能,按下事件将传播到该项目下的任何最上面的项目,并且不会向该项目传递其他鼠标事件。 若重新实现此函数,则默认情况下会接受事件(请参见QEvent::accept()
),并且此项就是鼠标抓取器。这允许项目接收未来的移动、释放和双击事件。如果对事件调用QEvent::ignore()
,则此项将失去鼠标抓取,并且事件将传播到下面任何最顶层的项。除非收到新的鼠标按下事件,否则不会向该项目传递更多的鼠标事件。 默认实现处理基本的项交互,如选择和移动。如果您想在重新实现此函数时保留基本实现,请在重新实现中调用QGraphicsItem::mousePressEvent()
。 对于既不可移动也不可选择的项,事件为QEvent::ignore()
。
也就是说,如果不accept
,那么这个对象就没法接收移动、释放和双击事件
解决
知道了原因就好办
问题出在mousePressEvent
,如果确认了需要移动的点,那么就需要accept
事件,以允许后续mouseMoveEvent
、mouseReleaseEvent
可以被正常触发
cpp
void TriangleItem::mousePressEvent(QGraphicsSceneMouseEvent* evt)
{
if (_activeIndex >= 0) {
_handleIndex = _activeIndex;
evt->accept();
}
else {
evt->ignore();
}
}
void TriangleItem::mouseMoveEvent(QGraphicsSceneMouseEvent* evt)
{
if (!_isFinished || _handleIndex < 0) {
QGraphicsObject::mouseMoveEvent(evt);
return;
}
QPointF p = evt->pos();
// 相关处理逻辑
QGraphicsObject::mouseMoveEvent(evt);
}
void TriangleItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* evt)
{
if (_handleIndex >= 0) {
_handleIndex = -1;
}
else {
evt->ignore();
}
}
相关内容
QGraphicsItem::mouseReleaseEvent文档也描述了这一点,要想触发mouseReleaseEvent
,必须在mousePressEvent
中accept
事件
对于事件事件,可以重新实现此事件处理程序以接收此项的鼠标释放事件。 对事件调用
QEvent::ignore()
或QEvent::accept()
无效。 默认实现处理基本的项交互,如选择和移动。如果您想在重新实现此函数时保留基本实现,请在重新实现中调用QGraphicsItem::mouseReleaseEvent()
。 请注意,mousePressEvent()
决定接收鼠标事件的图形项。有关详细信息,请参阅mousePressEvent()
描述。
mouseDoubleClickEvent
、mouseMoveEvent
也都是一样的描述