You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 11:03:12