pyqt5多tablewidget,在表格后面加勾选框,并为每个勾选框绑定槽函数

想法:

需要在页面的多个tablewidget中,每个表格控件的最后一列加上勾选框,勾选状态下,此行可编辑,取消勾选之后,该行置灰不可编辑;新增按钮可新增一行

运行结果:

在这里插入图片描述

代码

添加勾选框方法
    def setup_checkbox(self, table_widget, row, column):
        """
        对表格的单元格添加QCheckBox并连接信号
        :param table_widget: QTableWidget对象
        :param row: 行
        :param column: 列
        :return:
        """
        widget = QWidget()  # 方法内的局部变量,每次调用都是新的副本,所以才能单独让每个tablewidget的勾选框独立连接信号
        widget.checkbox = QCheckBox()  # 将checkbox放在widget中
        widget.checkbox.setCheckState(Qt.Checked)  # 默认全部勾选
        playout = QHBoxLayout(widget)
        playout.addWidget(widget.checkbox)  # 为小部件添加checkbox属性
        playout.setAlignment(Qt.AlignCenter)  # 设置小控件水平居中
        widget.setLayout(playout)  # 在QWidget放置布局

        table_widget.setCellWidget(row, column, widget)
        # 连接勾选框的stateChanged信号,使用lambda来捕获row和table_widget,并只传递状态参数给回调函数
        widget.checkbox.stateChanged.connect(lambda state: self.on_checkbox_state_changed(table_widget, row, state))
新增一行方法
    def table_add_row(self, table_widget):
        # 在表格下方新增一行
        current_row = table_widget.rowCount()   # 当前行数
        current_col = table_widget.columnCount()  # 当前列数
        # 插入新行
        table_widget.insertRow(current_row)
        # 添加勾选框,并且为每个勾选框连接信号
        self.setup_checkbox(table_widget, current_row, current_col-1)

        for column in range(current_col-1):
            # 默认新建的单元格内容是空,所以填充item和属性
            item = QTableWidgetItem()
            # 设置单元格属性居中
            item.setTextAlignment(Qt.AlignCenter)
            table_widget.setItem(current_row, column, item)

        # 自动调整行高
        table_widget.resizeRowToContents(current_row)
        self.set_cells_attribute(table_widget)
部分代码

从xml读取内容填充进不同的tablewidget中

