PyQt6对QTableWidget表格控件

TableWidget和TableView区别:

PyQt6提供了两种表格控件,分别是TableWidget和TableView,其中,TableView是基于模型的,它是TableWidget的父类,使用TableView时,首先需要建立模型,然后再保存数据;而TableWidget是TableView的升级版本,它已经内置了一个数据存储模型QTableWidgetItem,我们在使用时,不必自己建立模型,而直接使用setItem()方法即可添加数据。所以在实际开发时,推荐使用TableWidget控件作为表格。

一、要实现列表先附效果:

拖拽Table widget参数名为 tableWidget

小案例代码:

from PySide6.QtWidgets import (QApplication, QTableWidget,QTableWidgetItem,QAbstractItemView,QHeaderView)
from PySide6.QtUiTools import QUiLoader
import sys

class Window:
    def __init__(self):
        # 加载 UI 文件
        self.ui = QUiLoader().load('ui/dy.ui')
        self.ui.setWindowTitle('测试')

        # 获取 QTableWidget
        table: QTableWidget = self.ui.tableWidget
        table.setRowCount(2)
        table.setColumnCount(6)
        table.setHorizontalHeaderLabels(['编号', '书名', '类别', '作者', '出版日期', '价格'])
        table.setItem(0, 0, QTableWidgetItem('1'))
        table.setItem(0, 1, QTableWidgetItem('Python程序设计'))
        table.setItem(0, 2, QTableWidgetItem('计算机'))
        table.setItem(0, 3, QTableWidgetItem('张三'))
        table.setItem(0, 4, QTableWidgetItem('2021-10-10'))
        table.setItem(0, 5, QTableWidgetItem('20.00'))

        table.setItem(1, 0, QTableWidgetItem('2'))
        table.setItem(1, 1, QTableWidgetItem('Python程序设计'))
        table.setItem(1, 2, QTableWidgetItem('计算机'))
        table.setItem(1, 3, QTableWidgetItem('张三'))
        table.setItem(1, 4, QTableWidgetItem('2021-10-10'))
        table.setItem(1, 5, QTableWidgetItem('20.00'))

        # table.resizeColumnsToContents()  # 设置列宽跟随内容改变
        table.verticalHeader().setVisible(False)  # 隐藏垂直标题 序号
        # 设置最后一列自动填充容器
        # table.horizontalHeader().setStretchLastSection(True)

        # 设置列宽模式:所有列均匀拉伸填满表格
        table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        # 禁止编辑单元格
        table.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)




# ---------------------
# 程序入口
# ---------------------
if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = Window()
    window.ui.show()
    sys.exit(app.exec())

二、要实现列表全选和取消全选先附效果:

新增全选按钮,名称为:selectAllButton

小案例代码:

from PySide6.QtWidgets import (QApplication,
                               QTableWidget,
                               QTableWidgetItem,
                               QAbstractItemView,
                               QHeaderView,
                               QCheckBox,
                               QWidget,
                               QHBoxLayout)
from PySide6.QtUiTools import QUiLoader
from PySide6.QtCore import Qt
import sys

