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_())

  程序運行界面圖:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM