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

如何在PyQt5的QPushButton上设置悬停事件处理器

实现QPushButton悬停打开自定义对话框

核心修改点

  • 开启按钮的鼠标跟踪,捕获鼠标进入/离开事件
  • 替换点击触发为鼠标进入按钮时打开对话框
  • 处理重复打开问题,避免多次创建对话框实例
  • 优化鼠标从按钮移至对话框时的逻辑,防止误关闭

修改后的完整代码

ElementWidget类修改

from PyQt5.QtWidgets import (QWidget, QHBoxLayout, QLabel, QPushButton, 
                             QDialog, QApplication, QMainWindow)
from PyQt5.QtCore import Qt, QEvent, QCursor

class ElementWidget(QWidget):
    def __init__ (self, p, element):
        super().__init__(p)

        layout = QHBoxLayout()
        label = QLabel(element)        
        label.setFixedSize(200,39)

        self.btn = QPushButton("btn")
        # 开启鼠标跟踪并安装事件过滤器
        self.btn.setMouseTracking(True)
        self.btn.installEventFilter(self)
        self.btn.setFixedSize(50,39)
        
        layout.addWidget(label)
        layout.addWidget(self.btn)

        self.setLayout(layout)
        self.setFixedSize(250,60)
        # 初始化对话框变量
        self.dlg = None

    def _openOptionsMenu(self):
        # 避免重复打开对话框
        if self.dlg and self.dlg.isVisible():
            return
        self.dlg = selfClosingDialog(self.closeOptionsMenu, parent = self)
        
        self.dlg.setLayout(ElementOptionsLayout(self.closeOptionsMenu))
        self.dlg.setWindowFlag(Qt.FramelessWindowHint)
        
        self.dlg.setGeometry(QCursor.pos().x(), QCursor.pos().y() ,100,100)
        self.dlg.show()
        

    def closeOptionsMenu(self):
        if self.dlg:
            self.dlg.close()
            self.dlg = None

    def eventFilter(self, obj, event):
        if obj == self.btn:
            # 鼠标进入按钮时打开菜单
            if event.type() == QEvent.Enter:
                self._openOptionsMenu()
                return True
            # 鼠标离开按钮时,若未进入对话框则关闭菜单
            elif event.type() == QEvent.Leave:
                if self.dlg and not self.dlg.underMouse():
                    self.closeOptionsMenu()
                return True
        return super().eventFilter(obj, event)

自定义对话框类(保持原逻辑)

class selfClosingDialog(QDialog):
    def __init__(self, closeFunc, parent=None):
        super().__init__(parent)
        self.closeFunc = closeFunc

    def leaveEvent(self, event):
        self.closeFunc()

主程序部分

if __name__ == "__main__":
    app = QApplication([])
    window = QMainWindow()
    window.resize(500,400)
    wid = ElementWidget(window,"Parabola_0")
    
    window.show()
    app.exec_()

关键说明

  1. 鼠标跟踪:通过setMouseTracking(True)让按钮能捕获未按下鼠标时的移动事件,否则只有鼠标按下时才会触发enter/leave事件。
  2. 事件过滤器:通过安装事件过滤器监听按钮的QEvent.Enter和QEvent.Leave事件,分别对应鼠标进入和离开按钮的动作。
  3. 重复打开防护:在_openOptionsMenu中判断对话框是否已存在且可见,避免多次创建实例。
  4. 跨控件悬停逻辑:鼠标从按钮移到对话框时,通过underMouse()判断对话框是否处于鼠标下方,防止误关闭。

内容的提问来源于stack exchange,提问作者MGafaji

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 23:01:09