PyQt5 – 三态复选框

  • Post category:Python

PyQt5是一个流行的Python GUI库,它包括了丰富的UI组件。三态复选框是其中一种常用的控件之一。本文将针对Python的PyQt5库的三态复选框进行详细讲解。

PyQt5中的三态复选框

三态复选框是一种多选框控件,它有三种状态:未选中,选中和半选中。半选中状态表示其相关联的子选项只有一部分选中。在PyQt5中,三态复选框组件常用于实现复杂的多选数据筛选或数据分类。

PyQt5中三态复选框的创建

对于一个三态复选框,我们需要创建一个QCheckBox对象并将其设置为三态复选框模式。

from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QWidget, QCheckBox, QVBoxLayout

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        vbox = QVBoxLayout()

        # 创建一个QCheckBox对象,设置为三态复选框模式
        self.checkbox = QCheckBox('三态复选框', self)
        self.checkbox.setTristate(True)
        vbox.addWidget(self.checkbox)

        self.setLayout(vbox)
        self.show()

在这个例子中,我们创建了一个QWidget实例,并在其中创建了一个QCheckBox对象。我们将setTristate()方法用于设置复选框为三态复选框模式。最终的结果是我们得到了一个基本的三态复选框控件。

三态复选框的状态和检测

一旦我们创建了一个三态复选框,我们需要检测其被选中的状态。

    def initUI(self):
        vbox = QVBoxLayout()

        self.checkbox = QCheckBox('三态复选框', self)
        self.checkbox.setTristate(True)
        vbox.addWidget(self.checkbox)

        # 增加一个按钮,并用于检测并打印复选框的状态
        from PyQt5.QtWidgets import QPushButton
        btn = QPushButton('获取复选框状态', self)
        btn.clicked.connect(self.print_state)
        vbox.addWidget(btn)

        self.setLayout(vbox)
        self.show()

    def print_state(self):
        if self.checkbox.isChecked():
            print("选中状态")
        elif self.checkbox.checkState() == Qt.PartiallyChecked:
            print("半选中状态")
        else:
            print("未选中状态")

这个例子中我们添加了一个按钮,用于检测三态复选框的状态。打印不同状态的伪代码被放在print_state()方法中。我们可以通过isChecked()方法检查是否选中,通过checkState()方法检查复选框状态是否是部分选中。

三态复选框的事件

在PyQt5中,我们可以监听三态复选框的CheckedChanged事件。每当复选框的状态改变时,我们就会调用相应的槽函数。这样我们可以获得复选框的新状态并做相应处理。

    def initUI(self):
        vbox = QVBoxLayout()

        self.checkbox = QCheckBox('三态复选框', self)
        self.checkbox.setTristate(True)
        vbox.addWidget(self.checkbox)

        btn = QPushButton('获取复选框状态', self)
        btn.clicked.connect(self.print_state)
        vbox.addWidget(btn)

        # 监听复选框的CheckedChanged事件
        self.checkbox.stateChanged.connect(self.checkbox_changed)

        self.setLayout(vbox)
        self.show()

    def checkbox_changed(self):
        if self.checkbox.isChecked():
            print("选中状态")
        elif self.checkbox.checkState() == Qt.PartiallyChecked:
            print("半选中状态")
        else:
            print("未选中状态")

在这个例子中,我们添加了一个槽函数checkbox_changed()。我们使用stateChanged信号将其连接到三态复选框。checkbox_changed()方法将根据新状态执行相应的代码。

示例1:在QTreeView中使用三态复选框

在这个示例中,我们演示如何使用三态复选框在QTreeView中选择和展开项目。

import sys
from PyQt5.QtGui import QStandardItemModel, QStandardItem
from PyQt5.QtWidgets import QTreeView, QWidget, QVBoxLayout, QCheckBox, QApplication


class TreeViewExample(QWidget):

    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        vbox = QVBoxLayout()

        # 为treeview创建一个model
        self.model = QStandardItemModel()
        self.treeView = QTreeView()
        self.treeView.setModel(self.model)
        vbox.addWidget(self.treeView)

        # 添加根节点
        root = QStandardItem('示例')
        root.setCheckable(True)
        root.setTristate(True)
        self.model.invisibleRootItem().appendRow(root)

        # 为根节点添加子节点
        for i in range(5):
            child_node = QStandardItem(f'子节点{i}')
            child_node.setCheckable(True)
            root.appendRow(child_node)

        self.setLayout(vbox)
        self.show()

        # 监听复选框的CheckedChanged事件
        self.model.itemChanged.connect(self.treeItemChanged)

    def treeItemChanged(self, item: QStandardItem):
        # 检查复选框状态的改变
        if item.checkState() == Qt.Checked:
            print(item.text() + " 选中")
        elif item.checkState() == Qt.Unchecked:
            print(item.text() + " 未选中")
        else:
            print(item.text() + " 半选中")

        # 延展或折叠节点
        if item.checkState() != Qt.PartiallyChecked:
            rows = []
            topLevel = item.parent()
            if topLevel is None:
                rows = [self.model.indexFromItem(item), ]
            else:
                for i in range(topLevel.rowCount()):
                    child = topLevel.child(i, 0)
                    if child.checkState() == Qt.Checked:
                        rows.append(self.model.indexFromItem(child))
            for row in rows:
                self.treeView.setExpanded(row, item.checkState() == Qt.Checked)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    treeview = TreeViewExample()
    sys.exit(app.exec_())

