-2

我想使用一个可以选中的 QGroupBox,但是当 QGroupBox 复选框未选中时,我不会禁用 QGroupBox 的内容小部件。

来自参考:

checked : bool 此属性保存是否选中了组框

如果组框是可选中的,它会显示一个复选框。如果选中该复选框,则启用组框的子项;否则,孩子将被禁用并且用户无法访问。

默认情况下,选中的组框也被选中。

我想在 QGroupBox 标题栏中有一个复选框,但我不希望应用上述功能。

复选框逻辑将是全选、全选,因此当未选中复选框时,用户可以修改内部 QGroupBox 复选框元素。

我想保留一个界面-ui,如下所示:

也许我必须使用带有 QPaintEvent 或 QSS 样式表的 QFrame,但我不是这方面的专家。

在此处输入图像描述

编辑:如果可能的话,我还想要QGroupBox复选框的 triState。

编辑2:我试试这个代码:

self.main_self.ui_visible_player_list_fields_window.groupBox.changeEvent(QtCore.QEvent.EnabledChange).connect(lambda event:event.ignore())

但它有错误。

 self.main_self.ui_visible_player_list_fields_window.groupBox.changeEvent(QtCore.QEvent.EnabledChange).connect(lambda event:event.ignore())
TypeError: changeEvent(self, QEvent): argument 1 has unexpected type 'Type'

编辑:我认为以下代码将解决问题:

class Custom_QGroupBox(QtWidgets.QGroupBox):

    def __init__(self, parent=None):
        super(Custom_QGroupBox, self).__init__(parent)

    def changeEvent(self, event):
        if event.type() == QtCore.QEvent.EnabledChange:
            self.blockSignals(True)
            self.setEnabled(True)
            event.ignore()
            self.blockSignals(False)
        else:
            return super(Custom_QGroupBox, self).changeEvent(event)

但它没有:(

4

2 回答 2

0

我添加此代码:

self.main_self.ui_visible_player_list_fields_window.groupBox.blockSignals(True)
        self.main_self.ui_visible_player_list_fields_window.groupBox.setEnabled(True)
        
        for child_widget in self.main_self.ui_visible_player_list_fields_window.groupBox.children():
            try:
                child_widget.setEnabled(True)
            except:
                pass
        self.main_self.ui_visible_player_list_fields_window.groupBox.blockSignals(False)

在切换方法和是child_widget_checkbox.stateChanged.connect方法中,它可以工作。

唯一要完全回答这个问题的是 QGroupBox 的三态。

于 2021-11-16T12:45:02.777 回答
0

前提:可能不是一个好主意

UI 元素有已知的约定,用户已经习惯了它们,并期望对众所周知的元素类型执行“操作”会导致同样已知的结果。
虽然组框更像是一种边缘情况,但 Qt 的默认行为遵循约定:切换复选框会导致切换其内容的启用状态。

由于 UI 元素应始终尝试遵循约定并使用户操作的可能结果尽可能可预测,因此更好的解决方案是添加一个“顶级”按钮组,将所有框设置为选中或未选中(“检查所有”和“不检查”)。

为什么它不起作用?

首先,achangeEvent不是信号,因此您不能尝试“连接”它(始终在 Qt 文档中查找函数类型,如果它是信号,[signal]除了定义之外,它还有一个符号)。
它是一个事件处理程序,它需要一个事件实例作为参数,而不是类型。

然后,切换组框的复选框会更改其EnabledChange项的状态,而不是组框的状态,因此您在切换时永远不会收到事件。
如果您考虑一下,这很明显:如果在切换其复选框时整个组框被禁用,您永远不能再次单击它来启用它,因为默认情况下禁用的小部件会忽略输入事件,并且标题复选框都会也显示为禁用。

可能的解决方案

有多种可能的解决方案,包括子类化 QFrame 并绘制复选框和标题,但使其符合当前样式将非常(并且不必要)困难。
最佳选择通常是对默认行为进行较少更改的选择。

在这种情况下,我的建议是做两件事:

  • 连接到toggled组框的信号并覆盖默认行为(恢复启用状态,除非为该小部件明确设置);
  • 在实际绘制之前覆盖paintEvent并更改用于样式和画家的QStyleOptionGroupBox ; state

由于状态是为组框内部定义的,我们需要覆盖它的值:当复选框(理论上)选中或未选中时(因此,无论子小部件是否启用)initStyleOption()添加选项的状态标志,但是我们必须根据复选框状态来设置选项状态。为了做到这一点,我们必须检查所有复选框并验证是否所有复选框都被选中,其中任何一个都被选中,或者没有。State_OnState_Off

from PyQt5 import QtCore, QtWidgets

class Custom_QGroupBox(QtWidgets.QGroupBox):
    checkAllIfAny = True
    def __init__(self, *args, **kwargs):
        super(Custom_QGroupBox, self).__init__(*args, **kwargs)
        self.setCheckable(True)
        self.checkBoxes = []
        self.toggled.connect(self.toggleCheckBoxes)

    def addCheckBox(self, cb):
        self.checkBoxes.append(cb)
        cb.toggled.connect(self.update)
        cb.destroyed.connect(lambda: self.removeCheckBox(cb))

    def removeCheckBox(self, cb):
        try:
            self.checkBoxes.remove(cb)
            cb.toggled.disconnect(self.update)
        except:
            pass

    def allStates(self):
        return [cb.isChecked() for cb in self.checkBoxes]

    def toggleCheckBoxes(self):
        if self.checkAllIfAny:
            state = not all(self.allStates())
        else:
            state = not any(self.allStates())

        for widget in self.children():
            if not widget.isWidgetType():
                continue
            if not widget.testAttribute(QtCore.Qt.WA_ForceDisabled):
                # restore the enabled state in order to override the default
                # behavior of setChecked(False); previous explicit calls for
                # setEnabled(False) on the target widget will be ignored
                widget.setEnabled(True)
                if widget in self.checkBoxes:
                    widget.setChecked(state)

    def paintEvent(self, event):
        opt = QtWidgets.QStyleOptionGroupBox()
        self.initStyleOption(opt)
        states = self.allStates()
        if all(states):
            # force the "checked" state
            opt.state |= QtWidgets.QStyle.State_On
            opt.state &= ~QtWidgets.QStyle.State_Off
        else:
            # force the "not checked" state
            opt.state &= ~QtWidgets.QStyle.State_On
            if any(states):
                # force the "not unchecked" state and set the tristate mode
                opt.state &= ~QtWidgets.QStyle.State_Off
                opt.state |= QtWidgets.QStyle.State_NoChange
            else:
                # force the "unchecked" state
                opt.state |= QtWidgets.QStyle.State_Off
        painter = QtWidgets.QStylePainter(self)
        painter.drawComplexControl(QtWidgets.QStyle.CC_GroupBox, opt)


app = QtWidgets.QApplication([])
groupBox = Custom_QGroupBox('Group options')

layout = QtWidgets.QGridLayout(groupBox)
o = 0
for c in range(2):
    for r in range(4):
        o += 1
        cb = QtWidgets.QCheckBox('Option {}'.format(o))
        groupBox.addCheckBox(cb)
        layout.addWidget(cb, r, c)

groupBox.show()
app.exec_()
于 2021-11-17T03:42:28.467 回答