Qt中QPushButton的HoverEnter事件仅点击后生效的问题求助
问题现象
- 将自定义QPushButton(已设置
Qt::WA_Hover属性)添加到QGraphicsScene后,未点击按钮时无法触发HoverEnter/HoverLeave事件,仅点击按钮使其获得焦点后,hover事件才正常生效 - 提供的最小示例代码可正常运行,但实际项目中未点击时仅能收到
UpdateRequest、Paint等事件,无hover事件触发
核心原因
QWidget被添加到QGraphicsScene时,会自动被QGraphicsProxyWidget包裹,而默认情况下代理部件未启用hover事件转发。只有当内部QWidget获得焦点(点击操作)后,代理才会开始将hover事件传递给它,导致未点击时hover事件丢失。
解决方案
方案1:给代理部件启用hover属性
在将按钮添加到场景后,获取对应的代理部件,手动开启Qt::WA_Hover属性:
hoverBut* but = new hoverBut; // 添加按钮到场景并获取代理 QGraphicsProxyWidget* proxy = scene->addWidget(but); // 给代理启用hover属性 proxy->setAttribute(Qt::WA_Hover);
方案2:重写QGraphicsScene转发hover事件
如果场景内有多个需要hover响应的部件,可自定义QGraphicsScene,手动将场景级的hover事件转发给对应部件的代理:
class CustomScene : public QGraphicsScene { protected: void hoverEnterEvent(QGraphicsSceneHoverEvent* event) override { QGraphicsItem* targetItem = itemAt(event->scenePos(), QTransform()); if (auto proxyWidget = qgraphicsitem_cast<QGraphicsProxyWidget*>(targetItem)) { // 构造HoverEnter事件并发送给内部QWidget QHoverEvent hoverEnterEvent(QEvent::HoverEnter, proxyWidget->mapFromScene(event->scenePos()), event->screenPos()); QCoreApplication::sendEvent(proxyWidget->widget(), &hoverEnterEvent); } QGraphicsScene::hoverEnterEvent(event); } void hoverLeaveEvent(QGraphicsSceneHoverEvent* event) override { QGraphicsItem* targetItem = itemAt(event->scenePos(), QTransform()); if (auto proxyWidget = qgraphicsitem_cast<QGraphicsProxyWidget*>(targetItem)) { // 构造HoverLeave事件并发送给内部QWidget QHoverEvent hoverLeaveEvent(QEvent::HoverLeave, proxyWidget->mapFromScene(event->scenePos()), event->screenPos()); QCoreApplication::sendEvent(proxyWidget->widget(), &hoverLeaveEvent); } QGraphicsScene::hoverLeaveEvent(event); } };
之后使用CustomScene替代默认的QGraphicsScene即可。
方案3:改用QGraphicsWidget实现按钮
如果项目场景允许,直接继承QGraphicsWidget实现自定义按钮,它原生支持QGraphicsScene的hover事件机制,无需处理代理部件的转发问题。
关键验证点
- 确保QGraphicsView已启用鼠标跟踪:
view->setMouseTracking(true);(默认关闭,仅鼠标按下时才跟踪位置) - 检查自定义按钮的
Qt::WA_Hover属性是否被其他代码意外覆盖
内容的提问来源于stack exchange,提问作者plank
相关产品推荐
相关产品推荐

