如何在PySide6的QTableView单元格中添加删除按钮并处理点击事件
在PySide6的QTableView中为每行添加删除按钮的实现方案
1. 修正Delegate的paint方法
不要在paint中创建实际的QPushButton(这种方式不会显示控件,还会浪费资源),而是利用Qt的样式系统绘制按钮的视觉效果,保证样式和系统一致且性能更好:
from PySide6 import QtWidgets, QtGui, QtCore from typing import Union class DeleteButtonDelegate(QtWidgets.QStyledItemDelegate): btn_clicked = QtCore.Signal(int) # 自定义信号,传递被点击行的行号 def paint(self, painter: QtGui.QPainter, option: QtWidgets.QStyleOptionViewItem, index: Union[QtCore.QModelIndex, QtCore.QPersistentModelIndex]) -> None: # 仅在最后一列绘制删除按钮 if index.column() == index.model().columnCount() - 1: # 配置按钮样式参数 btn_option = QtWidgets.QStyleOptionButton() btn_option.rect = option.rect.adjusted(4, 4, -4, -4) # 调整按钮与单元格的边距 btn_option.text = "删除" btn_option.state = QtWidgets.QStyle.State_Enabled | QtWidgets.QStyle.State_Active # 调用系统样式绘制按钮 QtWidgets.QApplication.style().drawControl(QtWidgets.QStyle.CE_PushButton, btn_option, painter) else: # 其他列使用父类默认绘制逻辑 super().paint(painter, option, index)
2. 处理按钮点击事件
重写editorEvent方法,捕获鼠标点击动作,判断点击位置是否在按钮区域内,若是则发出删除信号:
在上述DeleteButtonDelegate类中添加以下代码:
def editorEvent(self, event: QtCore.QEvent, model: QtCore.QAbstractItemModel, option: QtWidgets.QStyleOptionViewItem, index: QtCore.QModelIndex) -> bool: # 非操作列直接调用父类逻辑 if index.column() != model.columnCount() - 1: return super().editorEvent(event, model, option, index) # 处理鼠标左键释放事件 if event.type() == QtCore.QEvent.MouseButtonRelease and event.button() == QtCore.Qt.LeftButton: # 判断点击位置是否在按钮范围内 btn_rect = option.rect.adjusted(4, 4, -4, -4) if btn_rect.contains(event.pos()): self.btn_clicked.emit(index.row()) return True return super().editorEvent(event, model, option, index)
3. 完善TableModel的删除功能
确保你的MyTableModel实现removeRow方法(QAbstractTableModel默认未实现),处理数据删除并通知模型更新:
class MyTableModel(QtCore.QAbstractTableModel): def __init__(self, data=None, headers=None): super().__init__() self._data = data or [["行1数据1", "行1数据2"], ["行2数据1", "行2数据2"], ["行3数据1", "行3数据2"]] self._headers = headers or ["列1", "列2", "操作"] # 最后一列设为操作列 def rowCount(self, parent=QtCore.QModelIndex()) -> int: return len(self._data) def columnCount(self, parent=QtCore.QModelIndex()) -> int: return len(self._headers) def data(self, index: QtCore.QModelIndex, role=QtCore.Qt.DisplayRole): if not index.isValid(): return None if role == QtCore.Qt.DisplayRole: if index.column() < len(self._data[index.row()]): return self._data[index.row()][index.column()] return None def headerData(self, section: int, orientation: QtCore.Qt.Orientation, role=QtCore.Qt.DisplayRole): if role == QtCore.Qt.DisplayRole and orientation == QtCore.Qt.Horizontal: return self._headers[section] return super().headerData(section, orientation, role) def removeRow(self, row: int, parent=QtCore.QModelIndex()) -> bool: if 0 <= row < len(self._data): # 通知模型即将删除行 self.beginRemoveRows(parent, row, row) del self._data[row] # 通知模型删除完成 self.endRemoveRows() return True return False
4. 主窗口中绑定代理与信号
修改Window类,设置代理并将按钮点击信号绑定到删除逻辑:
class Window(QtWidgets.QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("带删除按钮的表格") self.table_view = QtWidgets.QTableView() self.setCentralWidget(self.table_view) self.model = MyTableModel() self.table_view.setModel(self.model) # 为最后一列设置删除按钮代理 self.delete_delegate = DeleteButtonDelegate() self.table_view.setItemDelegateForColumn(self.model.columnCount()-1, self.delete_delegate) # 绑定删除信号到槽函数 self.delete_delegate.btn_clicked.connect(self.on_delete_btn_clicked) # 自动调整列宽适配内容 self.table_view.resizeColumnsToContents() def on_delete_btn_clicked(self, row): # 调用模型方法删除对应行 self.model.removeRow(row)
运行测试
添加主函数启动程序:
if __name__ == "__main__": app = QtWidgets.QApplication([]) window = Window() window.show() app.exec()
内容的提问来源于stack exchange,提问作者ucag
相关产品推荐
相关产品推荐

