PyQt5在QMenu中集成QFontComboBox的实现问题
问题描述
在PyQt5 GUI开发过程中,尝试将QFontComboBox组件集成到QMenu菜单内,需要在菜单中选中特定字体时实现两个效果:
- 自动关闭当前打开的
QMenu菜单 - 打印输出选中的字体名称
原有测试代码运行后无法达到预期效果,原始代码如下:
from PyQt5.QtCore import QObject from PyQt5.QtGui import QIcon, QFont, QCursor from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QFontComboBox, QWidgetAction, QMenu, QPushButton class Window(QWidget): def __init__(self): super().__init__() self.setWindowTitle("Pyside2 FontCombo Box") self.setGeometry(300,200,300,250) self.setFontBox() self.setIcon() self.show() def setIcon(self): appIcon = QIcon("icon.png") self.setWindowIcon(appIcon) def setFontBox(self): self.font_button = QPushButton(self) self.font_button.setFixedWidth(300) self.font_button.clicked.connect(lambda: self.setFontmenu()) vbox = QVBoxLayout() vbox.addWidget(self.font_button) self.setLayout(vbox) def setFontmenu(self): font_menu = QMenu() font_submenu = QFontComboBox() font_submenu.setCurrentFont(QFont("Arial")) objectTest = QObject() widget = QWidgetAction(objectTest) widget.setDefaultWidget(font_submenu) font_menu.addAction(widget) font_menu.exec_(QCursor.pos()) menu = font_menu menu.addSeparator() font_submenu.showPopup() font_submenu.setFocus() font_submenu.currentFontChanged.connect(self._changed) def _changed(self): font = self.currentFont().family() print(font) return myapp = QApplication(sys.argv) window = Window() myapp.exec_() sys.exit()
原代码问题排查
- 缺少
sys模块导入,代码启动时会直接抛出NameError - 代码执行顺序错误:
QMenu.exec_()会阻塞当前流程,后续的信号绑定、分隔符添加、下拉框弹出逻辑全部要等菜单关闭后才会执行,完全不生效 _changed槽函数逻辑错误:调用self.currentFont()时self指向窗口实例,窗口类不存在该方法,无法获取选中字体- 对象父级绑定错误:
QWidgetAction绑定到临时创建的QObject实例上,容易被Python垃圾回收导致组件异常 - 未添加字体选中后关闭菜单的逻辑
修正后完整代码
import sys from PyQt5.QtCore import QTimer from PyQt5.QtGui import QIcon, QFont, QCursor from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QFontComboBox, QWidgetAction, QMenu, QPushButton class Window(QWidget): def __init__(self): super().__init__() self.setWindowTitle("PyQt5 FontCombo Box in Menu") self.setGeometry(300,200,300,250) self.setFontBox() self.setIcon() self.show() def setIcon(self): appIcon = QIcon("icon.png") self.setWindowIcon(appIcon) def setFontBox(self): self.font_button = QPushButton("选择字体", self) self.font_button.setFixedWidth(300) self.font_button.clicked.connect(self.setFontmenu) vbox = QVBoxLayout() vbox.addWidget(self.font_button) self.setLayout(vbox) def setFontmenu(self): font_menu = QMenu(self) font_submenu = QFontComboBox() font_submenu.setCurrentFont(QFont("Arial")) # 初始化组件动作,绑定父对象为菜单避免被回收 widget_action = QWidgetAction(font_menu) widget_action.setDefaultWidget(font_submenu) font_menu.addAction(widget_action) font_menu.addSeparator() # 字体选中回调逻辑 def on_font_selected(current_font): # 打印选中字体名称 print(current_font.family()) # 关闭当前菜单 font_menu.close() # 菜单弹出前绑定信号 font_submenu.currentFontChanged.connect(on_font_selected) # 弹出菜单 font_menu.exec_(QCursor.pos()) # 延迟展开字体下拉框,避免和菜单弹出冲突 QTimer.singleShot(100, font_submenu.showPopup) if __name__ == "__main__": myapp = QApplication(sys.argv) window = Window() sys.exit(myapp.exec_())
关键实现说明
- 所有组件初始化、信号绑定逻辑全部放在
exec_()调用前完成,避开菜单弹出的阻塞流程 - 为
QMenu、QWidgetAction绑定正确的父对象,避免临时对象被垃圾回收引发异常 - 利用
QFontComboBox.currentFontChanged信号自带的QFont参数直接获取选中字体,不需要额外调用组件方法 - 选中字体后在回调内直接调用
QMenu.close()实现菜单自动关闭 - 用
QTimer.singleShot做短延迟后再展开字体组合框的下拉列表,解决组件弹出冲突问题
内容的提问来源于stack exchange,提问作者ROOMBON
相关产品推荐
相关产品推荐

