PyQt实现QListWidget拖拽项至QTableWidget表头添加行列
实现QListWidget拖拽到QTableWidget表头添加行列
需求
将QListWidget中的元素拖拽到QTableWidget的垂直/水平表头区域:
- 拖拽到垂直表头两行之间,添加以拖拽项命名的新行
- 拖拽到水平表头两列之间,添加以拖拽项命名的新列
问题
QTableWidget默认的dropEvent仅对单元格生效,无法直接捕获表头区域的拖拽事件,直接自定义表头的事件也无法实现需求。
解决方案
核心思路是自定义表头类(继承QHeaderView),重写拖拽相关事件,解析拖拽数据并触发表格添加行列的操作,再让QTableWidget使用这些自定义表头。
步骤1:自定义垂直表头(处理行添加)
from PyQt5.QtWidgets import QHeaderView, QTableWidgetItem, QStandardItemModel from PyQt5.QtCore import Qt class VerticalHeader(QHeaderView): def __init__(self, parent=None): super().__init__(Qt.Vertical, parent) self.setSectionsMovable(True) self.setDragEnabled(True) self.setDragDropMode(QHeaderView.DropOnly) self.setAcceptDrops(True) def dragEnterEvent(self, event): # 仅接受QListWidget的拖拽数据格式 if event.mimeData().hasFormat('application/x-qabstractitemmodeldatalist'): event.acceptProposedAction() else: super().dragEnterEvent(event) def dropEvent(self, event): if event.mimeData().hasFormat('application/x-qabstractitemmodeldatalist'): # 解析拖拽的文本内容 mime_data = event.mimeData() model = QStandardItemModel() model.dropMimeData(mime_data, Qt.CopyAction, 0, 0, model.index(0, 0)) item_text = model.item(0, 0).text() if model.item(0,0) else "" # 获取拖拽位置对应的行索引,末尾位置返回-1时设为当前行数 drop_index = self.logicalIndexAt(event.pos()) if drop_index == -1: drop_index = self.count() # 通知表格插入新行并设置表头文本 self.parent().insertRow(drop_index) self.parent().setVerticalHeaderItem(drop_index, QTableWidgetItem(item_text)) event.acceptProposedAction() else: super().dropEvent(event)
步骤2:自定义水平表头(处理列添加)
class HorizontalHeader(QHeaderView): def __init__(self, parent=None): super().__init__(Qt.Horizontal, parent) self.setSectionsMovable(True) self.setDragEnabled(True) self.setDragDropMode(QHeaderView.DropOnly) self.setAcceptDrops(True) def dragEnterEvent(self, event): if event.mimeData().hasFormat('application/x-qabstractitemmodeldatalist'): event.acceptProposedAction() else: super().dragEnterEvent(event) def dropEvent(self, event): if event.mimeData().hasFormat('application/x-qabstractitemmodeldatalist'): # 解析拖拽文本 mime_data = event.mimeData() model = QStandardItemModel() model.dropMimeData(mime_data, Qt.CopyAction, 0, 0, model.index(0, 0)) item_text = model.item(0, 0).text() if model.item(0,0) else "" # 获取拖拽位置对应的列索引 drop_index = self.logicalIndexAt(event.pos()) if drop_index == -1: drop_index = self.count() # 通知表格插入新列并设置表头文本 self.parent().insertColumn(drop_index) self.parent().setHorizontalHeaderItem(drop_index, QTableWidgetItem(item_text)) event.acceptProposedAction() else: super().dropEvent(event)
步骤3:自定义TableWidget使用自定义表头
class CustomTable(QTableWidget): def __init__(self, parent=None): super().__init__(parent) # 替换为自定义表头 self.setVerticalHeader(VerticalHeader(self)) self.setHorizontalHeader(HorizontalHeader(self)) # 原有样式和滚动条设置 self.setStyleSheet(tableStyle) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
步骤4:主窗口整合代码
import sys from PyQt5.QtWidgets import QApplication, QMainWindow, QAbstractItemView, QHBoxLayout, QWidget, QListWidget, QTableWidgetItem from PyQt5.QtCore import Qt tableStyle = ''' QTableWidget::item {background-color: "#F4FAFB"; border-style: outset; border-width:1px; border-radius: 2px; border-color: #AEAEAE} QTableWidget::item:selected {background-color: #66C3D0; border-width:1px; border-radius: 2px; color: white; border-color: #333333} ''' # 上述自定义表头和CustomTable类需放在此处 class TableDemo(QMainWindow): def __init__(self): super().__init__() # 创建可拖拽的ListWidget self.list = QListWidget(self) self.list.addItem('Item 1') self.list.addItem('Item 3') self.list.addItem('Item 4') self.list.setDragDropMode(QAbstractItemView.DragOnly) # 使用自定义表格 self.table = CustomTable(self) self.table.setRowCount(5) self.table.setColumnCount(3) self.table.setHorizontalHeaderLabels(['Column 1', 'Column 2', 'Column 3']) self.table.setVerticalHeaderLabels(['Row 1', 'Row 2', 'Row 3', 'Row 4', 'Row 5']) # 填充表格数据 for row in range(5): for col in range(3): self.table.setItem(row, col, QTableWidgetItem(f"Item ({row+1}, {col+1})")) # 布局设置 layout = QHBoxLayout() layout.addWidget(self.list) layout.addWidget(self.table) central_widget = QWidget() central_widget.setLayout(layout) self.setCentralWidget(central_widget) self.setWindowTitle("QTableWidget 拖拽添加行列") self.resize(800, 300) if __name__ == '__main__': app = QApplication(sys.argv) window = TableDemo() window.show() sys.exit(app.exec_())
关键说明
- 自定义表头通过
logicalIndexAt(event.pos())获取拖拽位置对应的行列索引,拖拽到表头末尾时自动添加到最后一行/列 - 解析拖拽数据时使用
QStandardItemModel的dropMimeData方法提取QListWidget项的文本 - 确保QListWidget的
dragDropMode设置为DragOnly,允许项被拖拽出
内容的提问来源于stack exchange,提问作者z3r0cr33d
相关产品推荐
相关产品推荐

