unselect 和 select PyQt5 中的所有复选框

unselect and select all checkboxes in PyQt5

类似于

我想要一个复选框

  1. unselect 所有 selected 复选框。
  2. 还有一个复选框 select 所有复选框
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QMainWindow, QTableView, QGridLayout, QWidget, QCheckBox
from PyQt5.QtGui import QFont
from functools import partial

class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        self.font = QFont("Helvetica", 9)
        self.setFont(self.font)
        self.showMaximized()     
        grid = QGridLayout()
        self.setLayout(grid)

        positions = [(i,j) for i in range(5) for j in range(5)]
        print('\npostions: ', positions)
        wordlist = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y']


        for position, wordlist in zip(positions, wordlist): 
            checkB =(QCheckBox(wordlist)) 
            checkB.setStatusTip("Crawling best singals for "+wordlist+"." ) # set Statusbar
            checkB.stateChanged.connect(partial(self.checkState, wordlist))
            grid.addWidget(checkB, *position)

        checkBoxNone = QCheckBox("None Selected")
        checkBoxNone.setChecked(True)
        checkBoxNone.stateChanged.connect(self.checkState)
        grid.addWidget(checkBoxNone, 6, 1)

        checkAll = QCheckBox("Select All")
        checkAll.setChecked(False)
        checkAll.stateChanged.connect(self.selectAll)
        grid.addWidget(checkAll, 6, 2)

        widget = QWidget()
        widget.setLayout(grid) 
        self.setCentralWidget(widget)      

        self.statusBar().showMessage('Ready')

    # Here are the problems. 
    # Is it because I have create checkboxes with a for loop?

    def selectAll(self, state):
        if state == Qt.Checked:
            if self.sender() == MainWindow.checkAll:
                MainWindow.checkB.setChecked(True)

    def checkState(self, checktext, state):
        if state == Qt.Checked:
            print(checktext)
            if self.sender() == MainWindow.checkBoxNone:
                MainWindow.checkB.setChecked(False)
            elif self.sender() == MainWindow.checkB:
                MainWindow.checkBoxNone.setChecked(False)

if __name__ == '__main__':

    app = QApplication(sys.argv)
    app.setStyle('Fusion')
    mw = MainWindow()

如何使用此设置获得工作代码?

您的代码存在各种问题。

  1. 您正在尝试访问 class 属性,例如 MainWindow.checkBMainWindow.checkBoxNone 等。它们不存在。您应该使用 instance 属性,使用 self.checkB;
  2. 之类的东西
  3. 要完成上述工作,您还必须 设置 这些属性,因此 checkBoxNone = QCheckBox("None Selected") 应该是 self.checkBoxNone = QCheckBox("None Selected"),等等
  4. 您正在将 checkBoxNone.stateChanged 连接到需要两个位置参数的函数,但 stateChanged() 只有一个(状态);没有复选框信号 returns 文本;
  5. 在您的函数中,您没有选中或取消选中任何其他复选框;
  6. 即使假设您使用了正确的引用(self.checkBoxNone,等等),您也不应该像在代码中那样检查未选中的框(或相反)作为 stateChanged 信号的结果,因为它将导致递归;
  7. QMainWindow 有自己的布局,您不能自己设置;另外,您已经要为中央小部件设置它了;

要使其正常工作,您应该引用您创建的所有复选框,然后应用您想要的状态,同时要非常小心地更改每个框的选中状态。

在下面的示例中,"select all" 和 "select none" 复选框分别显示为部分选中,如果不是所有复选框都被选中,或者至少有一个被选中。

class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        grid = QGridLayout()
        # You *cannot* set a layout to a main window
        # self.setLayout(grid)

        positions = [(i,j) for i in range(5) for j in range(5)]
        wordlist = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y']


        # use a list to keep a reference to all checkboxes
        <b>self.checkBoxes = []</b>
        for position, <b>word</b> in zip(positions, wordlist): 
            checkB =(QCheckBox(word)) 
            checkB.setStatusTip("Crawling best singals for "+<b>word</b>+"." ) # set Statusbar
            checkB.stateChanged.connect(self.checkStates)
            grid.addWidget(checkB, *position)
            <b>self.checkBoxes.append(checkB)</b>

        <b>self.</b>checkBoxNone = QCheckBox("Select none")
        self.checkBoxNone.setCheckState(Qt.Unchecked)
        self.checkBoxNone.stateChanged.connect(
            partial(self.selectBoxes, False))
        grid.addWidget(self.checkBoxNone, 6, 1)

        <b>self.</b>checkBoxAll = QCheckBox("Select All")
        self.checkBoxAll.setCheckState(Qt.PartiallyChecked)
        self.checkBoxAll.stateChanged.connect(
            partial(self.selectBoxes, True))
        grid.addWidget(self.checkBoxAll, 6, 2)

        widget = QWidget()
        widget.setLayout(grid) 
        self.setCentralWidget(widget)      

        self.statusBar().showMessage('Ready')

    def checkStates(self):
        states = [c.isChecked() for c in self.checkBoxes]

        # temporarily block signals so that there is no recursive calls
        self.checkBoxAll.blockSignals(True)
        self.checkBoxNone.blockSignals(True)

        # set the "select all" fully checked too if all boxes are checked,
        # otherwise make it partially checked
        self.checkBoxAll.setCheckState(
            Qt.Checked if all(states) else Qt.PartiallyChecked)

        # set the "select none" unchecked only if all boxes are unchecked,
        # otherwise make it partially checked
        self.checkBoxNone.setCheckState(
            Qt.Unchecked if not any(states) else Qt.PartiallyChecked)

        # unblock signals back
        self.checkBoxAll.blockSignals(False)
        self.checkBoxNone.blockSignals(False)

    def selectBoxes(self, state):
        for check in self.checkBoxes:
            check.blockSignals(True)
            check.setChecked(state)
            check.blockSignals(False)
        self.checkStates()

也就是说,让我告诉你,不建议使用复选框来完成你正在做的事情,因为它在视觉上和交互的角度上都是违反直觉的。最好使用一个按钮来检查所有内容,另一个按钮用于取消检查。
另外,命名变量和属性时要小心;例如,checkAllselectAll 非常相似,但它们指的是两个截然不同且截然不同的对象:复选框和函数;他们的名字也应该反映出这种差异。虽然不遵循这个原则并不代表技术问题,但当对象(函数、属性等)的数量随着程序的增长而增长时,它可能会成为一个问题:使用清晰和描述性的名称可以提高可读性(和心理参考),这是开发问题跟踪的一个重要方面。
同样的概念适用于循环:不要对列表和迭代器元素都使用 wordlist