自定义TableWidget,表头放置全选按钮

实现方式:自定义一个CheckBox样式的QHeaderView,并将它设置为TableWidget的表头, 绑定clicked函数;将TableWidget每一行的第一列设为CheckBox,绑定clicked函数;自定义中间对齐及是否可编辑的Delegate;

 

TableWidget运行代码:

# coding=utf-8
# python3
"""
@FileName:结合TableWidget的自定义全选表头.py
@Author: XiaoFang
@CreateFileTime: 2024/6/27 18:53
@Description: pyqt
"""

from PyQt5.QtWidgets import (QApplication, QTableWidget, QTableWidgetItem, QWidget, QVBoxLayout, QStyle, QLabel,
                             QStyledItemDelegate, QLineEdit)
from PyQt5.QtCore import Qt

from ButtonWidget import ButtonWidget
from ButtonHeader import ButtonHeader


class CenterAlignedDelegate(QStyledItemDelegate):
    _edit_column = [4]

    def initStyleOption(self, option, index):
        super().initStyleOption(option, index)
        option.displayAlignment = Qt.AlignCenter

    def createEditor(self, parent, option, index):
        if index.column() in self._edit_column:  # tableWidget部分可编辑 只允许第四列可编辑
            editor = QLineEdit(parent)
            editor.setAlignment(Qt.AlignCenter)
            return editor
        return None  # 返回 None 来禁止编辑


class MyWidget(QWidget):
    def __init__(self):
        super().__init__()
        self.resize(500, 300)
        self.init_ui()

    def init_ui(self):
        layout = QVBoxLayout(self)
        layout.setSpacing(10)  # 设置布局间距
        self.table_widget = QTableWidget(4, 5)
        layout.addWidget(self.table_widget)

        self.show_label = QLabel(self)
        layout.addWidget(self.show_label)

        self.check_header = ButtonHeader(_style=QStyle.CE_CheckBox, isOn=False)  # 实例化自定义表头
        self.table_widget.setHorizontalHeader(self.check_header)  # 设置表头段
        self.check_header.select_all_clicked.connect(self.select_all_items)  # 行表头复选框单击信号与槽

        delegate = CenterAlignedDelegate()  # 自定义中间对齐及是否可编辑
        self.table_widget.setItemDelegate(delegate)

        self.table_widget.setHorizontalHeaderLabels(['', '姓名', '性别', '体重', '年龄'])  # 设置表头内容
        self.table_widget.horizontalHeader().setVisible(True)  # 显示水平表头
        self.table_widget.verticalHeader().setVisible(False)  # 隐藏垂直表头
        self.table_widget.setColumnWidth(0, 35)
        self.table_widget.setColumnWidth(1, 60)
        self.table_widget.setColumnWidth(2, 60)
        self.table_widget.setColumnWidth(3, 60)
        datas = [
            ['张三', '男', 60, 20],
            ['李四', '男', 70, 30],
            ['王五', '女', 80, 40],
            ['赵六', '女', 90, 50],]

        for idx, item_infor in enumerate(datas):
            print(item_infor)
            _widget = ButtonWidget(_type='checkbox')  # 实例化复选框控件
            button = _widget.get_button()
            self.check_header.all_header_combobox.append(button)
            button.clicked.connect(lambda: self.select_items(0))
            self.table_widget.setCellWidget(idx, 0, _widget)
            self.table_widget.setItem(idx, 1, QTableWidgetItem(item_infor[0]))
            self.table_widget.setItem(idx, 2, QTableWidgetItem(item_infor[1]))
            self.table_widget.setItem(idx, 3, QTableWidgetItem(str(item_infor[2])))
            self.table_widget.setItem(idx, 4, QTableWidgetItem(str(item_infor[3])))

    def select_all_items(self, state):
        self.check_header.change_state(state)
        self.select_items(1)

    def select_items(self, select_all_flag, *args):
        names = []
        for index, item in enumerate(self.check_header.all_header_combobox):
            if item.checkState() == Qt.Checked:
                names.append(self.table_widget.item(index, 1).text())
        if not select_all_flag:
            if all(item.checkState() == Qt.Checked for item in self.check_header.all_header_combobox):
                self.check_header.all_change_state(True)
            if all(item.checkState() == Qt.Unchecked for item in self.check_header.all_header_combobox):
                self.check_header.all_change_state(False)
        self.show_label.setText(','.join(names))


if __name__ == '__main__':
    app = QApplication([])
    window = MyWidget()
    window.show()
    app.exec_()
自定义QHeaderView控件,ButtonHeader代码:
# coding=utf-8
# python3
"""
@FileName:ButtonHeader.py
@Author: XiaoFang
@CreateFileTime: 2024/6/27 18:27
@Description: 自定义表头QHeaderView
"""

from PyQt5.QtWidgets import QHeaderView, QStyleOptionButton, QStyle
from PyQt5.QtCore import pyqtSignal, QRect, Qt


