from PyQt5.QtWidgets import QWidget, QComboBox, QLineEdit, QListView from PyQt5.QtGui import QStandardItemModel, QStandardItem, QMouseEvent from PyQt5.Qt import Qt global classIds classIds = '' # 全选与单选的绑定(没有这个会导致勾选数据错乱) def show_text(function): def wrapped(self, *args, **kwargs): global classIds if self.vars["showTextLock"]: self.vars["showTextLock"] = False result = function(self, *args, **kwargs) items = self.get_selected() l = len(items) l_ = self.vars["listViewModel"].rowCount() - 1 self.vars["listViewModel"].item(0).setCheckState( Qt.Checked if l == l_ else Qt.Unchecked if l == 0 else Qt.PartiallyChecked) self.vars["lineEdit"].setText( "(全选)" if l == l_ else "(无选择)" if l == 0 else ";".join((item.text() for item in items))) self.vars["showTextLock"] = True classIds = "" if l == 0 else ",".join((item.text().split('.')[0] for item in items)) else: result = function(self, *args, **kwargs) return result return wrapped # 选项的渲染和选择后的显示 class QComboCheckBox(QComboBox): class MyListView(QListView): def __init__(self, parent: QWidget = None, vars=None): super().__init__(parent) self.vars = vars def mousePressEvent(self, event: QMouseEvent): self.vars["lock"] = False super().mousePressEvent(event) def mouseDoubleClickEvent(self, event: QMouseEvent): self.vars["lock"] = False super().mouseDoubleClickEvent(event) def __init__(self, parent: QWidget = None): super().__init__(parent) self.vars = dict() self.vars["lock"] = True self.vars["showTextLock"] = True # 装饰器锁,避免批量操作时重复改变lineEdit的显示 self.vars["lineEdit"] = QLineEdit(self) self.vars["lineEdit"].setReadOnly(True) self.vars["listView"] = self.MyListView(self, self.vars) self.vars["listViewModel"] = QStandardItemModel(self) self.setModel(self.vars["listViewModel"]) self.setView(self.vars["listView"]) self.setLineEdit(self.vars["lineEdit"]) self.activated.connect(self.__show_selected) self.add_item("(全选)") @show_text def add_item(self, text: "str", flag=False): # 根据文本添加子项 item = QStandardItem() item.setText(text) item.setCheckable(True) if flag: item.setCheckState(Qt.Checked) self.vars["listViewModel"].appendRow(item) # 根据文本查找子项 def find_text(self, text: "str"): tempList = self.vars["listViewModel"].findItems(text) tempList.pop(0) if tempList and tempList[0].row() == 0 else tempList return tempList # 获取班级ids def get_class_text(self): return classIds @show_text # 全选 def select_all(self): for row in range(0, self.vars["listViewModel"].rowCount()): self.vars["listViewModel"].item(row).setCheckState(Qt.Checked) @show_text # 全不选 def select_clear(self): for row in range(0, self.vars["listViewModel"].rowCount()): self.vars["listViewModel"].item(row).setCheckState(Qt.Unchecked) # 获取当前选择的子项 def get_selected(self): items = list() for row in range(1, self.vars["listViewModel"].rowCount()): item = self.vars["listViewModel"].item(row) if item.checkState() == Qt.Checked: items.append(item) return items @show_text # 显示选中的选项 def __show_selected(self, index): # 未被选中 if not self.vars["lock"]: # 选中全选 if index == 0: if self.vars["listViewModel"].item(0).checkState() == Qt.Checked: self.select_clear() else: self.select_all() # 选中其他 else: self.__select_reverse(index) self.vars["lock"] = True # 选中一个选项 def __select_reverse(self, row: "int"): item = self.vars["listViewModel"].item(row) item.setCheckState(Qt.Unchecked if item.checkState() == Qt.Checked else Qt.Checked)