需求:在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
