PySide6 QMenuBar的QMenu首次点击下拉菜单显示过短问题
问题描述
在QMainWindow挂载的QMenuBar中添加多个QMenu及对应QAction后,程序首次启动点击任意菜单时,弹出的下拉菜单高度过短,无法完整展示所有菜单项;第二次点击打开同一菜单时显示恢复正常,后续使用过程中菜单显示始终符合预期。重启程序后,首次点击菜单时会再次复现下拉菜单过短的问题。
- 首次点击效果:

- 后续正常点击效果:

该问题在File、Edit、Record、Help所有菜单上均会复现,测试环境为Windows 11,暂未在其他平台验证。
核心代码
QMainWindow实现类
class Win(QMainWindow): from PySide6.QtGui import QCloseEvent gui = None def __init__(self, gui): QMainWindow.__init__(self) self.gui = gui self.setWindowTitle('Sermon Prep Database') self.setStyleSheet('background-color: white') self.resize(1000, 800) def closeEvent(self, event:QCloseEvent) -> None: event.ignore() self.gui.doExit() def keyPressEvent(self, event:QKeyEvent): if event.modifiers() & Qt.ControlModifier and event.key() == Qt.Key_B: self.gui.setBold() # 其余快捷键处理逻辑省略 event.accept()
菜单栏构建逻辑
def buildMenuBar(self): menubar = self.win.menuBar() # win为Win类实例 menubar.setStyleSheet('QMenuBar::item:selected { background: WhiteSmoke; }') filemenu = menubar.addMenu('File') filemenu.setStyleSheet('QMenu::item:selected { background: WhiteSmoke; color: black}') saveaction = filemenu.addAction('Save (Ctrl-S)') saveaction.triggered.connect(self.spd.saveRec) printaction = filemenu.addAction('Print (Ctrl-P)') printaction.setStatusTip('Print the current record') printaction.triggered.connect(self.printRec) backupaction = filemenu.addAction('Create Backup') backupaction.setStatusTip('Manually save a backup of your database') backupaction.triggered.connect(self.dobackup) filemenu.addSeparator() exitaction = filemenu.addAction('Exit (Ctrl-Q)') exitaction.setStatusTip('Quit the program') exitaction.triggered.connect(self.doExit) # 其余菜单项逻辑省略
最小复现代码
import sys from PySide6.QtWidgets import QApplication, QBoxLayout, QWidget, QMainWindow class SermonPrepDatabase: gui = None def __init__(self): self.startup() def startup(self): self.app = QApplication(sys.argv) self.gui = GUI(self) self.gui.initComponents() self.gui.win.show() sys.exit(self.app.exec()) class GUI(): accentColor = '#202050' backgroundColor = '#f0f0ff' spd = None win = None def __init__(self, spd): self.spd = spd def initComponents(self): self.win = Win(self) self.layout = QBoxLayout(QBoxLayout.TopToBottom) self.mainwidget = QWidget() self.mainwidget.setStyleSheet('background-color: ' + self.backgroundColor + ';') self.win.setCentralWidget(self.mainwidget) self.mainwidget.setLayout(self.layout) self.buildMenuBar() def buildMenuBar(self): menubar = self.win.menuBar() menubar.setStyleSheet('QMenuBar::item:selected { background: WhiteSmoke; }') filemenu = menubar.addMenu('File') filemenu.setStyleSheet('QMenu::item:selected { background: WhiteSmoke; color: black; }') saveaction = filemenu.addAction('Save (Ctrl-S)') saveaction.triggered.connect(self.afunction) printaction = filemenu.addAction('Print (Ctrl-P)') printaction.setStatusTip('Print the current record') printaction.triggered.connect(self.afunction) backupaction = filemenu.addAction('Create Backup') backupaction.setStatusTip('Manually save a backup of your database') backupaction.triggered.connect(self.afunction) filemenu.addSeparator() exitaction = filemenu.addAction('Exit (Ctrl-Q)') exitaction.setStatusTip('Quit the program') exitaction.triggered.connect(self.afunction) editmenu = menubar.addMenu('Edit') editmenu.setStyleSheet('QMenu::item:selected { background: WhiteSmoke; color: black}') cutaction = editmenu.addAction('Cut (Ctrl-X)') cutaction.triggered.connect(self.afunction) copyaction = editmenu.addAction('Copy (Ctrl-C)') copyaction.triggered.connect(self.afunction) pasteaction = editmenu.addAction('Paste (Ctrl-V)') pasteaction.triggered.connect(self.afunction) configmenu = editmenu.addMenu('Configure') bgColorAction = configmenu.addAction('Change Accent Color') bgColorAction.setStatusTip('Choose a different color for accents and borders') bgColorAction.triggered.connect(self.afunction) fgColorAction = configmenu.addAction('Change Background Color') fgColorAction.setStatusTip('Choose a different color for the background') fgColorAction.triggered.connect(self.afunction) renameAction = configmenu.addAction('Rename Labels') renameAction.setStatusTip('Rename the labels in this program') renameAction.triggered.connect(self.afunction) fontaction = configmenu.addAction('Change Font') fontaction.setStatusTip(('Change the font and font size used in the program')) fontaction.triggered.connect(self.afunction) recordmenu = menubar.addMenu('Record') recordmenu.setStyleSheet('QMenu::item:selected { background: WhiteSmoke; color: black}') firstrecaction = recordmenu.addAction('Jump to First Record') firstrecaction.triggered.connect(self.afunction) prevrecaction = recordmenu.addAction('Go to Previous Record') prevrecaction.triggered.connect(self.afunction) nextrecaction = recordmenu.addAction('Go to Next Record') nextrecaction.triggered.connect(self.afunction) lastrecaction = recordmenu.addAction('Jump to Last Record') lastrecaction.triggered.connect(self.afunction) recordmenu.addSeparator() newrecaction = recordmenu.addAction('Create New Record') newrecaction.triggered.connect(self.afunction) delrecaction = recordmenu.addAction('Delete Current Record') delrecaction.triggered.connect(self.afunction) def afunction(self): pass class Win(QMainWindow): from PySide6.QtGui import QCloseEvent gui = None def __init__(self, gui): QMainWindow.__init__(self) self.gui = gui self.setWindowTitle('Sermon Prep Database') self.setStyleSheet('background-color: white') self.move(50, 50) self.resize(1000, 800) def closeEvent(self, event:QCloseEvent) -> None: event.ignore() self.doExit() def doExit(self): sys.exit(0) SermonPrepDatabase()
问题原因
这是PySide6对应Qt版本在Windows 11平台的原生样式渲染bug:菜单首次弹出前,Qt未完成嵌套子菜单的尺寸预计算,错误使用了不包含子菜单项的高度值渲染下拉框;第一次弹出后所有菜单项完成布局缓存,后续点击即可正常显示。
修复方案
可任选以下一种方案解决:
- 全局使用Fusion样式,绕过Windows原生菜单渲染逻辑,在QApplication初始化后添加代码:
self.app.setStyle('Fusion') - 保留原生样式的前提下,在所有菜单构建完成后强制触发尺寸预计算,在
buildMenuBar函数末尾添加:for menu in menubar.findChildren(QMenu): menu.adjustSize() - 不要给每个QMenu单独设置样式表,将QMenu相关的样式规则统一放到QApplication或QMainWindow的全局样式中,避免单独设置样式引发的布局计算异常。
内容的提问来源于stack exchange,提问作者Jeremy Wilson
相关产品推荐
相关产品推荐

