如何为宽度的 Qt 菜单项添加填充?

How to add padding to Qt Menu Items for Width?

基本上,我通过使用快捷方式添加操作来使用 Qt 菜单。当菜单出现时,它们看起来不错。

但我想在操作项文本与其快捷方式之间添加更多间距。这可能吗?我找不到任何功能来执行此操作。

setMinimumWidth 有效,但我需要在 Qt 计算的动态宽度之上添加。

由于 QMenu 计算其大小的复杂方式,使用 setMinimumWidth() 不是一个可靠的选择:一旦设置了该大小,就无法取消设置,并且 sizeHint() 将始终使用那个最小值。

不过,有两种可能的解决方法。

强制菜单布局

这有点老套和肮脏,可能无法在所有情况下正常工作。诀窍是通过添加将立即删除的“假”操作来强制重新布局。

您可以通过将特定函数连接到 aboutToShowaboutToHide 信号来实现此目的:

def resizeMenu(menu):
    for action in menu.actions():
        if action.shortcut():
            menu.setMinimumWidth(menu.sizeHint().width() + 50)
            menu.removeAction(menu.addAction(''))
            break

def restoreMenu(menu):
    menu.setMinimumWidth(0)
    menu.removeAction(menu.addAction(''))


menu.aboutToShow.connect(lambda: resizeMenu(menu))
menu.aboutToHide.connect(lambda: restoreMenu(menu))

您还可以在应用程序上安装事件过滤器,以便它适用于所有菜单:

class MenuWatcher(QtCore.QObject):
    def eventFilter(self, obj, event):
        if isinstance(obj, QtWidgets.QMenu):
            if event.type() == event.Show:
                for action in obj.actions():
                    if action.shortcut():
                        menu.setMinimumWidth(menu.sizeHint().width() + 50)
                        menu.removeAction(menu.addAction(''))
                        break
            elif event.type() == event.Hide:
                if menu.minimumWidth():
                    menu.setMinimumWidth(0)
                    menu.removeAction(menu.addAction(''))
        return super().eventFilter(obj, event)

# ...
watcher = MenuWatcher()
app.installEventFilter(watcher)

使用 QProxyStyle

通过覆盖 QProxyStyle 的 sizeFromContents() 我们可以检查选项是否是 CT_MenuItem,如果它有 tabWidth(表明至少有一个 previous action has a shortcut) or a \t in its text (means that it probably have a shortcut),我们可以在返回默认提供的大小之前添加一个特定的宽度实施:

class ProxyStyle(QtWidgets.QProxyStyle):
    def sizeFromContents(self, ct, opt, size, widget=None):
        size = super().sizeFromContents(ct, opt, size, widget)
        if ct == self.CT_MenuItem and (opt.tabWidth or '\t' in opt.text):
            size.setWidth(size.width() + 50)
        return size

# ...
app.setStyle(ProxyStyle())