PyQt5中有一个代码,它类似于树形表(QTreeView
),您可以在其中使用复选框来选择复选框。我需要这个表像这样工作:
- 如果所有复选框都被禁用(没有标记复选标记)并且您单击父类,则父类和所有子类都被启用 - 这已经起作用了,完成了;
- 如果父复选框的所有子复选框都被禁用,并且您单击一个子复选框,则该子复选框和父复选框都会被启用。其余子复选框不包含在内;
- 如果所有复选框都启用(父级和所有子级),并且您启用/禁用一个子级,则只有该子级复选框会发生变化,其余的复选框不会发生变化。
我设法做到了第 1 点和第 3 点,但第 2 点就是行不通。我能做到的唯一方法是,如果我启用一个子复选框(单击它),那么所有子复选框和父复选框都会被启用 - 但它不应该那样工作。
请帮帮我。
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import QWidget
import pandas as pd
class Pivot_table(QTreeView):
def __init__(
self,
table_name: str,
table_width: int,
columns_width: list,
data_frame: pd.DataFrame,
index_cols: list,
columns_cols: list,
values_cols: list,
included_checkBox: bool):
super().__init__()
data_frame = data_frame[index_cols]
pivot_df = data_frame.pivot_table(
index=index_cols,
aggfunc='sum',
fill_value=0)
header_names = [table_name]
if columns_cols is not None:
header_names = header_names + columns_cols
if values_cols is not None:
header_names = header_names + values_cols
self.model_Pivot_table = QStandardItemModel()
self.model_Pivot_table.setHorizontalHeaderLabels(
header_names)
self.model_Pivot_table.itemChanged.connect(
self.status_checkboxses)
# Настройка QTreeView
self.setModel(self.model_Pivot_table)
self.setFixedWidth(table_width)
self.setEditTriggers(
QAbstractItemView.EditTrigger.NoEditTriggers)
self.populate_model(
index_cols, pivot_df, included_checkBox)
if columns_width is not None: # Установка ширины столбцов
for column in columns_width:
self.setColumnWidth(column[0], column[1])
def populate_model(self, index_cols, pivot_df, included_checkBox):
parent_items = {}
for row_index, (index_value, row) in enumerate(pivot_df.iterrows()):
index_values = index_value \
if isinstance(index_value, tuple) \
else (index_value,)
parent_item = None
for idx, value in enumerate(index_values):
if idx == 0: # Родительский уровень
if value not in parent_items:
parent_item = QStandardItem(str(value))
if included_checkBox:
parent_item.setCheckable(True)
parent_item.setCheckState(Qt.CheckState.Checked)
self.model_Pivot_table.appendRow(parent_item)
parent_items[value] = parent_item
else:
parent_item = parent_items[value]
else:
child_found = False
for i in range(parent_item.rowCount()):
if parent_item.child(i, 0).text() == str(value):
child_item = parent_item.child(i, 0)
child_found = True
break
if not child_found:
child_item = QStandardItem(str(value))
if included_checkBox:
child_item.setCheckable(True)
child_item.setCheckState(Qt.CheckState.Checked)
parent_item.appendRow(child_item)
parent_item = child_item
# Добавление значения из сводной таблицы
for col_value in pivot_df.columns:
value_item = QStandardItem(str(row[col_value]))
if included_checkBox:
value_item.setCheckable(True)
value_item.setCheckState(Qt.CheckState.Checked)
parent_item.appendRow(value_item)
def status_checkboxses(self, item):
if not item.parent():
child_count = item.rowCount()
for i in range(child_count):
child_item = item.child(i, 0)
child_item.setCheckState(item.checkState())
# Основное приложение
if __name__ == '__main__':
app = QApplication(sys.argv)
# Данные
data = {
0: [1, 2, 3, 3, 4],
1: [2, 2, 2, 3, 2],
'ФИО': [
'Иванов Иван Иванович',
'Иванов2 Иван2 Иванович2',
'Иванов3 Иван3 Иванович3',
'Иванов4 Иван4 Иванович4',
'Иванов5 Иван5 Иванович5']
}
df_residents = pd.DataFrame(data)
widget_apartment = Pivot_table(
table_name= 'Кв и ФИО',
table_width= 680,
columns_width=[[0, 640]],
data_frame=df_residents,
index_cols= [1, 'ФИО'],
columns_cols= None,
values_cols= None,
included_checkBox= True)
# Устанавливаем виджет в главное окно
central_widget = QWidget()
layout = QVBoxLayout()
layout.addWidget(widget_apartment)
central_widget.setLayout(layout)
main_window = QMainWindow()
main_window.setGeometry(100, 100, 800, 600)
main_window.setCentralWidget(central_widget)
main_window.show()
sys.exit(app.exec_())