unselect 和 select PyQt5 中的所有复选框
unselect and select all checkboxes in PyQt5
类似于
我想要一个复选框
- unselect 所有 selected 复选框。
- 还有一个复选框 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()
如何使用此设置获得工作代码?
您的代码存在各种问题。
- 您正在尝试访问 class 属性,例如
MainWindow.checkB
、MainWindow.checkBoxNone
等。它们不存在。您应该使用 instance 属性,使用 self.checkB
; 之类的东西
- 要完成上述工作,您还必须 设置 这些属性,因此
checkBoxNone = QCheckBox("None Selected")
应该是 self.checkBoxNone = QCheckBox("None Selected")
,等等
- 您正在将
checkBoxNone.stateChanged
连接到需要两个位置参数的函数,但 stateChanged()
只有一个(状态);没有复选框信号 returns 文本;
- 在您的函数中,您没有选中或取消选中任何其他复选框;
- 即使假设您使用了正确的引用(
self.checkBoxNone
,等等),您也不应该像在代码中那样检查未选中的框(或相反)作为 stateChanged 信号的结果,因为它将导致递归;
- 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()
也就是说,让我告诉你,不建议使用复选框来完成你正在做的事情,因为它在视觉上和交互的角度上都是违反直觉的。最好使用一个按钮来检查所有内容,另一个按钮用于取消检查。
另外,命名变量和属性时要小心;例如,checkAll
和 selectAll
非常相似,但它们指的是两个截然不同且截然不同的对象:复选框和函数;他们的名字也应该反映出这种差异。虽然不遵循这个原则并不代表技术问题,但当对象(函数、属性等)的数量随着程序的增长而增长时,它可能会成为一个问题:使用清晰和描述性的名称可以提高可读性(和心理参考),这是开发和问题跟踪的一个重要方面。
同样的概念适用于循环:不要对列表和迭代器元素都使用 wordlist
。
类似于
我想要一个复选框
- unselect 所有 selected 复选框。
- 还有一个复选框 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()
如何使用此设置获得工作代码?
您的代码存在各种问题。
- 您正在尝试访问 class 属性,例如
MainWindow.checkB
、MainWindow.checkBoxNone
等。它们不存在。您应该使用 instance 属性,使用self.checkB
; 之类的东西
- 要完成上述工作,您还必须 设置 这些属性,因此
checkBoxNone = QCheckBox("None Selected")
应该是self.checkBoxNone = QCheckBox("None Selected")
,等等 - 您正在将
checkBoxNone.stateChanged
连接到需要两个位置参数的函数,但stateChanged()
只有一个(状态);没有复选框信号 returns 文本; - 在您的函数中,您没有选中或取消选中任何其他复选框;
- 即使假设您使用了正确的引用(
self.checkBoxNone
,等等),您也不应该像在代码中那样检查未选中的框(或相反)作为 stateChanged 信号的结果,因为它将导致递归; - 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()
也就是说,让我告诉你,不建议使用复选框来完成你正在做的事情,因为它在视觉上和交互的角度上都是违反直觉的。最好使用一个按钮来检查所有内容,另一个按钮用于取消检查。
另外,命名变量和属性时要小心;例如,checkAll
和 selectAll
非常相似,但它们指的是两个截然不同且截然不同的对象:复选框和函数;他们的名字也应该反映出这种差异。虽然不遵循这个原则并不代表技术问题,但当对象(函数、属性等)的数量随着程序的增长而增长时,它可能会成为一个问题:使用清晰和描述性的名称可以提高可读性(和心理参考),这是开发和问题跟踪的一个重要方面。
同样的概念适用于循环:不要对列表和迭代器元素都使用 wordlist
。