pyqt5 QStandardItemModel 复选框

在pyqt5 中 QStandardItemModel 创建了一个 表格, 想在表格中加入 复选框。 全选多选 那种。 找了好多材料都没有找到 。 有没有同学碰到过这种问题呀。

用代码块功能插入代码,请勿粘贴截图

from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import  sql_mok
import sys

class Table(QWidget):
    def __init__(self,arg = None):
        super(Table, self).__init__(arg)
        self.setWindowTitle("QTableView表格视图控件案例")
        self.resize(500 , 300)


        sql = sql_mok.sql_mokuai()
        sql_jb = sql.huoqucanshu()

        data = sql.sql_select_pl(sql_jb["xsdd"])


        self.model = QStandardItemModel(1,1)

        self.model.setHorizontalHeaderLabels(["id","平台单号","下单日期","客户名称","总金额","手机号","收货人","收货地址","快递单号",""])


        for i,j in enumerate(data):
            # print(j)
            # tup1 = list(j)
            # tup1.append(QCheckBox())
            # j = tup1
            # j =  tuple(j)
            # print(j)

            for h,z in enumerate(j):
                item = QStandardItem(z)
                # print(i, h,z)
                self.model.setItem(i, h, item)


        # self.model.appendRow([item1, item2, item3, item4, item5])

        self.tableView = QTableView()
        self.tableView.setModel(self.model)

        frm = QFrame()
        dlgLayout = QVBoxLayout(frm)
        dlgLayout.addWidget(self.tableView)
        self.setLayout(dlgLayout)



if __name__ == '__main__':

    app = QApplication(sys.argv)
    win = Table()
    win.show()
    sys.exit(app.exec_())

img


#-*- coding: utf-8 -*-
from PySide2.QtUiTools import *
from PySide2.QtWidgets import *
from PySide2.QtGui import *
from PySide2.QtCore import *
import sys

all_header_checkbox =[]

#设置列不可编辑类
class EmptyDelegate(QItemDelegate):
    def __init__(self,parent):
        super(EmptyDelegate, self).__init__(parent)
    def createEditor(self, QWidget, QStyleOptionViewItem, QModelIndex):
        return None
#表格类
class qtableDelete():
    def __init__(self):
        self.ui = QUiLoader().load('ui/qtable_delete.ui')
        self.settable()
        self.ui.delete_2.clicked.connect(self.delete_check)
        
    #设置表格内容
    def settable(self):
        header = CheckBoxHeader()
        self.ui.table.setHorizontalHeader(header) # 设置头复选框
        header.select_all_clicked.connect(header.change_state)  # 行表头复选框单击信号与槽
        self.ui.table.setSelectionBehavior(QAbstractItemView.SelectRows)  # 设置整行选中
        # self.ui.table.setSelectionMode(QAbstractItemView.SingleSelection)#设置选择模式,选择单行
        self.ui.table.setRowCount(15)  # 设置表格行数
        self.ui.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)  # 设置表头自适应
        #设置表格内容和复选框
        for i in range(15):
            checkbox = QCheckBox()
            all_header_checkbox.append(checkbox)
            # checkbox.setCheckState(Qt.Unchecked) #设置复选框为不选状态、Partially(半选)、Checked(全选)
            self.ui.table.setCellWidget(i, 0, checkbox)  # 设置表格可选项
            for j in range(5):
                self.ui.table.setItem(i, j, QTableWidgetItem(f'{i}row,{j}col'))

                self.ui.table.item(i, j).setTextAlignment(Qt.AlignCenter | Qt.AlignVCenter)  # 设置表格内水平垂直居#设置指定列的颜色和下划线
        #设置第4列样式
        for i in range(self.ui.table.rowCount()):
            self.ui.table.item(i, 3).setForeground(QBrush(QColor('Blue'))) #设置颜色
            font = QFont()
            font.setUnderline(True)
            self.ui.table.item(i, 3).setFont(font)#设置下划线

        #设置第1/2/3、5列不可编辑
        list = [1, 2, 0, 4]
        for i in list:
            self.ui.table.setItemDelegateForColumn(i, EmptyDelegate(self.ui))

