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_())
效果图:
为了进一步了解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就可以了。如下图。