如何为宽度的 Qt 菜单项添加填充?
How to add padding to Qt Menu Items for Width?
基本上,我通过使用快捷方式添加操作来使用 Qt 菜单。当菜单出现时,它们看起来不错。
但我想在操作项文本与其快捷方式之间添加更多间距。这可能吗?我找不到任何功能来执行此操作。
setMinimumWidth 有效,但我需要在 Qt 计算的动态宽度之上添加。
由于 QMenu 计算其大小的复杂方式,使用 setMinimumWidth()
不是一个可靠的选择:一旦设置了该大小,就无法取消设置,并且 sizeHint()
将始终使用那个最小值。
不过,有两种可能的解决方法。
强制菜单布局
这有点老套和肮脏,可能无法在所有情况下正常工作。诀窍是通过添加将立即删除的“假”操作来强制重新布局。
您可以通过将特定函数连接到 aboutToShow
和 aboutToHide
信号来实现此目的:
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())
基本上,我通过使用快捷方式添加操作来使用 Qt 菜单。当菜单出现时,它们看起来不错。
但我想在操作项文本与其快捷方式之间添加更多间距。这可能吗?我找不到任何功能来执行此操作。
setMinimumWidth 有效,但我需要在 Qt 计算的动态宽度之上添加。
由于 QMenu 计算其大小的复杂方式,使用 setMinimumWidth()
不是一个可靠的选择:一旦设置了该大小,就无法取消设置,并且 sizeHint()
将始终使用那个最小值。
不过,有两种可能的解决方法。
强制菜单布局
这有点老套和肮脏,可能无法在所有情况下正常工作。诀窍是通过添加将立即删除的“假”操作来强制重新布局。
您可以通过将特定函数连接到 aboutToShow
和 aboutToHide
信号来实现此目的:
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())