我使用PyQt4,因为它是开发的要求。我的任务之一是恢复菜单的状态。例如,用户关闭并重新打开应用程序后,小部件状态应保持不变。在这种情况下,我想恢复在前一个实例中中断的 QMenu 状态。这样做很困难,关于这个问题的文档很少。在PyQt5中,我在QMenu文档中看到有showTearOffMenu(),但在PyQt4中找不到这样的方法。供您参考,QMenu isTearOffEnabled 已设置为 True,现在我想以编程方式撕下菜单。
这是我写的代码块,出现错误:
# restore the menu widget state
self.menuWidgets = self.menubar.findChildren(QtWidgets.QMenu)
totalMenu = [(m.title(), m) for m in self.menuWidgets]
# get the value from setting to restore back the state
tearOffVisibleMenuNames = self.settings.value("tearOffMenuVisible")
for menu in totalMenu:
name = menu[0]
widget = menu[1]
# if the menu is teared off in previously instance
if tearOffVisibleMenuNames and name in tearOffVisibleMenuNames:
widget.showTearOffMenu() # this is not working
错误显示:
AttributeError: 'QMenu' object has no attribute 'showTearOffMenu'
我尝试了不同的方法来打开菜单,例如 exec_() 但它看起来不像是撕下的菜单,而 popup() 和 show() 没有对小部件进行任何更改。
我知道 QMenu 中的虚线是使菜单被撕下的项目,但是,我尝试打印该菜单中的所有操作,操作列表中没有虚线操作。我的想法是找到一种方法来访问虚线项目,以便我可以调用它以编程方式撕下菜单,但没有运气。
我能想到的唯一解决方案是尝试模仿 QMenu 在菜单被撕下时实际期望的内容,即对“撕下”区域的几何形状内的鼠标按钮释放(跟随鼠标移动)做出反应.
您需要使用菜单样式和
pixelMetric()
函数获取该区域的可能坐标,然后在这些坐标处发送两个假鼠标事件。
对于任何情况和情况,它可能不是 100% 安全,但应该足够了。
def tearOff(menu):
if not menu.isTearOffEnabled():
return
style = menu.style()
opt = QStyleOption()
opt.initFrom(menu)
menuBorder = menu.contentsMargins().top()
vmargin = style.pixelMetric(QStyle.PM_MenuVMargin, opt, menu)
tearHeight = style.pixelMetric(QStyle.PM_MenuTearoffHeight, opt, menu)
pos = QPoint(menu.width() // 2, menuBorder + vmargin + tearHeight // 2)
moveEvent = QMouseEvent(QEvent.MouseButtonRelease,
pos, menu.mapToGlobal(pos),
Qt.LeftButton, Qt.MouseButtons(Qt.LeftButton), Qt.KeyboardModifier(0)
)
QApplication.sendEvent(menu, moveEvent)
releaseEv = QMouseEvent(QEvent.MouseButtonRelease,
pos, menu.mapToGlobal(pos),
Qt.LeftButton, Qt.MouseButtons(Qt.LeftButton), Qt.KeyboardModifier(0)
)
QApplication.sendEvent(menu, releaseEv)
请注意,为了正常工作,这可能应该在父窗口已经显示后完成,可能是在主窗口第一次调用
QTimer.singleShot()
时使用 showEvent()
。