class ButtonHeader(QHeaderView):
    """自定义表头类
    QStyle.CE_CheckBox: CheckBox
    QStyle.CE_RadioButton: RadioButton
    ...

    self.check_header = ButtonHeader(_style=QStyle.CE_CheckBox, isOn=False)  # 实例化自定义表头
    self.EventsTableWidget.setHorizontalHeader(self.check_header)  # 设置表头段
    self.check_header.select_all_clicked.connect(self.select_all_items)  # 行表头复选框单击信号与槽
    self.EventsTableWidget.setHorizontalHeaderLabels(['', '1', '2'])

    """

    # 自定义 复选框全选信号
    select_all_clicked = pyqtSignal(bool)
    # 这4个变量控制列头复选框的样式,位置以及大小
    _x_offset = 7
    _y_offset = 0
    _width = 20
    _height = 20

    def __init__(self, _style=QStyle.CE_CheckBox, orientation=Qt.Horizontal, parent=None, isOn=False):
        super(ButtonHeader, self).__init__(orientation, parent)
        self.all_header_combobox = []
        self.isOn = isOn
        self._style = _style

    def paintSection(self, painter, rect, logicalIndex):
        painter.save()
        super(ButtonHeader, self).paintSection(painter, rect, logicalIndex)
        painter.restore()
        self._y_offset = int((rect.height() - self._width) / 2.)
        if logicalIndex == 0:
            option = QStyleOptionButton()
            option.rect = QRect(rect.x() + self._x_offset, rect.y() + self._y_offset, self._width, self._height)
            option.state = QStyle.State_Enabled | QStyle.State_Active
            if self.isOn:
                option.state |= QStyle.State_On
            else:
                option.state |= QStyle.State_Off
            self.style().drawControl(self._style, option, painter)

    def mousePressEvent(self, event):
        index = self.logicalIndexAt(event.pos())
        if 0 == index:
            x = self.sectionPosition(index)
            if x + self._x_offset < event.pos().x() < x + self._x_offset + self._width and self._y_offset < event.pos().y() < self._y_offset + self._height:
                if self.isOn:
                    self.isOn = False
                else:
                    self.isOn = True
                self.select_all_clicked.emit(self.isOn)  # 当用户点击了行表头复选框,发射 自定义信号 select_all_clicked()
                self.updateSection(0)
        super(ButtonHeader, self).mousePressEvent(event)

    # 自定义信号 select_all_clicked 的槽方法
    def change_state(self, isOn):
        if isOn:
            # 将所有的复选框都设为勾选状态
            for i in self.all_header_combobox:
                i.setCheckState(Qt.Checked)
        else:
            for i in self.all_header_combobox:
                i.setCheckState(Qt.Unchecked)

    # 改变行表头复选框状态(不会触发勾选事件)
    def all_change_state(self, isOn):
        self.isOn = isOn
        self.updateSection(0)

自定义widget控件,ButtonWidgetd代码:

# coding=utf-8
# python3
"""
@FileName:自定义按钮widget类.py
@Author: XiaoFang
@CreateFileTime: 2024/6/27 18:10
@Description: pyqt==5.15.7
"""

from PyQt5.QtWidgets import QWidget, QCheckBox, QHBoxLayout, QRadioButton, QPushButton
from PyQt5.QtCore import Qt, QSize
from PyQt5.QtGui import QPixmap, QIcon


class ButtonWidget(QWidget):
    def __init__(self, parent=None, _type='pushbutton', size=(20, 20), icon_picture=None, icon_size=(18, 18)):
        super(ButtonWidget, self).__init__(parent)
        self.setAutoFillBackground(True)
        if _type == 'checkbox':
            self._button = QCheckBox()
        elif _type == 'radiobutton':
            self._button = QRadioButton()
        elif _type == 'pushbutton':
            self._button = QPushButton()
        self._button.setMinimumSize(*size)
        self._button.setMaximumSize(*size)
        self._button.setChecked(False)
        button_layout = QHBoxLayout()
        button_layout.addWidget(self._button, alignment=Qt.AlignCenter)
        button_layout.setContentsMargins(0, 0, 0, 0)
        button_layout.setSpacing(0)
        button_layout.setAlignment(Qt.AlignCenter)
        self.setLayout(button_layout)

        if icon_picture is not None:
            self._button.setIconSize(QSize(*icon_size))
            self._button.setStyleSheet("QPushButton {border:0px; background-color:none;}\n"
                                       "QPushButton:hover {background-color:rgb(200,100,100);}")
            icon = QIcon()
            icon.addPixmap(QPixmap(icon_picture), QIcon.Normal, QIcon.Off)
            self._button.setIcon(icon)

    def set_size(self, size):
        self._button.setMinimumSize(*size)
        self._button.setMaximumSize(*size)

    def get_button(self):
        return self._button

 

运行效果:

3b7664d154fa4983a8b1b5c36f4438c1.png

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值