Qt开发经验:鼠标悬停在QMenu上时导致状态栏信息消失
创作时间:
作者:
@小白创作中心
Qt开发经验:鼠标悬停在QMenu上时导致状态栏信息消失
引用
CSDN
1.
https://m.blog.csdn.net/chenai886/article/details/144055559
本文将围绕鼠标悬停在QMenu上时导致状态栏信息消失的情况,整合事件信息流,对流程进行详细解读,并通过代码剖析每个关键环节的行为。
1. 问题描述
当鼠标悬停在QMenu的空白区域、分隔符或禁用菜单项时:
- 当前的QAction被置为nullptr。
- QMenu调用previousAction->showStatusText("", ...),发送空字符串的QStatusTipEvent。
- 状态栏(QStatusBar)接收到该事件后清空状态栏内容。
2. 信息流的完整路径
整个信息流从鼠标事件开始,到状态栏显示或清空结束,共分为以下5个阶段:
- 鼠标移动事件触发(QMenu):
- 鼠标移动到QMenu内部,触发QMenu::mouseMoveEvent。
- 检测鼠标悬停位置,并调用QMenuPrivate::setCurrentAction更新当前QAction。
- 当前QAction状态更新(QMenuPrivate):
- 如果鼠标在空白区域,调用showStatusText("", ...),生成空字符串的QStatusTipEvent。
- 状态提示事件发送(QActionPrivate):
- 将QStatusTipEvent发送到QMainWindow或父控件。
- 事件捕获与处理(QMainWindow):
- QMainWindow::event捕获QEvent::StatusTip,并调用QStatusBar::showMessage。
- 状态栏显示更新(QStatusBar):
- 接收到空字符串消息,调用clearMessage清空状态栏。
3. 信息流的代码与详细解读
3.1 鼠标移动事件触发
当鼠标移动到QMenu内部时,QMenu::mouseMoveEvent被触发。
核心代码:QMenu::mouseMoveEvent
void QMenu::mouseMoveEvent(QMouseEvent *e) {
Q_D(QMenu);
QAction *action = d->actionAt(e->pos()); // 获取鼠标悬停的 QAction
if ((!action || action->isSeparator()) && !d->sloppyState.enabled()) {
d->setCurrentAction(action); // 鼠标在空白区域,action 为 nullptr
return;
}
d->setCurrentAction(action); // 鼠标悬停在有效菜单项上
}
- 行为分析:
- d->actionAt(e->pos()):检测鼠标当前位置是否有对应的QAction。
- 如果鼠标在空白区域或分隔符上,action == nullptr。
- 调用d->setCurrentAction(action),将当前激活的菜单项设置为nullptr。
3.2 当前QAction状态更新
QMenuPrivate::setCurrentAction是管理QAction激活状态的核心逻辑。
核心代码:QMenuPrivate::setCurrentAction
void QMenuPrivate::setCurrentAction(QAction *action, int popup, SelectionReason reason, bool activateFirst) {
QAction *previousAction = currentAction;
currentAction = action; // 更新当前 QAction
if (action) {
activateAction(action, QAction::Hover); // 激活当前 QAction
} else if (previousAction) {
// 当前 QAction 被清空,调用 previousAction 的 showStatusText
previousAction->d_func()->showStatusText(topCausedWidget(), QString());
}
}
- 行为分析:
- 如果currentAction == nullptr,说明鼠标离开了有效的菜单项。
- 调用previousAction->showStatusText("", ...),生成空字符串状态提示。
3.3 状态提示事件发送
QActionPrivate::showStatusText用于生成并分发QStatusTipEvent。
核心代码:QActionPrivate::showStatusText
bool QActionPrivate::showStatusText(QWidget *widget, const QString &str) {
if (QObject *object = widget ? widget : parent) {
QStatusTipEvent tip(str); // 创建状态提示事件
QApplication::sendEvent(object, &tip); // 发送事件到目标控件
return true;
}
return false;
}
- 行为分析:
- str是状态提示内容,此处为""(空字符串)。
- 使用QApplication::sendEvent分发QStatusTipEvent,通常发送到QMainWindow。
3.4 事件捕获与处理
QMainWindow是QStatusTipEvent的中继点,它捕获事件并调用状态栏的showMessage。
核心代码:QMainWindow::event
bool QMainWindow::event(QEvent *event) {
#if QT_CONFIG(statustip)
case QEvent::StatusTip:
#if QT_CONFIG(statusbar)
if (QStatusBar *sb = d->layout->statusBar())
sb->showMessage(static_cast<QStatusTipEvent *>(event)->tip()); // 更新状态栏
else
#endif
static_cast<QStatusTipEvent *>(event)->ignore(); // 忽略事件
return true;
#endif
return QMainWindow::event(event); // 其他事件交由父类处理
}
- 行为分析:
- 捕获QEvent::StatusTip类型事件。
- 调用QStatusBar::showMessage,将事件中的tip内容传递给状态栏。
- 如果tip == "",状态栏会显示空消息并清空内容。
3.5 状态栏显示更新
状态栏(QStatusBar)是信息流的终点,通过showMessage和clearMessage更新显示内容。
核心代码:QStatusBar::showMessage
void QStatusBar::showMessage(const QString &message, int timeout) {
Q_D(QStatusBar);
if (message.isEmpty()) {
clearMessage(); // 如果消息为空,清空状态栏
return;
}
d->tempItem = message; // 更新临时消息
hideOrShow(); // 根据消息状态更新状态栏显示
}
核心代码:QStatusBar::clearMessage
void QStatusBar::clearMessage() {
Q_D(QStatusBar);
d->tempItem.clear(); // 清空临时消息
hideOrShow(); // 隐藏状态栏
}
- 行为分析:
- 如果message是空字符串,调用clearMessage清空状态栏。
- 调用hideOrShow更新状态栏的可见性。
4. 问题的根本原因
- 鼠标悬停在空白区域或分隔符时:
- QMenu的currentAction被置为nullptr。
- 调用previousAction->showStatusText("", ...),生成空字符串状态提示。
- 状态栏响应空字符串事件:
- QMainWindow捕获QStatusTipEvent,将tip内容传递给状态栏。
- 如果tip == "",状态栏调用clearMessage清空显示内容。
5. 解决方案
方法1:拦截空字符串事件
通过事件过滤器,阻止空字符串的QStatusTipEvent被传递到状态栏。
bool MainWindow::eventFilter(QObject *obj, QEvent *event) {
if (event->type() == QEvent::StatusTip) {
QStatusTipEvent *se = static_cast<QStatusTipEvent *>(event);
if (se->tip().isEmpty()) {
return true; // 阻止空字符串事件
}
}
return QMainWindow::eventFilter(obj, event);
}
6. 总结
事件信息流的完整路径
- 鼠标移动到QMenu内部。
- QMenu更新currentAction,调用showStatusText("")。
- QActionPrivate发送空字符串的QStatusTipEvent。
- QMainWindow捕获事件并调用状态栏的showMessage。
- QStatusBar接收空字符串,调用clearMessage清空显示。
问题的根因
- 鼠标悬停在空白区域时,QMenu发送空字符串事件。
- 状态栏默认响应空字符串事件,清空内容。
通过优化QMenu和拦截空字符串事件,可以有效解决鼠标悬停在QMenu上导致状态栏信息消失的问题。
热门推荐
伊藤博文是好人吗?都有什么贡献存在?
艾尔登法环中哪个敌人或任务能让你经验值暴涨?这份攻略必看
健身增肌热量摄入公式
谐音梗是烂梗吗?
掌握音乐剪辑技巧,轻松制作个性化音乐作品的实用指南
梦到已故老人再次出殡的深层含义
徜徉皇家园林,在花海里拥抱春天
如何去除电镀层?这种去除方法对材料有何影响?
防城港房价暴跌原因分析:市场供需变化与政策调控的影响
闲置手机改造指南:不到20元实现直供电,变身家用监控或行车记录仪
护工考健康照护师证书有啥好处?这里给你全部答案!
网文新星:从零开始,新手如何用写作模板与技巧开启小说财富之路
T5灯条和T8灯条的区别:尺寸、长度、亮度及应用场景详解
2024年建成9条高速!湖北高速公路总里程突破8000公里
夏山学校探访记:异类还是自由教育的圣地?
高考考试过程中如何合理的分配时间?
七岁女孩夜间突发头痛应如何处理
东营港经济开发区:聚力石化产业绿色高端升级,全力打造世界级高端化工产业集群
秋冬红色穿搭指南:比例分配与搭配技巧详解
logo越简约越高级,快人一步的设计
超级加总带出超级升班马:蒙扎成功是如何缔造的?
直接发钱刺激消费,真的会被存起来或者引发通胀吗?
扁平疣和毛囊炎有什么区别?从病因、症状到治疗全方位解析
红曲的六大功效
【硬核科普】KN95 口罩真假鉴别秘籍大公开!
新农合报销比例为多少:法律依据与政策变化解析
为什么在期货交易中严格止损很重要?止损策略如何制定?
睡8小时≠充满电!当代人“虚电睡眠”自救指南来啦
专家推荐的10个大专专业:就业前景好、能拿高薪
房龄的重要性体现出来了!事实证明,老破小再便宜也别买!