class Window:
    def __init__(self):
        # 加载 UI 文件
        self.ui = QUiLoader().load('ui/dy.ui')
        self.ui.setWindowTitle('测试')
        self.ui.executeButton.clicked.connect(self.executeButton)
        # 连接按钮点击事件
        self.ui.selectAllButton.clicked.connect(self.toggle_select_all)

        # 获取 QTableWidget
        table: QTableWidget = self.ui.tableWidget
        table.setRowCount(2)
        table.setColumnCount(6)
        table.setHorizontalHeaderLabels(['', '书名', '类别', '作者', '出版日期', '价格'])
        # table.resizeColumnsToContents()  # 设置列宽跟随内容改变
        table.verticalHeader().setVisible(False)  # 隐藏垂直标题 序号
        # 设置最后一列自动填充容器
        # table.horizontalHeader().setStretchLastSection(True)

        # 设置列宽模式:所有列均匀拉伸填满表格
        table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        # 禁止编辑单元格
        table.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)

        # 存储复选框对象(可选:用于后续操作)
        self.checkboxes = []

        # 为每一行创建带复选框的单元格
        for row in range(2):
            # 创建复选框并居中
            checkbox = QCheckBox()
            checkbox.setChecked(True)  # 默认选中,可按需设置
            checkbox.stateChanged.connect(lambda state, r=row: self.on_checkbox_state_changed(r, state))

            # 创建一个居中的 widget 容器
            container = QWidget()
            layout = QHBoxLayout(container)
            layout.addWidget(checkbox)
            layout.setAlignment(Qt.AlignCenter)
            layout.setContentsMargins(0, 0, 0, 0)

            # 将容器设为单元格 widget
            table.setCellWidget(row, 0, container)

            # 保存复选框引用(可选)
            self.checkboxes.append(checkbox)

            # 其他列填充数据(从第1列开始)
            table.setItem(row, 1, QTableWidgetItem('Python程序设计'))
            table.setItem(row, 2, QTableWidgetItem('计算机'))
            table.setItem(row, 3, QTableWidgetItem('张三'))
            table.setItem(row, 4, QTableWidgetItem('2021-10-10'))
            table.setItem(row, 5, QTableWidgetItem('20.00'))
    def toggle_select_all(self):
        """全选 / 取消全选"""
        # 判断当前状态:是否全部已选中
        all_selected = all(cb.isChecked() for cb in self.checkboxes)

        # 如果当前是全选状态,则取消全选;否则全选
        new_state = False if all_selected else True

        for cb in self.checkboxes:
            cb.setChecked(new_state)

        self.update_select_all_button_text()
        print("批量操作:", "全选" if new_state else "取消全选")

    def update_select_all_button_text(self):
        """更新按钮文字"""
        all_selected = all(cb.isChecked() for cb in self.checkboxes)
        text = "取消全选" if all_selected else "全选"
        self.ui.selectAllButton.setText(text)

    def on_checkbox_state_changed(self, row, state):
        """行复选框状态改变"""
        if state == Qt.Checked:
            print(f"第 {row + 1} 行被选中")
        else:
            print(f"第 {row + 1} 行被取消选中")


    def get_selected_rows(self):
        """获取选中的行"""
        return [i for i, cb in enumerate(self.checkboxes) if cb.isChecked()]

    def executeButton(self):
        """示例:执行按钮点击"""
        selected = self.get_selected_rows()
        print("当前选中的行:", selected)



# ---------------------
# 程序入口
# ---------------------
if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = Window()
    window.ui.show()
    sys.exit(app.exec())

二、要实现列表全选选中Excel导出功能先附效果:

新增全选按钮,名称为:exportButton

小案例代码:

from PySide6.QtWidgets import (QApplication,
                               QTableWidget,
                               QTableWidgetItem,
                               QAbstractItemView,
                               QHeaderView,
                               QCheckBox,
                               QWidget,
                               QHBoxLayout)
from PySide6.QtUiTools import QUiLoader
from PySide6.QtWidgets import QFileDialog  # 添加导入
import openpyxl
from openpyxl.styles import Alignment, Font
from PySide6.QtCore import Qt
import sys

