由于某种原因,在 QGraphicsScene 类中使用 addWidget 函数会使相关的 QGraphicsView 小部件接收 mouseMoveEvents,而无需按下鼠标按钮并关闭鼠标跟踪。
MyView.h:
#pragma once
#include <qgraphicsview>
#include <qevent>
#include <qgraphicsscene>
class MyView : public QGraphicsView // subclassing QGraphicsView
{
Q_OBJECT
protected:
void mouseMoveEvent(QMouseEvent* event);
public:
MyView(QGraphicsScene* scene, QWidget *parent);
~MyView();
};
MyView.cpp:
#include "MyView.h"
MyView::MyView(QGraphicsScene* scene, QWidget* parent)
: QGraphicsView(scene, parent)
{}
void MyView::mouseMoveEvent(QMouseEvent* event)
{
qDebug() << this->hasMouseTracking(); // indicating that the event goes on
// even though I dont't press any buttons
// and mouse tracking is disabled by default
}
MyView::~MyView()
{}
QMainWindow.cpp:
QVBoxLayout* layout = new QVBoxLayout();
ui.centralWidget->setLayout(layout);
QGraphicsScene* scene = new QGraphicsScene();
scene->addWidget(new QWidget());
MyView* v = new MyView(scene, ui.centralWidget);
layout->addWidget(v);
只有在场景中添加 QWidget 或其子类后才会发生这种情况。 Qt版本是6.7.0
只有在场景中添加 QWidget 或其子类后才会发生这种情况
这就是它发生的原因。
只要场景中的项目需要鼠标跟踪,鼠标跟踪就会自动启用,这对于通过 QGraphicsProxyWidgets 添加的小部件是隐式的。
mouseTracking
属性,该属性通常为 false
(禁用),并且不会为其更改提供任何通知信号。
实际上,许多小部件将该属性设置为
true
:例如,在启用了清除按钮的 QLineEdit 中更改鼠标光标,或者显示超链接的 QLabel,或者在视图中显示悬停的项目。
为了通过代理将
Enter
和 Leave
事件正确传播到小部件,还需要正确的鼠标移动跟踪。
因此,QGraphicsScene 所做的假设是,每当将 any QGraphicsProxyWidget 添加到其中时,即使没有按下鼠标按钮,其小部件也可能接收鼠标移动事件,因此它会自动将 mouseTracking
属性设置为
true
对于所有显示它的视图。如果将场景添加到视图,并且它已经包含 QGraphicsProxyWidgets,则该属性会类似地自动设置。代理项最终将根据其 mouseTracking
属性决定事件是否实际发送到小部件。
请注意,小部件可能是一个复杂的小部件(例如,一个容器,甚至是一个“窗口”),因此拥有一个通知器信号毫无意义,因为每次其子树发生更改时都很难传播和管理。因此,结论是,每当将任何
QGraphicsProxyWidget
添加到场景中(包括使用
scene::addWidget()
)时,连接到该场景的视图将始终使用鼠标跟踪(即使这些项目被删除并且场景被清除后) ,并且从那一刻起总会导致 mouseMoveEvent()
触发,除非手动调用 setMouseTracking(false)
。这需要在视图中正确实现mouseMoveEvent()
:根据您的需求(顺便说一句,您没有澄清),您可能需要首先调用基本实现,这可能会将事件中继到场景如果 QGraphicsProxyWidget 中的小部件
contained首先执行了该事件,则接受/忽略该事件,并最终在这种情况下检查
event::isAccepted()
。或者,您可能只想在将事件映射到场景并检查该场景位置是否有最上面的 QGraphicsProxyWidget 项之后才处理该事件。