目录
简述
己见,model穿了一件view的外衣,但觉得差点什么,就找QStyledItemDelegate裁缝来加工改造。成果怎样,则需要通过使用(即编辑单元格,可能是QSpinBox或QComboBox...等等)来知晓。
自定义的QStyledItemDelegate
class StuDelegate(QStyledItemDelegate): # 自定义的QStyledItemDelegate
def __init__(self, parent=None):
super().__init__(parent)
self.x_and_y = None # 点击的(x, y)坐标
# 创建编辑
def createEditor(self, parent: QWidget, option: QStyleOptionViewItem, index: QModelIndex) ->None:
return None # 此时不要创建编辑渲染
# 绘制
def paint(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex) -> None:
# 此处option.rect 就是 index中(n , 3)项的图形(n为数据行)
edit_btn = self.get_btn('编辑', option.rect.left(), option.rect.top(), option.rect.width() / 2, option.rect.height())
delete_btn = self.get_btn('删除', option.rect.left() + option.rect.width() / 2, option.rect.top(), option.rect.width() / 2, option.rect.height())
# 按钮创建
QPushButton().style().drawControl(QStyle.ControlElement.CE_PushButton, edit_btn, painter)
QPushButton().style().drawControl(QStyle.ControlElement.CE_PushButton, delete_btn, painter)
# 自定义按钮的创建
def get_btn(self, txt, x, y, width, height) -> QStyleOptionButton:
btn = QStyleOptionButton() # 样式按钮
btn.rect = QRect(x, y, width, height) # 设置矩形
btn.text = txt # 设置文本
if self.x_and_y and btn.rect.contains(self.x_and_y): # 当存在点击并且在矩形按钮范围内部
btn.state = QStyle.StateFlag.State_Active | QStyle.StateFlag.State_Sunken # 样式的状态效果
else:
btn.state = QStyle.StateFlag.State_Enabled | QStyle.StateFlag.State_Raised
return btn
# 编辑事件
def editorEvent(self, event: QEvent, model: QStandardItemModel, option: QStyleOptionViewItem, index: QModelIndex) -> bool:
if event.type() == QEvent.Type.MouseButtonPress: # 按下事件
self.x_and_y = event.position().toPoint() # QPointF 转成 QPoint
if option.rect.top() < self.x_and_y.y() < option.rect.bottom():
if self.x_and_y.x() < int(option.rect.left() + option.rect.right()) / 2: # 中间点判断
QMessageBox.information(None, '提示', '这是编辑') # 消息提示框
else:
QMessageBox.information(None, '提示', '这是删除')
elif event.type() == QEvent.Type.MouseButtonRelease: # 释放事件
self.x_and_y = None
return True
绘制按钮的方式有很多,以下就是2种(此处使用drawControl): QStyle.drawPrimitive(pe, opt, p[, widget=None]) QStyle.drawControl(element, opt, p[, widget=None])--通过提供的painter和option来绘制指定的element。
主窗体
class StuWin(QWidget):
def __init__(self):
super().__init__()
self.stu_lis = [['学习a', 16, '男'], ['学习b', 17, '男'], ['练习c', 18, '男']]
self.initUI()
def initUI(self):
self.setWindowTitle('学习练习')
self.move_center(600, 200)
layout = QVBoxLayout()
model = QStandardItemModel()
model.setRowCount(3)
model.setColumnCount(3)
model.setHorizontalHeaderLabels(['姓名', '年龄', '性别', '操作'])
for rowIndex, row in enumerate(self.stu_lis):
for colIndex, col in enumerate(row):
model.setItem(rowIndex, colIndex, QStandardItem(str(col)))
view = QTableView()
view.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
view.setEditTriggers(QTableView.EditTrigger.NoEditTriggers)
view.setSelectionBehavior(QTableView.SelectionBehavior.SelectRows)
view.setModel(model)
view.setItemDelegateForColumn(3, StuDelegate())
layout.addWidget(view)
self.setLayout(layout)
def move_center(self, width, height):
w = QGuiApplication.primaryScreen().size().width()
h = QGuiApplication.primaryScreen().size().height()
self.setGeometry((w - width) / 2, (h - height) / 2, width, height)
运行结果
不实现paint
不需要自定义绘制的时候,无需实现paint(),只需要重写下述方法: def createEditor(self, parent, option, index): ... 创建所需控件,例如QSpinBox等等 def setEditorData(self, editor, index): ... 设置控件数据,QSpinBox().setValue(... def setModelData(self, editor, model, index): ... 设置模型数据,model.setData(... def updateEditorGeometry(self, editor, option, index): ... 简单布局
painter绘制图形
def paint(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex) -> None:
h_center1 = option.rect.left()
v_center1 = option.rect.bottom() - option.rect.height()
painter.drawEllipse(h_center1, v_center1, option.rect.width() / 2, option.rect.height())
painter.drawText(h_center1 + 25, option.rect.bottom() - 10, '编辑')
h_center2 = option.rect.left() + option.rect.width() / 2
v_center2 = option.rect.bottom() - option.rect.height()
painter.drawEllipse(h_center2, v_center2, option.rect.width() / 2, option.rect.height())
painter.drawText(h_center2 + 25, option.rect.bottom() - 10, '删除')
这里仅仅使用了 QPinter 进行绘制图形,依据option的坐标,运行结果如下: