PyQt4 QMenu 中没有 showTearOffMenu()

问题描述 投票:0回答:1

我使用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 中的虚线是使菜单被撕下的项目,但是,我尝试打印该菜单中的所有操作,操作列表中没有虚线操作。我的想法是找到一种方法来访问虚线项目,以便我可以调用它以编程方式撕下菜单,但没有运气。

python pyqt4
1个回答
0
投票

我能想到的唯一解决方案是尝试模仿 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()

© www.soinside.com 2019 - 2024. All rights reserved.