PyQt5之 QTableView 添加复选框(自定义委托)

import sys

from untitled import Ui_Form
from PyQt5.QtWidgets import QApplication, QWidget, QStyleOptionButton, QAbstractItemDelegate, QStyle, QCheckBox, QStyledItemDelegate, QStyleOptionViewItem, QItemDelegate
from PyQt5.QtCore import Qt, QAbstractTableModel, QModelIndex, QVariant, QThread, pyqtSignal, QEvent, QRect
from PyQt5.QtGui import QColor, QMouseEvent


class WorkThread(QThread):
    scrollBottomSignal = pyqtSignal()
    addDataSignal = pyqtSignal()

    def __init__(self, model):
        super(WorkThread, self).__init__()
        self.model = model
        self.run_flag = True

    def run(self):
        while self.run_flag:
            self.addDataSignal.emit()
            self.scrollBottomSignal.emit()
            self.usleep(1)      # 不加延迟界面会卡顿。

    def stop(self):
        self.run_flag = False


class MyTableModel(QAbstractTableModel):
    def __init__(self):
        super(MyTableModel, self).__init__()
        self._data = []     # 要显示的数据
        self._headers = ['选项', '姓名', '年龄', '性别']    # 表头

    def rowCount(self, parent=QModelIndex()):
        """
        返回行数量。
        """
        return len(self._data)

    def columnCount(self, parent=QModelIndex()):
        """
        返回列数量。
        """
        return len(self._headers)

    def insertRows(self, row, count, parent):
        """
        插入行。
        :param row: 插入起始行。
        :param count: 插入行数量。
        :param parent:
        :return:
        """
        self.beginInsertRows(QModelIndex(), row, row + count - 1)
        for i in range(count):
            self._data.insert(row, [Qt.Checked, 'CZ', '25', '男'])
        self.endInsertRows()
        return True

    def removeRows(self, row, count, parent):
        self.beginRemoveRows(QModelIndex(), 0, row + count - 1)
        for i in range(count):
            self._data.pop(row + count - 1 - i)     # 倒着删
        self.endRemoveRows()

    def clearView(self):
        self.removeRows(0, self.rowCount(), QModelIndex())

    def addData(self):
        self.insertRows(self.rowCount(), 1, QModelIndex())

    def headerData(self, section, orientation, role):
        """
        设置表头。
        """
        if role == Qt.DisplayRole and orientation == Qt.Horizontal:  # 限定只更改行表头
            return self._headers[section]

    def data(self, index, role=Qt.DisplayRole):
        if not index.isValid() or not 0 <= index.row() < self.rowCount():
            return QVariant()

        row = index.row()
        col = index.column()

        if role == Qt.DisplayRole:
            if col != 0:
                return str(self._data[row][col])  # 数据
        elif role == Qt.TextColorRole:
            return QColor(Qt.red)
        elif Qt.UserRole:
            if col == 0:
                return self._data[row][col]

        return QVariant()

    def setData(self, index, value, role):
        if not index.isValid() or not 0 <= index.row() < self.rowCount():
            return False
        col = index.column()
        row = index.row()

        if role == Qt.UserRole or role == Qt.CheckStateRole:
            if col == 0:
                self._data[row][col] = value
                self.layoutChanged.emit()
                return True

        return False

    def flags(self, index):
        flags = Qt.ItemFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
        return flags


class MyDelegate(QStyledItemDelegate):
    def __init__(self):
        super(MyDelegate, self).__init__()

    def paint(self, painter, option, index):
        if index.column() == 0:
            data = index.model().data(index, Qt.UserRole)

            ckbtn = QStyleOptionButton()
            ckbtn.state = QStyle.State_On if data == Qt.Checked else QStyle.State_Off
            ckbtn.state |= QStyle.State_Enabled
            ckbtn.rect = option.rect

            QApplication.style().drawControl(QStyle.CE_CheckBox, ckbtn, painter)
        else:
            QStyledItemDelegate.paint(self, painter, option, index)

    def editorEvent(self, event, model, option, index):
        if event.type() == QEvent.KeyPress:
            return False
        if event.type() == QEvent.MouseButtonRelease:
            event = QMouseEvent(event)      # 类型强转
            if event.button() == Qt.LeftButton:
                value = index.data(Qt.UserRole)

                if value == Qt.Checked:
                    rev_value = Qt.Unchecked
                else:
                    rev_value = Qt.Checked

                return model.setData(index, rev_value, Qt.UserRole)
            else:
                return False
        else:
            return False


class MainUI(QWidget, Ui_Form):
    def __init__(self):
        super(MainUI, self).__init__()
        self.setupUi(self)
        self.workThread = None

        self.pushButton.clicked.connect(self.buttonClickedStart)
        self.pushButton_2.clicked.connect(self.buttonClickedStop)
        self.pushButton_3.clicked.connect(self.buttonClickedClear)

        self.model = MyTableModel()
        self.myDelegate = MyDelegate()
        self.tableView.setItemDelegate(self.myDelegate)
        self.tableView.setModel(self.model)

        self.tableView.show()

    def buttonClickedStart(self):
        """开启线程,向表中插入数据。"""
        self.workThread = WorkThread(self.model)
        self.workThread.addDataSignal.connect(self.model.addData)
        self.workThread.scrollBottomSignal.connect(self.scrollBottom)
        self.workThread.start()

    def buttonClickedStop(self):
        """停止线程向表中插入数据。"""
        self.workThread.stop()

    def buttonClickedClear(self):
        """清空表。"""
        self.model.clearView()

    def scrollBottom(self):
        """右侧滑动条保持在最下面。"""
        self.tableView.scrollToBottom()


if __name__ == '__main__':
    app = QApplication(sys.argv)

    ui = MainUI()
    ui.show()
    sys.exit(app.exec_())

  程序运行界面图:

 

posted @ 2020-08-26 19:54  小圳  阅读(3739)  评论(0编辑  收藏  举报