Pyqt5——表格中隱藏的控件(Model/View/Delegate)


  需求:在TableView表格中點擊單元格可以實現編輯功能。性別由LineEdite控件編輯,年齡由spinBox控件編輯。

  實現:(1)使用Qt的model-view模式生成表格視圖。

       (2)重寫QAbstractItemDelegate類和類中的paint、createEditor、setEditorData、setModelData函數。

       (3)重寫QAbstractTableModel類。

  

  功能展示:

 

  主要代碼:

   (1)Model部分。此部分完成數據推送和數據編輯功能。

class MyTableModel(QAbstractTableModel):
    """Model"""
    def __init__(self):
        super(MyTableModel, self).__init__()
        self._data = []
        self._background_color = []
        self._headers = ['學號', '姓名', '性別', '年齡']

        self._generate_data()

    def _generate_data(self):
        """填充表格數據"""
        name_list = ['張三', '李四', '王五', '王小二', '李美麗', '王二狗']

        for id_num, name in enumerate(name_list):
            self._data.append([str(id_num), name, '', str(random.randint(20, 25))])

            # :默認單元格顏色為白色
            self._background_color.append([QColor(255, 255, 255) for i in range(4)])

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

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

    def headerData(self, section, orientation, role):
        """設置表格頭"""
        if role == Qt.DisplayRole and orientation == Qt.Horizontal:
            return self._headers[section]

    def data(self, index, role):
        """顯示表格中的數據。"""
        if not index.isValid() or not 0 <= index.row() < self.rowCount():
            return QVariant()

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

        if role == Qt.DisplayRole:
            return self._data[row][col]
        elif role == Qt.BackgroundColorRole:
            return self._background_color[row][col]
        elif role == Qt.TextAlignmentRole:
            return Qt.AlignCenter

        return QVariant()

    def setData(self, index, value, role):
        """編輯單元格中的數據"""
        if not index.isValid() or not 0 <= index.row() < self.rowCount():
            return QVariant()

        if role == Qt.EditRole:
            if index.column() == 2:
                self._data[index.row()][index.column()] = value
                self.layoutChanged.emit()       # 更新數據后要通知表格刷新數據
                return True
            elif index.column() == 3:
                self._data[index.row()][index.column()] = str(value)
                self.layoutChanged.emit()
                return True
            else:
                return False

    def flags(self, index):
        """設置單元格的屬性。"""
        if index.column() == 0 or index.column() == 1:
            # :我們設置第0、1列不可編輯,其他列可以編輯。
            return super().flags(index)

        return Qt.ItemIsEditable | super().flags(index)

  (2)Delegate部分。此部分完成View中數據的展示,以及單元格中編輯器的生成、編輯器內容的推送和編輯器內容更新到Model。

class MyDelegate(QAbstractItemDelegate):
    """Delegate"""
    def __init__(self):
        super(MyDelegate, self).__init__()

    def paint(self, painter, option, index):
        """繪制單元格。"""
        if index.column() == 0:
            # :表格第一列是ID,單元格中繪制一個圖片和ID。
            p = QStyleOptionViewItem()
            p.index = index
            p.rect = option.rect
            p.features = QStyleOptionViewItem.HasDecoration | QStyleOptionViewItem.HasDisplay
            p.text = str(index.data())
            p.decorationSize = QSize(44, 44)      # 設置裝飾圖標的大小。
            p.icon = QIcon('../image/id.png')     # 設置裝飾圖標路徑名
            p.state = option.state
            p.showDecorationSelected = True     # 開啟選中時,單元格高亮顯示
            # :若項目被選擇,則高亮繪制其矩形

            p.decorationPosition = QStyleOptionViewItem.Left        # 圖片在文字的左邊
            p.displayAlignment = Qt.AlignLeft | Qt.AlignCenter      # 設置文字的位置
            QApplication.style().drawControl(QStyle.CE_ItemViewItem, p, painter)
        else:
            # :向表格中渲染數據,如果缺少下面代碼,表格中數據不能正常顯示。
            # :這里應該在model的data函數之后調用,此時通過index可以獲取要顯示。
            # :的數據。
            p = QStyleOptionViewItem()
            p.features = QStyleOptionViewItem.HasDisplay
            p.index = index                     # 表格QModelIndex索引
            p.rect = option.rect
            p.state = option.state

            p.showDecorationSelected = True     # 開啟選中時,單元格高亮顯示
            p.text = str(index.data())          # 表格中的數據
            QApplication.style().drawControl(QStyle.CE_ItemViewItem, p, painter)

    def createEditor(self, parent, option, index):
        """給單元格創建編輯器(點擊單元格的時候調用)"""
        if index.column() == 2:
            # :第2列性別設置為lineEdite編輯器。
            # :注意,在創建編輯控件的時候傳入parent防止在編輯時新彈出窗口來進行編輯。
            p = QLineEdit(parent)
            p.setFocusPolicy(Qt.TabFocus)
            # :設置控件的位置,如果忽略此句,控件會出現在窗體的左上角。
            p.setGeometry(option.rect)
            return p
        elif index.column() == 3:
            # :第3列年齡設置為spinBox編輯器。
            p = QSpinBox(parent)
            p.setMaximum(150)       # 年齡最大值為150
            p.setGeometry(option.rect)
            return p
        else:
            return super().createEditor(parent, option, index)

    def setEditorData(self, editor, index):
        """把model中的數據填充到編輯器當中(點擊單元格的時候調用但晚於createEditor)"""
        if index.column() == 2:
            # :lineEdit編輯器。
            editor.setText(index.data())
        elif index.column() == 3:
            editor.setValue(int(index.data()))
        else:
            super().setEditorData(editor, index)

    def setModelData(self, editor, model, index):
        """把編輯器中的數據更新到model當中(編輯完成時調用)"""
        if index.column() == 2:
            model.setData(index, editor.text(), role=Qt.EditRole)
        elif index.column() == 3:
            model.setData(index, editor.value(), role=Qt.EditRole)
        else:
            super().setModelData(editor, model, index)

 

  Demo源碼:

  Demo源碼參考網址(碼雲):https://gitee.com/cui_zhen/pyqt5-example

 


免責聲明!

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



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