【问题标题】:Python2 PyQt4 Connect a bool Variable to a QCheckBox itemPython2 PyQt4 将 bool 变量连接到 QCheckBox 项
【发布时间】:2014-06-05 21:57:30
【问题描述】:

我对 QCheckBox 有疑问。

我正在尝试将一个布尔变量连接到一个 QCheckBox,以便 当我更改布尔变量时,QCheckBox 将被自动选中或取消选中。

我的问题与下面的问题类似,但方式相反。

question: Python3 PyQt4 Creating a simple QCheckBox and changing a Boolean variable

我只是将那个问题的一个解决方案复制到这里。

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 会做出正确的反应。


更新:

感谢您的所有回复和帮助。你所有的解决方案都很棒!!!我需要的方式更像是一个 Modeling-View 解决方案,以便我可以将建模部分与 gui 部分分开。当我想更新一些东西时,我只需要更新建模,而不需要关注 gui 的样子。我无法在 View Class 中设置此 Bool 属性,因此无法使用此解决方案。

我不确定 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。 .

【问题讨论】:

  • 你可以用@property 做到这一点,但我不明白你为什么需要它。只需公开复选框并使用setChecked 而不是分配给变量。
  • @Avaris 感谢您的帮助。我正在使用 MVC,所以我不想将 checkBox 暴露给模型
  • 我会写一个答案,但我仍然认为这不是正确的方法。但是,如果不了解您的用例,我无法提出其他建议(可能是 QDataWidgetMapper)。

标签: python model-view-controller pyqt model-view qcheckbox


【解决方案1】:

正如 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()

并连接信号和插槽,将该行添加到 _ _ init _ _ 上一行之后的某个位置。 重要提示,您没有绑定在 SelectionWindow 类中建立连接

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

为了测试结果,只需添加:

 window.ILCheck.value = True

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

由于结构原因,完整的代码示例被添加到末尾

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_())

【讨论】:

  • 我意识到这是一个旧帖子。但只是想说声谢谢。我发现 SmartBool 很有帮助。一个改进说明,我发现有必要在设置器中更改发射信号的顺序。如果您在设置值之前发出信号,则您正在实现 valueChanging,而不是 valueChanged。首先设置值然后发出信号允许在槽处理程序中针对布尔值的新值进行测试。
【解决方案2】:

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_())

【讨论】:

  • 感谢您的回复和帮助。你的解决方案很棒!!!我需要的方式更像是一个建模视图解决方案,以便我可以将建模部分与 gui 部分分开。当我想更新一些东西时,我只需要更新建模,而不需要关注 gui 的样子。我无法在 View Class 中设置此 Bool 属性,因此无法使用此解决方案。
【解决方案3】:

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

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

如果您想多次使用此功能,您应该考虑编写一个 setter 来更改 self.ILCheck 的状态并发出信号。

在您澄清后编辑:

【讨论】:

  • 感谢您的帮助。对不起,我没有解释清楚。你可以在上面查看我的更新
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-24
  • 1970-01-01
  • 2016-02-29
  • 1970-01-01
  • 1970-01-01
  • 2018-03-12
相关资源
最近更新 更多