class Config_FL_Window(QWidget, Ui_Freq_lineLoss):
    # 初始化,配置频点和线损的页面
    def __init__(self, app_path='./'):
        """
        :param app_path: 程序运行目录
        """
        super().__init__()
        self.setupUi(self)
        self._app_path = app_path  # 配置文件的根目录

        # 不同监听口在不同表格中显示
        self.models_dict = {"TT": self.tableWidget_TT, "TR": self.tableWidget_TR, "TS": self.tableWidget_TS,
                            "FT": self.tableWidget_FT, "FR": self.tableWidget_FR}
        # 不同表格下面的新增按钮
        self.add_buttons = {"TT": self.add_TT, "TR": self.add_TR, "TS": self.add_TS, "FT": self.add_FT, "FR": self.add_FR}

        # 配置表格的列对应配置文件的标签属性
        self.file_with_table_title = {0: "1", 1: "2", 2: "3", 3: "4"}

        self.changed_stat = False  # 表格修改状态符
        self.changed_msg = ""  # 保存时的告警消息
        # # 设置自定义的信号和槽
        self.CreateSignalSlot()

    def CreateSignalSlot(self):
        """ 设置信号与槽"""
        self.save_button.clicked.connect(self.save_config)
        self.cancel_button.clicked.connect(self.cancel)
        for model in self.models_dict:  # 遍历监听口模式,打印在不同的模式模块中
            # 检测QTableWidget内容是否发生变化
            self.models_dict[model].itemChanged.connect(self.handle_item_changed)
        for model, add_b in self.add_buttons.items():
            # 把按键对应的模块tablewidget传递进去
            add_b.clicked.connect(lambda checked, table=self.models_dict[model]: self.table_add_row(table))

    def pop_message(self, m_type, message):
        """
        弹窗提示
        :param m_type: 弹窗的类型,[information,warning,question,critical,about]
        :param message: 提示消息内容
        :return:
        """
        if m_type == 'information':
            QMessageBox.information(self, '消息', message, QMessageBox.Ok)
        elif m_type == 'warning':
            QMessageBox.warning(self, '警告', message, QMessageBox.Ok)
        elif m_type == 'question':
            QMessageBox.question(self, '问题', message, QMessageBox.Ok | QMessageBox.No)
        elif m_type == 'critical':
            QMessageBox.critical(self, '错误', message, QMessageBox.Ok)
        elif m_type == 'about':
            QMessageBox.about(self, '关于', message)
        else:
            raise "未识别的提示框类型 " + m_type

    def handle_item_changed(self, item):
        # 槽函数,当单元格内容发生变化时调用
        self.changed_stat = True

        if item.tableWidget() == self.tableWidget_TT:
            self.changed_msg = f"TT模式,在位置({item.row() + 1}, {item.column() + 1})发生变化,保存后退出 或 取消修改"
        elif item.tableWidget() == self.tableWidget_TR:
            self.changed_msg = f"TR单元格内容在位置({item.row() + 1}, {item.column() + 1})发生变化,保存后退出 或 取消修改"
        elif item.tableWidget() == self.tableWidget_TS:
            self.changed_msg = f"TS单元格内容在位置({item.row() + 1}, {item.column() + 1})发生变化,保存后退出 或 取消修改"
        elif item.tableWidget() == self.tableWidget_FT:
            self.changed_msg = f"FT单元格内容在位置({item.row() + 1}, {item.column() + 1})发生变化,保存后退出 或 取消修改"
        elif item.tableWidget() == self.tableWidget_FR:
            self.changed_msg = f"FR单元格内容在位置({item.row() + 1}, {item.column() + 1})发生变化,保存后退出 或 取消修改"
        else:
            print("未添加该表格的提示")
            self.changed_msg = "存在表格修改,保存后退出 或 取消修改"

    def on_checkbox_state_changed(self, table_widget, row: int, state):
        """
        根据table_widget来区分是哪个QTableWidget触发了信号
        :param table_widget: QTableWidget对象
        :param row: 哪一行
        :param state: 勾选的状态
        :return:
        """
        # print(f"TableWidget {table_widget}: Checkbox in row {row} changed state to {Qt.Checked if state == Qt.Checked else Qt.Unchecked}")

        # 检查勾选框的状态
        if state == Qt.Unchecked:
            # 将整行置灰(示例中使用浅灰色)
            for col in range(table_widget.columnCount()):
                if table_widget.cellWidget(row, col) is not None:
                    # 如果单元格中有小部件(如QCheckBox),则可能不需要改变背景
                    continue
                item = table_widget.item(row, col)
                # 禁用编辑
                item.setFlags(item.flags() & ~Qt.ItemIsEditable)
                if item is not None:
                    item.setBackground(Qt.lightGray)

        else:
            # 如果是勾选状态,取消置灰处理
            for col in range(table_widget.columnCount() - 1):
                item = table_widget.item(row, col)
                # 恢复可编辑
                item.setFlags(item.flags() | Qt.ItemIsEditable)
                item.setBackground(Qt.white)

    def init_object(self, config_file, title):
        # 设置该窗口的标题,以及配置文件初始化信息
        self.setWindowTitle(title)
        self.confg_filename = config_file
        self.config_file_path = os.path.join(self._app_path, 'config', config_file)  # 拼接指定的配置文件路径

        print(self._app_path)
        xml_file = self.find_config_file(self._app_path, config_file)  # 查找回来的xml文件路径
        if xml_file is not None:
            self.config_tree = ET.parse(xml_file)  # 解析XML文件
            self.config_root = self.config_tree.getroot()  # 获取XML文档的根元素
            self.filled_content()  # 填充表格内容,之后才初始化下面的状态符
            self.changed_stat = False  # 表格修改状态符
            self.changed_msg = ""  # 保存时的提示信息
        else:
            self.close()  # 关闭窗口

    def find_config_file(self, root_dir, filename, base_filename="config.xml"):
        """
        搜索配置文件路径,如果不存在则用默认配置文件
        :param root_dir: 查找文件的根目录
        :param filename: 要查找的文件名
        :param base_filename: 默认配置文件的文件名
        :return: 配置文件路径,如果不存在则返回None
        """
        config_path = os.path.dirname(self.config_file_path)  # 指定的配置文件的路径
        print(config_path)
        if not os.path.isdir(config_path):
            # 不存在目录则创建
            os.makedirs(config_path, exist_ok=True)  # exist_ok=True表示如果目录已存在,则不会抛出异常
            self.pop_message('critical', f"模板配置文件丢失!请放置配置文件到{config_path, base_filename}")  # 错误,找不到配置文件
            return None
        else:
            if not os.path.isfile(self.config_file_path):
                print(f"找不到指定配置文件{self.config_file_path}")
                self.pop_message('warning', f"指定配置文件未找到{self.config_file_path},读取模板配置")  # 错误,找不到配置文件

                basefile_path = os.path.join(config_path, base_filename)
                if not os.path.isfile(basefile_path):
                    self.pop_message('critical',
                                     f"模板配置文件丢失!请放置配置文件到{basefile_path}")  # 错误,找不到配置文件
                    return None
                else:
                    return basefile_path

            else:
                return self.config_file_path


    def set_cells_attribute(self, table_wigdet):
        """
        设置表格属性
        :param table_wigdet: 表格对象
        :return:
        """
        # 设置表格的列标题,并设置列的模式为"stretch",在这种模式下列直接自适应显示,无法对列的宽度和高度进行设置
        table_wigdet.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        # 解决如果保存ui时页面不在表格页,表头就隐藏
        table_wigdet.horizontalHeader().setVisible(True)
        table_wigdet.verticalHeader().setVisible(True)
        # 设置自定义代理,限制单元格输入内容
        table_wigdet.setItemDelegate(NumberRestrictedDelegate(table_wigdet))

    def filled_content(self):
        """设置单元格居中显示,填充配置文件的内容到UI中"""
        for model in self.models_dict:  # 遍历监听口模式,打印在不同的模式模块中
            model_values = self.config_root.find(f'.//{model}')  # 取配置文件相对应的值
            for row in range(model_values.__len__()):
                # for row in range(models_dict[model].rowCount()):
                for column in range(self.models_dict[model].columnCount()):
                    # 如果配置文件的数据多于UI表格中固定的行数,则要添加一行
                    if row > self.models_dict[model].rowCount() - 1:
                        self.models_dict[model].insertRow(row)
                    if column < self.file_with_table_title.__len__():  # 依据对应字典配置的长度来设置单元格值
                        item = QTableWidgetItem(model_values[row].get(self.file_with_table_title[column]))
                        # 设置单元格属性居中
                        item.setTextAlignment(Qt.AlignCenter)
                        self.models_dict[model].setItem(row, column, item)
                    else:
                        # 设置该列单元格为勾选框
                        # 添加勾选框,并且为每个勾选框连接信号
                        self.setup_checkbox(self.models_dict[model], row, column)

                # 自动调整表格高度
                self.models_dict[model].resizeRowToContents(row)

                self.set_cells_attribute(self.models_dict[model])


    def setup_checkbox(self, table_widget, row, column):
        """
        对表格的单元格添加QCheckBox并连接信号
        :param table_widget: QTableWidget对象
        :param row: 行
        :param column: 列
        :return:
        """
        widget = QWidget()  # 方法内的局部变量,每次调用都是新的副本,所以才能单独让每个tablewidget的勾选框独立连接信号
        widget.checkbox = QCheckBox()  # 将checkbox放在widget中
        widget.checkbox.setCheckState(Qt.Checked)  # 默认全部勾选
        playout = QHBoxLayout(widget)
        playout.addWidget(widget.checkbox)  # 为小部件添加checkbox属性
        playout.setAlignment(Qt.AlignCenter)  # 设置小控件水平居中
        widget.setLayout(playout)  # 在QWidget放置布局

        table_widget.setCellWidget(row, column, widget)
        # 连接勾选框的stateChanged信号,使用lambda来捕获row和table_widget,并只传递状态参数给回调函数
        widget.checkbox.stateChanged.connect(lambda state: self.on_checkbox_state_changed(table_widget, row, state))

    def table_add_row(self, table_widget):
        # 在表格下方新增一行
        current_row = table_widget.rowCount()   # 当前行数
        current_col = table_widget.columnCount()  # 当前列数
        # 插入新行
        table_widget.insertRow(current_row)
        # 添加勾选框,并且为每个勾选框连接信号
        self.setup_checkbox(table_widget, current_row, current_col-1)

        for column in range(current_col-1):
            # 默认新建的单元格内容是空,所以填充item和属性
            item = QTableWidgetItem()
            # 设置单元格属性居中
            item.setTextAlignment(Qt.AlignCenter)
            table_widget.setItem(current_row, column, item)

        # 自动调整行高
        table_widget.resizeRowToContents(current_row)
        self.set_cells_attribute(table_widget)

    def validate_table_rows(self, text_list:list, title:str, row:int):
        """
        校验内容填写完整,不缺少项
        :param text_list: 一行数据,列表格式
        :param title: 告警提示的模块名称
        :param row: 提示第几行数据
        :return: bool
        """
        # 遍历这一行的所有数据
        num = text_list.__len__()  # 有多少数据
        for i in range(num):
            # 记录有值的单元格数
            if text_list[i].strip() != "":
                continue

            else:
                # 该行不满足条件,可以进行相应的处理(例如提示用户)
                self.pop_message("warning", f"{title}模块,第{row}行存在未填写完整内容,如不需要则取消该行勾选状态")

                return False
        return True
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值