PySide2学习记录(二十四):自定义TableModel和Delegate(二)

Python2.7 或 Python3.7
PySide2 Version: 5.11.2
官方文档:http://doc.qt.io/qtforpython/index.html

代码:

from PySide2 import QtWidgets, QtCore, QtGui
import sys

# 自定义Delegate
class MyDelegate(QtWidgets.QStyledItemDelegate):
    def __init__(self, parent=None):
        QtWidgets.QStyledItemDelegate.__init__(self, parent)

    def createEditor(self, parent, option, index):
        editor = QtWidgets.QSpinBox(parent)
        editor.setMinimum(0)
        editor.setMaximum(100)
        return editor

    def setEditorData(self, editor, index):
        value = index.model().data(index)
        editor.setValue(value)

    def setModelData(self, editor, model, index):
        value = editor.value()
        model.setData(index, int(value))

    def updateEditorGeometry(self, editor, option, index):
        editor.setGeometry(option.rect)


# 自定义TableModel
class MyTableModel(QtCore.QAbstractTableModel):
    def __init__(self, parent=None):
        QtCore.QAbstractTableModel.__init__(self, parent)
        self.rows = 4
        self.cols = 3
        self.colhead = [u'第一列', u'第二列', u'第三列']
        self.rowhead = [u'第一行', u'第二行', u'第三行', u'第四行']
        self.d = [[1, 2, 3, 4], [4, 5, 6, 7], [7, 8, 9, 10]]

    # 返回table中有几行
    def rowCount(self, index):
        return self.rows

    # 返回table中有几列
    def columnCount(self, index):
        return self.cols

    # 返回model中的存储的数据,这里就是d中的值
    def data(self, index, role=QtCore.Qt.DisplayRole):
        if not index.isValid():
            return 0
        if role == QtCore.Qt.DisplayRole:
            return self.d[index.column()][index.row()]

    # 设置table头的数据
    def headerData(self, section, orientation, role):
        # 如果是水平方向
        if role == QtCore.Qt.DisplayRole and orientation == QtCore.Qt.Horizontal:
            return self.colhead[section]
        # 如果是垂直方向
        elif role == QtCore.Qt.DisplayRole and orientation == QtCore.Qt.Vertical:
            return self.rowhead[section]
        else:
            return QtCore.QAbstractTableModel.headerData(self, section, orientation, role)

    def setData(self, index, value, role=QtCore.Qt.DisplayRole):
        if role == QtCore.Qt.DisplayRole:
            self.d[index.column()][index.row()] = value

    def flags(self, index):
        flags = QtCore.QAbstractItemModel.flags(self, index)
        flags |= QtCore.Qt.ItemIsEditable
        return flags


app = QtWidgets.QApplication()

# 打印出支持的风格
print(QtWidgets.QStyleFactory.keys())
# 设置整个程序的风格
app.setStyle('Fusion')

window = QtWidgets.QWidget()
window.setFixedSize(500, 400)
layout = QtWidgets.QVBoxLayout(window)

tableview = QtWidgets.QTableView()

# 将第二列都应用自定义的Delegate
tableview.setItemDelegateForColumn(1, MyDelegate())

# 生成自定义的TableModel
model = MyTableModel()

# 加载自定义的TableModel
tableview.setModel(model)
layout.addWidget(tableview)
window.setLayout(layout)
window.show()

sys.exit(app.exec_())

效果图:

PySide2学习记录(二十四):自定义TableModel和Delegate(二)_第1张图片
图1

为了进一步了解delegate和model是怎么交互的,我又写了一个例子。这次并没有自己绘制控件,而是由createEditor函数生成。要实现与数据进行交互,在自定义Delegate中,必须要实现以下几个函数:
createEditor(parent, option, index)
创建一个可以显示数据的编辑器
setEditorData(editor, index)
从Model中取出值给编辑器
setModelData(editor, model, index)
从编辑器中取出值给Model
updateEditorGeometry(editor, option, index)
更新编辑器的位置

要实现可以编辑,还需要在自定义的Model中实现以下两个函数(headerData函数可以不实现),分别如下:
setData(index, value[, role=Qt.EditRole])
用于给model设置数据
flags(index)
返回一个组合标记,包含可编辑标记

从结果可以看出,给第二列设置了自定义的Delegate,所以出现了给TableView提供的QSpinBox,而其它列并没有。

如果想要编辑器脱离TableView,那么在生成QSpinBox对象的时候,不传入parent就可以了。如下图。

图2

你可能感兴趣的:(PySide2学习记录(二十四):自定义TableModel和Delegate(二))