#删除选中的行数
    def delete_check(self):
        row_box_list = []
        # 获取选中数据
        for i in range(self.ui.table.rowCount()):
            if self.ui.table.cellWidget(i, 0).isChecked() is True:
                row_box_list.append(i)
                row_box_list.reverse()  # 将数据进行降序
        for j in row_box_list:
            self.ui.table.removeRow(j)  # 删除选中行数据
            all_header_checkbox.pop(j)  # 重新构建check box列表

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

    def __init__(self, orientation=Qt.Horizontal, parent=None):
        super(CheckBoxHeader, self).__init__(orientation, parent)
        self.isOn = False

    def paintSection(self, painter, rect, logicalIndex):
        painter.save()
        super(CheckBoxHeader, 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(QStyle.CE_CheckBox, 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
                    # 当用户点击了行表头复选框,发射 自定义信号 select_all_clicked()
                self.select_all_clicked.emit(self.isOn)

                self.updateSection(0)
        super(CheckBoxHeader, self).mousePressEvent(event)

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

if __name__ == '__main__':
    app = QApplication(sys.argv)
    stats = qtableDelete()
    stats.ui.show()
    app.exec_()

【代码仅供参考】
效果图:

img

要自定义modle的,标准的不支持,可以参考下这个,直接运行就能看到效果

import sys
from PyQt5.QtWidgets import (QApplication, QHeaderView, QStyle, QStyleOptionButton, QTableView)
from PyQt5.QtCore import (pyqtSignal, Qt, QAbstractTableModel, QModelIndex, QRect, QVariant)


# https://wiki.qt.io/Technical_FAQ#How_can_I_insert_a_checkbox_into_the_header_of_my_view.3F
# https://stackoverflow.com/questions/30932528/adding-checkbox-as-vertical-header-in-qtableview

class CheckBoxHeader(QHeaderView):
    clicked = pyqtSignal(bool)

    _x_offset = 3
    _y_offset = 0
    _width = 20
    _height = 20

    def __init__(self, orientation=Qt.Horizontal, parent=None):
        super(CheckBoxHeader, self).__init__(orientation, parent)
        self.isOn = False

    def paintSection(self, painter, rect, logicalIndex):
        painter.save()
        super(CheckBoxHeader, 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(QStyle.CE_CheckBox, 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.clicked.emit(self.isOn)
                self.update()
        super(CheckBoxHeader, self).mousePressEvent(event)


class MyModel(QAbstractTableModel):
    def __init__(self, parent=None):
        super(MyModel, self).__init__(parent)
        # Keep track of which object are checked
        self.checkList = ['Checked', 'Unchecked']

    def rowCount(self, QModelIndex):
        return len(self.checkList)

    def columnCount(self, QModelIndex):
        return 2

    def data(self, index, role):
        row = index.row()
        col = index.column()
        if role == Qt.DisplayRole:
            return 'Row %d, Column %d' % (row + 1, col + 1)
        elif role == Qt.CheckStateRole:
            if col == 0:
                return Qt.Checked if self.checkList[row] == 'Checked' else Qt.Unchecked
        elif role == Qt.ToolTipRole:
            if col == 0:
                return self.checkList[row]
        return QVariant()

    def setData(self, index, value, role):
        row = index.row()
        col = index.column()
        if role == Qt.CheckStateRole and col == 0:
            self.checkList[row] = 'Checked' if value == Qt.Checked else 'Unchecked'
        return True

    def flags(self, index):
        if index.column() == 0:
            return Qt.ItemIsEnabled | Qt.ItemIsUserCheckable
        return Qt.ItemIsEnabled

    def headerData(self, section, orientation, role):
        if role == Qt.DisplayRole:
            if orientation == Qt.Horizontal:
                if section == 0:
                    return 'Title 1'
                elif section == 1:
                    return 'Title 2'

    def headerClick(self, isOn):
        self.beginResetModel()
        if isOn:
            self.checkList = ['Checked', 'Checked']
        else:
            self.checkList = ['Unchecked', 'Unchecked']
        self.endResetModel()


if __name__ == '__main__':
    a = QApplication(sys.argv)
    tableView = QTableView()
    myModel = MyModel()
    tableView.setModel(myModel)
    header = CheckBoxHeader()
    tableView.setHorizontalHeader(header)
    #tableView.horizontalHeader().setStretchLastSection(True)
    tableView.horizontalHeader().setStretchLastSection(True)
    tableView.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeToContents)
    header.clicked.connect(myModel.headerClick)
    tableView.resize(400, 200)
    tableView.show()
    a.exec_()


#-*- coding: utf-8 -*-
from PySide2.QtUiTools import *
from PySide2.QtWidgets import *
from PySide2.QtGui import *
from PySide2.QtCore import *
import sys

all_header_checkbox =[]

#设置列不可编辑类
class EmptyDelegate(QItemDelegate):
    def __init__(self,parent):
        super(EmptyDelegate, self).__init__(parent)
    def createEditor(self, QWidget, QStyleOptionViewItem, QModelIndex):
        return None
#表格类
class qtableDelete():
    def __init__(self):
        self.ui = QUiLoader().load('ui/qtable_delete.ui')
        self.settable()
        self.ui.delete_2.clicked.connect(self.delete_check)
        
    #设置表格内容
    def settable(self):
        header = CheckBoxHeader()
        self.ui.table.setHorizontalHeader(header) # 设置头复选框
        header.select_all_clicked.connect(header.change_state)  # 行表头复选框单击信号与槽
        self.ui.table.setSelectionBehavior(QAbstractItemView.SelectRows)  # 设置整行选中
        # self.ui.table.setSelectionMode(QAbstractItemView.SingleSelection)#设置选择模式,选择单行
        self.ui.table.setRowCount(15)  # 设置表格行数
        self.ui.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)  # 设置表头自适应
        #设置表格内容和复选框
        for i in range(15):
            checkbox = QCheckBox()
            all_header_checkbox.append(checkbox)
            # checkbox.setCheckState(Qt.Unchecked) #设置复选框为不选状态、Partially(半选)、Checked(全选)
            self.ui.table.setCellWidget(i, 0, checkbox)  # 设置表格可选项
            for j in range(5):
                self.ui.table.setItem(i, j, QTableWidgetItem(f'{i}row,{j}col'))

                self.ui.table.item(i, j).setTextAlignment(Qt.AlignCenter | Qt.AlignVCenter)  # 设置表格内水平垂直居#设置指定列的颜色和下划线
        #设置第4列样式
        for i in range(self.ui.table.rowCount()):
            self.ui.table.item(i, 3).setForeground(QBrush(QColor('Blue'))) #设置颜色
            font = QFont()
            font.setUnderline(True)
            self.ui.table.item(i, 3).setFont(font)#设置下划线

        #设置第1/2/3、5列不可编辑
        list = [1, 2, 0, 4]
        for i in list:
            self.ui.table.setItemDelegateForColumn(i, EmptyDelegate(self.ui))

#删除选中的行数
    def delete_check(self):
        row_box_list = []
        # 获取选中数据
        for i in range(self.ui.table.rowCount()):
            if self.ui.table.cellWidget(i, 0).isChecked() is True:
                row_box_list.append(i)
                row_box_list.reverse()  # 将数据进行降序
        for j in row_box_list:
            self.ui.table.removeRow(j)  # 删除选中行数据
            all_header_checkbox.pop(j)  # 重新构建check box列表

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

    def __init__(self, orientation=Qt.Horizontal, parent=None):
        super(CheckBoxHeader, self).__init__(orientation, parent)
        self.isOn = False

    def paintSection(self, painter, rect, logicalIndex):
        painter.save()
        super(CheckBoxHeader, 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(QStyle.CE_CheckBox, 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
                    # 当用户点击了行表头复选框,发射 自定义信号 select_all_clicked()
                self.select_all_clicked.emit(self.isOn)

                self.updateSection(0)
        super(CheckBoxHeader, self).mousePressEvent(event)

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

if __name__ == '__main__':
    app = QApplication(sys.argv)
    stats = qtableDelete()
    stats.ui.show()
    app.exec_()


您好,我是有问必答小助手,您的问题已经有小伙伴帮您解答,感谢您对有问必答的支持与关注!
PS:问答VIP年卡 【限时加赠:IT技术图书免费领】,了解详情>>> https://vip.csdn.net/askvip?utm_source=1146287632

参考链接,希望有帮助