单击时移除 QPushButton 周围的方格边框

Posted

技术标签:

【中文标题】单击时移除 QPushButton 周围的方格边框【英文标题】:Remove checkered border around QPushButton when clicked 【发布时间】:2020-09-14 14:10:01 【问题描述】:

这是QPushButton。点击后是这样的:

如您所见,按钮周围有一个浅灰色的点/方格高亮/边框。我该如何摆脱它?似乎无法在任何地方找到答案。

我什至尝试在样式表中将边框设置为None

【问题讨论】:

那个“边框”是焦点矩形,它实际上非常有助于用户知道哪个小部件当前具有键盘焦点。您完全确定要摆脱它吗? 另外,你在哪个平台上?我假设它在 Linux 上(也许是 Mint?)。这是界面中唯一的按钮吗?如果该界面中还有其他小部件接受焦点,则该虚线边框仅出现在已单击的小部件上,对吗? 【参考方案1】:

那个“边框”实际上是焦点矩形,只要小部件具有键盘焦点,就会显示它。如果是按钮,则表示可以使用键盘上的空格键按下。

有两种方法可以“移除”焦点矩形:使用setFocusPolicy()QtCore.Qt.NoFocus 来禁用任何小部件上的焦点,或者阻止其绘制。

考虑到任何一种可能性都会使键盘导航(通过 tab 和箭头键)和交互(使用空格键)变得不可能,或者至少不那么可用。

要禁用焦点策略,只需使用以下命令:

    self.someButton.setFocusPolicy(QtCore.Qt.NoFocus)

考虑到在大多数样式中禁用焦点也会禁用自动助记符下划线加速器快捷键(对于 Alt+ 快捷键);虽然在 MacOS 上这些会自动禁用,但在其他平台上可能会出现问题,因为在这种情况下,所有助记符都需要在快捷方式的字母前使用 & 手动设置。

在这种情况下,绘画方法可能会很有用,如果用户在任何时候不小心按下了空格键,当前聚焦的按钮就会被按下,从用户体验的角度来看,这肯定不是一件好事。

有两种主要方法可以防止绘制:通过样式表或通过自定义绘制。

使用样式表可以完全控制绘画,但缺点是需要至少为正常和按下状态(但也可能为选中和悬停状态)提供样式表,并且会不尊重按钮的平台默认大小提示和边距。此外,对于某些特定平台样式(尤其是在某些 Linux 发行版上),如果样式还在内部混合样式表,则无法保证不会绘制焦点;在这些情况下,可能可以通过设置 outline: none; 来禁用焦点矩形。

button.setStyleSheet('''
    QPushButton 
        border: 1px outset green;
        border-radius: 2px;
        background: lightgreen;
    
    QPushButton:pressed 
        border: 1px inset green;
    
    ''')

自定义绘画可以通过继承QPushButton并重新实现paintEvent()来完成;通过使用QStylePainter() 和QStyleOptionButton(),我们可以确保按钮始终根据当前样式进行绘制,同时在实际绘制之前控制其某些方面:

class NoFocusRectButton(QtWidgets.QPushButton):
    def paintEvent(self, event):
        qp = QtWidgets.QStylePainter(self)
        opt = QtWidgets.QStyleOptionButton()
        # initialize the style option for the current button
        self.initStyleOption(opt)
        # remove the focus state flag if it exists
        opt.state &= ~QtWidgets.QStyle.State_HasFocus
        # paint the button
        qp.drawControl(QtWidgets.QStyle.CE_PushButton, opt)

另一种方法是使用QProxyStyle,它可以安装在按钮上或整个应用程序上(不幸的是,在父窗口小部件上设置样式不会在其子窗口小部件上传播样式)。

class NoFocusProxyStyle(QtWidgets.QProxyStyle):
    def drawControl(self, control, opt, painter, widget=None):
        if control in (self.CE_PushButton, self.CE_PushButtonBevel):
            opt.state &= ~self.State_HasFocus
        super().drawControl(control, opt, painter, widget)

    def drawPrimitive(self, element, opt, painter, widget=None):
        if element == self.PE_FrameFocusRect and isinstance(widget, QtWidgets.QPushButton):
            opt.state &= ~self.State_HasFocus
        super().drawPrimitive(element, opt, painter, widget)

# ...
app = QtWidgets.QApplication(sys.argv)
proxyStyle = NoFocusProxyStyle()
app.setStyle(proxyStyle)
# or, alternatively
someButton.setStyle(proxyStyle)

请注意,在小部件上设置样式表时,在某些情况下会部分绕过样式(取决于样式、小部件、当前默认样式和样式表中设置的属性)。

【讨论】:

以上是关于单击时移除 QPushButton 周围的方格边框的主要内容,如果未能解决你的问题,请参考以下文章

移除 QGraphicsView 周围的蓝色焦点边框

移除页内链接周围的边框

android EditText,单击另一个对象时移除焦点

在 Windows 上使用 PySide/PyQT 移除 QPushButton 周围奇怪的一像素空间

移除 Android 应用程序周围的绿色边框

如何移除 Canvas 小部件周围的浅灰色边框?