在这个示例中,我们在QTreeView控件中使用了三态复选框,用于选择和拓展子节点。我们创建了一个QStandardItemModel,并在其上创建了根节点和5个子节点。每个子节点都是可选的并可以处于三态复选框状态。我们通过传递itemChanged信号连接树的事件来检测负责节点的复选框状态。

示例2:在多个三态复选框中选择员工

在这个示例中,我们演示了如何使用多个三态复选框,根据不同的员工属性筛选和分类员工。

import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QStandardItemModel, QStandardItem
from PyQt5.QtWidgets import QTreeView, QLineEdit, QPushButton, QVBoxLayout, QWidget


class Employee:
    def __init__(self, first, last, department, salary, city, state):
        self.firstName = first
        self.lastName = last
        self.department = department
        self.salary = salary
        self.city = city
        self.state = state


class EmployeesModel(QStandardItemModel):
    def __init__(self, employees):
        super().__init__()

        self.setHorizontalHeaderLabels(['员工', '部门', '工资', '城市', '州'])

        for emp in employees:
            emp_item = QStandardItem(f'{emp.firstName} {emp.lastName}')
            emp_item.setEditable(False)
            self.appendRow([emp_item, QStandardItem(emp.department), QStandardItem(str(emp.salary)), QStandardItem(emp.city), QStandardItem(emp.state)])


class EmployeeListExample(QWidget):

    def __init__(self):
        super().__init__()

        self.employees = [
            Employee('John', 'Smith', '销售', 65000, '纽约市', '纽约州'),
            Employee('Jane', 'Doe', '销售', 65000, '纽约市', '纽约州'),
            Employee('Joe', 'Johnson', '制造', 80000, '迈阿密', '佛罗里达州'),
            Employee('Mary', 'Smith', '制造', 80000, '迈阿密', '佛罗里达州'),
            Employee('Tom', 'Jones', 'IT', 90000, '旧金山', '加利福尼亚州'),
            Employee('Harry', 'Garcia', 'IT', 90000, '旧金山', '加利福尼亚州')
        ]

        self.initUI()

    def initUI(self):
        vbox = QVBoxLayout()

        # 创建一个model
        self.model = EmployeesModel(self.employees)

        # 创建treeview
        self.treeView = QTreeView()
        self.treeView.setModel(self.model)
        vbox.addWidget(self.treeView)

        # 创建筛选框
        self.filterLineEdit = QLineEdit(self)
        self.filterLineEdit.setPlaceholderText("搜索关键字")
        vbox.addWidget(self.filterLineEdit)

        # 向UI中添加员工属性筛选框
        dept_checkbox = self.create_checkbox("部门")
        dept_checkbox.stateChanged.connect(self.filter)

        city_checkbox = self.create_checkbox("城市")
        city_checkbox.stateChanged.connect(self.filter)

        state_checkbox = self.create_checkbox("州")
        state_checkbox.stateChanged.connect(self.filter)

        vbox.addStretch(1)
        self.setLayout(vbox)
        self.show()

    def create_checkbox(self, text):
        checkbox = QCheckBox(text, self)
        checkbox.setCheckState(Qt.Checked)
        checkbox.setTristate(False)
        self.layout().addWidget(checkbox)
        return checkbox

    def filter(self):
        filters = []
        if self.filterLineEdit.text():
            filters.append(self.filterLineEdit.text())

        for i in range(self.layout().count()):
            widget = self.layout().itemAt(i).widget()
            if isinstance(widget, QCheckBox) and widget.checkState() == Qt.Checked:
                filters.append(widget.text())

        self.model.setRowCount(0)
        for emp in self.employees:
            if all(f.lower() in str(emp.__dict__.values()).lower()
                   for f in filters):
                self.model.appendRow([QStandardItem(f'{emp.firstName} {emp.lastName}'),
                                      QStandardItem(emp.department),
                                      QStandardItem(str(emp.salary)),
                                      QStandardItem(emp.city),
                                      QStandardItem(emp.state)])
if __name__ == '__main__':
    app = QApplication(sys.argv)
    employeeList = EmployeeListExample()
    sys.exit(app.exec_())

在这个示例中,我们将三态复选框用于筛选员工数据。我们首先创建了一个名为 Employee 的类,该类表示员工的属性和统计数据。接下来,我们将Employee作为一个数组放入QStandardItemModel。之后,我们根据Employee属性添加三个复选框,以便可以按部门、城市或州过滤数据。

在筛选框中,我们可以同时输入搜索关键字和选择筛选属性。我们使用all()对每一行数据进行比较,以确认它是否满足给定的筛选条件。最后,只有符合条件的行才会在UI中呈现。