class Window:
    def __init__(self):
        # 加载 UI 文件
        self.ui = QUiLoader().load('ui/dy.ui')
        self.ui.setWindowTitle('测试')
        # Excel 导出按钮
        self.ui.exportButton.clicked.connect(self.exportButton)
        # 全选 / 取消全选按钮
        self.ui.selectAllButton.clicked.connect(self.toggle_select_all)

        # 获取 QTableWidget
        table: QTableWidget = self.ui.tableWidget
        table.setRowCount(2)
        table.setColumnCount(6)
        table.setHorizontalHeaderLabels(['', '书名', '类别', '作者', '出版日期', '价格'])
        # table.resizeColumnsToContents()  # 设置列宽跟随内容改变
        table.verticalHeader().setVisible(False)  # 隐藏垂直标题 序号
        # 设置最后一列自动填充容器
        # table.horizontalHeader().setStretchLastSection(True)

        # 设置列宽模式:所有列均匀拉伸填满表格
        # table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)

        # 设置列宽策略
        table.horizontalHeader().setSectionResizeMode(0, QHeaderView.Fixed)
        table.horizontalHeader().resizeSection(0, 70)  # 复选框列宽度

        # 其他列等比例拉伸
        for col in range(1, 6):
            table.horizontalHeader().setSectionResizeMode(col, QHeaderView.Stretch)

        # table.resizeColumnsToContents()  # 设置列宽跟随内容改变
        # 禁止编辑单元格
        table.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)

        # 存储复选框对象(可选:用于后续操作)
        self.checkboxes = []

        # 为每一行创建带复选框的单元格
        for row in range(2):
            # 创建复选框并居中
            checkbox = QCheckBox()
            checkbox.setChecked(False)  # 默认未选中,可按需设置
            checkbox.stateChanged.connect(lambda state, r=row: self.on_checkbox_state_changed(r, state))

            # 创建一个居中的 widget 容器
            container = QWidget()
            layout = QHBoxLayout(container)
            layout.addWidget(checkbox)
            layout.setAlignment(Qt.AlignCenter)
            layout.setContentsMargins(0, 0, 0, 0)

            # 将容器设为单元格 widget
            table.setCellWidget(row, 0, container)

            # 保存复选框引用(可选)
            self.checkboxes.append(checkbox)

            # 其他列填充数据(从第1列开始)
            table.setItem(row, 1, QTableWidgetItem('Python程序设计'))
            table.setItem(row, 2, QTableWidgetItem('计算机'))
            table.setItem(row, 3, QTableWidgetItem('张三'))
            table.setItem(row, 4, QTableWidgetItem('2021-10-10'))
            table.setItem(row, 5, QTableWidgetItem('20.00'))
    def toggle_select_all(self):
        """全选 / 取消全选"""
        # 判断当前状态:是否全部已选中
        all_selected = all(cb.isChecked() for cb in self.checkboxes)

        # 如果当前是全选状态,则取消全选;否则全选
        new_state = False if all_selected else True

        for cb in self.checkboxes:
            cb.setChecked(new_state)

        self.update_select_all_button_text()
        print("批量操作:", "全选" if new_state else "取消全选")

    def update_select_all_button_text(self):
        """更新按钮文字"""
        all_selected = all(cb.isChecked() for cb in self.checkboxes)
        text = "取消全选" if all_selected else "全选"
        self.ui.selectAllButton.setText(text)

    def on_checkbox_state_changed(self, row, state):
        """行复选框状态改变"""
        if state == Qt.Checked:
            print(f"第 {row + 1} 行被选中")
        else:
            print(f"第 {row + 1} 行被取消选中")


    def get_selected_rows(self):
        """获取选中的行"""
        return [i for i, cb in enumerate(self.checkboxes) if cb.isChecked()]

    def exportButton(self):
        """导出选中的行到 Excel 文件"""
        selected_rows = self.get_selected_rows()
        if not selected_rows:
            print("没有选中任何行,无需导出。")
            return

        # 弹出保存文件对话框
        file_path, _ = QFileDialog.getSaveFileName(
            self.ui,
            "保存 Excel 文件",
            "导出数据.xlsx",  # 默认文件名
            "Excel 文件 (*.xlsx)"
        )

        if not file_path:
            return  # 用户取消

        # 获取表头
        headers = ['序号', '书名', '类别', '作者', '出版日期', '价格']

        # 准备数据(带上序号)
        data = []
        for idx, row in enumerate(selected_rows, start=1):
            row_data = [
                idx,
                self.ui.tableWidget.item(row, 1).text(),
                self.ui.tableWidget.item(row, 2).text(),
                self.ui.tableWidget.item(row, 3).text(),
                self.ui.tableWidget.item(row, 4).text(),
                self.ui.tableWidget.item(row, 5).text()
            ]
            data.append(row_data)

        # 创建 Excel 工作簿
        wb = openpyxl.Workbook()
        ws = wb.active
        ws.title = "导出数据"

        # 写入表头
        ws.append(headers)
        # 设置表头样式
        header_font = Font(bold=True)
        alignment = Alignment(horizontal='center', vertical='center')
        for cell in ws[1]:
            cell.font = header_font
            cell.alignment = alignment

        # 写入数据
        for row_data in data:
            ws.append(row_data)

        # 设置所有单元格居中
        for row in ws.iter_rows(min_row=1, max_row=ws.max_row, max_col=6):
            for cell in row:
                cell.alignment = alignment

        # 自动调整列宽
        column_widths = [5, 15, 10, 10, 12, 8]  # 序号、书名、类别、作者、日期、价格
        for i, width in enumerate(column_widths, start=1):
            ws.column_dimensions[openpyxl.utils.get_column_letter(i)].width = width

        # 保存文件
        try:
            wb.save(file_path)
            print(f"✅ 数据已成功导出到:{file_path}")
        except Exception as e:
            print(f"❌ 导出失败:{e}")



# ---------------------
# 程序入口
# ---------------------
if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = Window()
    window.ui.show()
    sys.exit(app.exec())

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值