You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyQt5带下拉菜单QPushButton点击时状态栏提示消失问题求助

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 02:31:13