如何在 PySide/PyQt 中设置“只读复选框”

Posted

技术标签:

【中文标题】如何在 PySide/PyQt 中设置“只读复选框”【英文标题】:How to set a "read-only checkbox" in PySide/PyQt 【发布时间】:2012-07-13 14:16:12 【问题描述】:

我正在尝试使用 QCheckBox 小部件显示布尔变量的值,并使用户无法更改显示的值。我不想禁用它,因为由此产生的灰色看起来不太好。当用户单击QCheckBox 时,我试图通过将新值更改回其先前值来近似效果。但是,由于小部件的状态由 QAbstractButton 父类的“已检查”属性和 QCheckBox 类本身的“状态”属性描述,因此问题更加复杂。这引起了信号和槽的组合练习,我一直无法获得任何好的结果。

var_ctrl = QtGui.QCheckBox( 'some name' )

def rdslot1(state): 
    if state == QtCore.Qt.Checked:
        var_ctrl.setCheckState( QtCore.Qt.Unchecked )
    else:                               
        var_ctrl.setCheckState( QtCore.Qt.Checked )

def rdslot2(state): 
    if var_ctrl.isChecked():
        var_ctrl.setChecked(False)
    else:
        var_ctrl.setChecked(True)

# Signal/Slot combinations (only one should be active)
var_ctrl.stateChanged.connect( rdslot1 )
var_ctrl.toggled.connect( rdslot2 )
var_ctrl.stateChanged.connect( rdslot2 )
var_ctrl.toggled.connect( rdslot1 )

【问题讨论】:

【参考方案1】:

我迟到了 - 看来你找到了一个可行的解决方案。以供将来参考,另一种方法是使用鼠标事件 - 这使您的所有信号都以应有的方式工作:

from PyQt4 import QtGui, QtCore

class MyCheckBox(QtGui.QCheckBox):
    def __init__( self, *args ):
        super(MyCheckBox, self).__init__(*args) # will fail if passing **kwargs
        self._readOnly = False

    def isReadOnly( self ):
        return self._readOnly

    def mousePressEvent( self, event ):
        if ( self.isReadOnly() ):
            event.accept()
        else:
            super(MyCheckBox, self).mousePressEvent(event)

    def mouseMoveEvent( self, event ):
        if ( self.isReadOnly() ):
            event.accept()
        else:
            super(MyCheckBox, self).mouseMoveEvent(event)

    def mouseReleaseEvent( self, event ):
        if ( self.isReadOnly() ):
            event.accept()
        else:
            super(MyCheckBox, self).mouseReleaseEvent(event)

    # Handle event in which the widget has focus and the spacebar is pressed.
    def keyPressEvent( self, event ):
        if ( self.isReadOnly() ):
            event.accept()
        else:
            super(MyCheckBox, self).keyPressEvent(event)

    @QtCore.pyqtSlot(bool)
    def setReadOnly( self, state ):
        self._readOnly = state

    readOnly = QtCore.pyqtProperty(bool, isReadOnly, setReadOnly)

以这种方式设置代码可以获得一些东西(您可能关心也可能不关心),但在开发自定义 Qt 小部件时会很有用:

    使用该事件会阻止信号发射,因此您仍然可以将其他插槽连接到单击和切换之类的东西。如果您正在寻找这些信号,然后只是打开/关闭值 - 那么侦听这些信号的其他小部件将被错误触发 使用 isReadOnly/setReadOnly 保持类遵循 Qt 编码风格 如果您将插件公开给 Qt 的设计器,创建 pyqtSignals 和 pyqtSlots 会有所帮助

【讨论】:

【参考方案2】:

后来我想出了一个快捷方式,它可以简单地捕捉用户的点击并根据可指定的“可修改”属性进行处理。我做了这门课:

class MyQCheckBox(QtGui.QCheckBox):

    def __init__(self, *args, **kwargs):
        QtGui.QCheckBox.__init__(self, *args, **kwargs)        
        self.is_modifiable = True
        self.clicked.connect( self.value_change_slot )

    def value_change_slot(self): 
        if self.isChecked():
            self.setChecked(self.is_modifiable)
        else:
            self.setChecked(not self.is_modifiable)            

    def setModifiable(self, flag):
        self.is_modifiable = flag            

    def isModifiable(self):
        return self.is_modifiable

它的行为就像一个普通的QCheckBox,默认是可以修改的。但是,当您调用setModifiable(False) 时,每次单击它,它都会保持小部件的当前状态。诀窍是捕捉clicked 信号,而不是toggledstateChanged

【讨论】:

【参考方案3】:

尝试禁用复选框小部件,但使用小部件 palette 或 style 覆盖其外观

【讨论】:

嗯...听起来很高级。不确定我是否理解正确。您愿意提供或指向一些示例代码吗? 我没有给你的示例代码。我有一段时间没有编写 Qt 代码了。但这里有一个有趣的线程:qtforum.org/article/10564/…

以上是关于如何在 PySide/PyQt 中设置“只读复选框”的主要内容,如果未能解决你的问题,请参考以下文章

如何在PySide / PyQt中连接QApplication()和QWidget()对象?

如何创建一个新的窗口按钮 PySide/PyQt?

PySide/PyQT5:如何从 QGraphicsItem 发出信号?

如何显示 PySide/PyQt UI 并自动运行其中一种方法?

PySide/PyQt QMainWindow 如何关闭 QDockWidget?

模型中 dropActions 的访问值 (PySide/PyQt/Qt)