Python2 PyQt4 将布尔变量连接到QCheckBox项

0 投票
3 回答
2919 浏览
提问于 2025-04-18 08:47

我遇到了一个关于QCheckBox的问题。

我想把一个布尔变量和QCheckBox连接起来,这样当我改变这个布尔变量时,QCheckBox会自动被勾选或取消勾选。

我的问题和下面的问题类似,但方向正好相反。

问题:Python3 PyQt4 创建一个简单的QCheckBox并改变一个布尔变量

我只是把那个问题中的一个解决方案复制过来了。

import sys

from PyQt4.QtGui import *
from PyQt4.QtCore import *

class SelectionWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.ILCheck = False

        ILCheckbox = QCheckBox(self)
        ILCheckbox.setCheckState(Qt.Unchecked)

        ILCheckbox.stateChanged.connect(self.ILCheckbox_changed)

        MainLayout = QGridLayout()
        MainLayout.addWidget(ILCheckbox, 0, 0, 1, 1)

        self.setLayout(MainLayout)

    def ILCheckbox_changed(self, state):
        self.ILCheck = (state == Qt.Checked)

        print(self.ILCheck)


if __name__ == '__main__':
  app = QApplication(sys.argv)
  window = SelectionWindow()

  window.show()
  window.ILCheck = True
  sys.exit(app.exec_())

在这种情况下,一旦我把ILCheck设置为True,QCheckBox就会被勾选。

任何帮助都非常感谢!!!

谢谢!!!!


更新:

我在我的项目中使用MVC,这段代码只是一个示例,展示我需要的功能。布尔值ILCheck会在其他地方使用,我不想在我的模型中调用ILCheckBox

我希望如果我修改ILCheck的值,ILCheckBox能够正确反应。


更新:

感谢大家的回复和帮助。你们的解决方案都很棒!!!我需要的方式更像是模型-视图的解决方案,这样我可以把模型部分和界面部分分开。当我想更新某些内容时,我只需要更新模型,而不需要关注界面的样子。我不能在视图类中设置这个布尔属性,所以我无法使用这个解决方案。

我不确定MVC在PyQT中是否合适。我有一个类似的解决方案,但遇到了问题。

from PyQt4 import QtGui, QtCore, uic
import sys
class CellList(QtGui.QStandardItemModel):
    def __init__(self, cells = [], parent = None):
        QtGui.QStandardItemModel.__init__(self, parent)
        self.__cells = cells
        self.add(cells)

    def headerData(self, section, orientation, role):
        if role == QtCore.Qt.DisplayRole:
            return QtCore.QString("Cell id List")
    def flags(self, index):
        return QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable

    def add(self, cells):
        for i in xrange(0, len(cells)):
            item = QtGui.QStandardItem('Cell %s' % cells[i][0])
            if (cells[i][1]):
                item.setCheckState(QtCore.Qt.Checked)
            else:
                item.setCheckState(QtCore.Qt.Unchecked)

            item.setCheckable(True)
            self.appendRow(item)
    def update(self, cells = None):
        # TODO: Making this working with out clean all old Cell
        self.clear()
        if cells is None: 
            cells = self.__cells
        else:
            print "hi"
            self.__cells = cells
        print cells
        self.add(cells)

if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)
    listView = QtGui.QListView()
    listView.show()

    data = [[85, True], (105, True), (123, False)]
    model = CellList(data)
    listView.setModel(model)

    data[0][1] = False
    model.update(data)

    sys.exit(app.exec_())

这个解决方案出现了一个问题,我无法解决。我认为只有视图可以设置模型。我不确定是否可以将模型设置给单个QCheckBox

3 个回答

0

只需在调用 ILCheck 之后使用 ILCheckbox.setCheckState(Qt.Checked)

这里不需要信号,因为你可以直接调用一个槽函数。

如果你想多次使用这个功能,建议你写一个设置函数,这个函数可以改变 self.ILCheck 的状态,并发送一个信号。

根据你的澄清进行编辑:

  • 你可以使用设置函数的方法,但不是设置 ILCheckbox 的值,而是应该调用 your_properly_named_anddefine_signal.emit()。关于信号定义的更多信息,可以参考 http://www.pythoncentral.io/pysidepyqt-tutorial-creating-your-own-signals-and-slots/
  • 你需要将你的信号连接到一个槽,这个槽会正确地设置复选框。这个连接可以在你的控制器类的 __init__() 方法中完成。
