PyQt5带下拉菜单QPushButton点击时状态栏提示消失问题求助
问题现象
- 为带下拉菜单的
QPushButton及其他控件通过enterEvent()实现鼠标悬停(含按钮禁用状态)和焦点获取时的状态栏提示 - 点击按钮打开下拉菜单时,状态栏提示会消失:首次点击时提示仍显示,但第二次开始点击后提示消失,需切换焦点才恢复;若设置
QT_QPA_PLATFORM=xcb,首次点击就会出现该问题 - 仅保留
focusInEvent处理时,下拉菜单打开后提示不会消失,但无法满足禁用按钮也显示提示的需求
问题原因
点击按钮打开下拉菜单时,菜单会获取焦点,同时按钮会触发leaveEvent(Qt内部可能判定鼠标已离开按钮区域,xcb平台下该行为更明显),导致状态栏提示被重置。另外,禁用按钮无法获取焦点,仅靠focusInEvent无法覆盖禁用状态下的悬停提示需求。
解决方案
核心思路:区分真实鼠标离开和菜单打开导致的假离开,监听菜单显示/隐藏状态,在菜单打开时强制保持按钮提示,同时保留原有悬停和焦点逻辑以覆盖禁用按钮场景。
修改后的完整代码:
import sys from PyQt5.QtWidgets import (QApplication, QDialog, QLineEdit, QMenu, QPushButton, QStatusBar, QVBoxLayout, ) from PyQt5 import QtGui class myDialog(object): def setup(self, Dialog): self.layout = QVBoxLayout(Dialog) self.lineEdit = MyLineEdit() self.button = myButton() svg = "/path/to/local/icon.svg" # <<<<<< to customize icon = QtGui.QIcon() icon.addPixmap(QtGui.QPixmap(svg)) Dialog.setWindowIcon(icon) self.layout.addWidget(self.button) self.layout.addWidget(self.lineEdit) class myButton(QPushButton): def __init__(self): super(myButton, self).__init__() self.menu = QMenu() self.act_1 = self.menu.addAction('Action 1', self._1) self.act_11 = self.menu.addAction('Action 11', self._11) self.setMenu(self.menu) self.tip = "Button tip" self._menu_is_showing = False # 监听菜单显示/隐藏信号 self.menu.aboutToShow.connect(self._on_menu_show) self.menu.aboutToHide.connect(self._on_menu_hide) def enterEvent(self, event): super(myButton, self).enterEvent(event) self.prev_message = bar.currentMessage() bar.showMessage(self.tip) def leaveEvent(self, event): super(myButton, self).leaveEvent(event) # 仅在菜单未显示时重置提示 if not self._menu_is_showing: bar.showMessage("no longer button tip") def focusInEvent(self, event): super(myButton, self).focusInEvent(event) bar.showMessage(self.tip) def _on_menu_show(self): self._menu_is_showing = True # 菜单打开时强制刷新按钮提示 bar.showMessage(self.tip) def _on_menu_hide(self): self._menu_is_showing = False # 菜单关闭后检查鼠标位置,决定是否恢复提示 if self.underMouse(): bar.showMessage(self.tip) else: bar.showMessage("no longer button tip") def _1(self): pass def _11(self): pass class MyLineEdit(QLineEdit): def __init__(self): super(MyLineEdit, self).__init__() self.tip = "Line edit tip" def enterEvent(self, event): super(MyLineEdit, self).enterEvent(event) self.prev_message = bar.currentMessage() bar.showMessage(self.tip) def leaveEvent(self, event): super(MyLineEdit, self).leaveEvent(event) bar.showMessage("") def focusOutEvent(self, event): super(MyLineEdit, self).focusOutEvent(event) bar.showMessage(self.prev_message) def focusInEvent(self, event): self.prev_message = bar.currentMessage() bar.showMessage(self.tip) if __name__ == '__main__': app = QApplication(sys.argv) Dialog = QDialog() ui = myDialog() ui.setup(Dialog) bar = QStatusBar(Dialog) ui.layout.addWidget(bar) Dialog.show() sys.exit(app.exec())
代码说明
- 添加
_menu_is_showing标志跟踪菜单状态,避免菜单打开时误触发leaveEvent重置提示 - 连接菜单的
aboutToShow/aboutToHide信号,在菜单打开时强制保持按钮提示,关闭时根据鼠标位置判断是否恢复提示 - 保留
enterEvent逻辑,确保禁用按钮悬停时仍能显示提示 - 保留
focusInEvent逻辑,确保按钮获得焦点时显示提示
内容的提问来源于stack exchange,提问作者rai
相关产品推荐
相关产品推荐