1

property 是一种定义变量的方法,它在你给变量赋值或访问它时可以做一些额外的工作。下面的代码就是为了这个目的而修改的。它把 ILCheck 变成了一个属性,这样在赋值的时候也会更新复选框。关于 .setter 的错误检查没有写,但实际上通常是需要的。

import sys

from PyQt4.QtGui import *
from PyQt4.QtCore import *

class SelectionWindow(QWidget):
    def __init__(self, parent=None):
        super(SelectionWindow, self).__init__(parent)

        self._ILCheck = False

        self.ILCheckbox = QCheckBox(self)
        self.ILCheckbox.setCheckState(Qt.Unchecked)

        self.ILCheckbox.stateChanged.connect(self.ILCheckbox_changed)

        MainLayout = QGridLayout()
        MainLayout.addWidget(self.ILCheckbox, 0, 0, 1, 1)

        self.setLayout(MainLayout)

    def ILCheckbox_changed(self, state):
        self._ILCheck = (state == Qt.Checked)

        print(self.ILCheck)

    @property
    def ILCheck(self):
        return self._ILCheck

    @ILCheck.setter
    def ILCheck(self, value):
        self._ILCheck = value
        self.ILCheckbox.setChecked(value)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = SelectionWindow()

    window.show()
    window.ILCheck = True
    sys.exit(app.exec_())
3

正如Avaris在他的回答中提到的,模拟重载操作符=是解决这个问题的一个好方法。不过,代码还需要添加到SelectionWindow类中。

既然我们使用的是Qt,那么我们可以创建一个自定义的QObject,它代表我们的“智能”布尔变量,当它的值改变时会发出信号。

class SmartBool(QObject):

    valueChanged = pyqtSignal(bool)         # Signal to be emitted when value changes.

    def __init__(self):
        super(SmartBool, self).__init__()   # Call QObject contructor.
        self.__value = False                # False initialized by default.

    @property
    def value(self):
        return self.__value

    @value.setter
    def value(self, value):
        if self.__value != value:
            self.valueChanged.emit(value)   # If value change emit signal.
            self.__value = value

现在你的代码只需要做几个小改动:

把这一行替换为:

self.ILCheck = False

改为:

self.ILCheck = SmartBool()

然后连接信号和槽,在上面那行之后的某个地方添加这一行。重要的是,你不一定要在SelectionWindow类中进行连接

self.connect(self.ILCheck, SIGNAL("valueChanged(bool)"), ILCheckbox, SLOT("setChecked(bool)"))

为了测试结果,只需在你的“main”中添加:

 window.ILCheck.value = True

下次运行示例时,你会看到复选框被选中。

完整的代码示例已添加在最后,主要是为了美观

import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *

class SmartBool(QObject):

    valueChanged = pyqtSignal(bool)         # Signal to be emitted when value changes.

    def __init__(self, value=False):
        super(SmartBool, self).__init__()   # Call QObject contructor.
        self.__value = value                # False initialized by default.

    @property
    def value(self):
        return self.__value

    @value.setter
    def value(self, value):
        if self.__value != value:
            self.valueChanged.emit(value)   # If value change emit signal.
            self.__value = value


class SelectionWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.ILCheck = SmartBool()          # Your steroides bool variable.
        ILCheckbox = QCheckBox(self)
        self.connect(self.ILCheck, SIGNAL("valueChanged(bool)"), ILCheckbox, SLOT("setChecked(bool)"))
        ILCheckbox.setCheckState(Qt.Unchecked)
        ILCheckbox.stateChanged.connect(self.ILCheckbox_changed)
        MainLayout = QGridLayout()
        MainLayout.addWidget(ILCheckbox, 0, 0, 1, 1)
        self.setLayout(MainLayout)

    def ILCheckbox_changed(self, state):
        self.ILCheck = (state == Qt.Checked)
        print(self.ILCheck)


if __name__ == '__main__':
  app = QApplication(sys.argv)
  window = SelectionWindow()
  window.show()
  window.ILCheck.value = True
  sys.exit(app.exec_())

撰写回答