PySide6中如何实现TableWidget跨行列粘贴Excel表格内容
实现功能:使用PySide6进行工具开发,通过TableWidget实现跨行列粘贴Excel表格内容。列数是固定的(因为列标题是固定的),而只根据粘贴内容动态增加行数。如果粘贴的内容超出表格列范围,超出的部分会被忽略。
难点:在 PySide6 中,QTableWidget 默认不支持跨行或跨列粘贴内容。要实现跨行列粘贴功能,需要自定义粘贴逻辑。可以通过重写 QTableWidget 的 dropEvent 或 paste 方法来实现。
示例代码如下:
from PySide6.QtWidgets import QApplication, QTableWidget, QTableWidgetItem, QMainWindow, QMenu
from PySide6.QtCore import Qt, QMimeData
class CustomTableWidget(QTableWidget):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 启用拖放和粘贴功能
self.setAcceptDrops(True)
self.setSelectionMode(QTableWidget.SelectionMode.ContiguousSelection)
def paste(self):
"""重写粘贴方法,支持从 Excel 复制的内容"""
clipboard = QApplication.clipboard()
mime_data = clipboard.mimeData()
if mime_data.hasText():
# 获取剪贴板中的文本内容
text = mime_data.text()
# 按行分割(Excel 复制的内容通常以 \n 分隔行)
rows = text.strip().split('\n')
# 获取当前选中的起始单元格
start_row = self.currentRow()
start_col = self.currentColumn()
# 动态调整表格的行数
required_rows = start_row + len(rows)
if required_rows > self.rowCount():
self.setRowCount(required_rows)
for i, row in enumerate(rows):
if not row.strip():
continue # 跳过空行
# 按列分割(Excel 复制的内容通常以 \t 分隔列)
cells = row.split('\t')
for j, cell in enumerate(cells):
# 计算目标单元格的位置
target_row = start_row + i
target_col = start_col + j
# 检查目标单元格是否在表格列范围内
if target_col < self.columnCount():
# 创建新的 QTableWidgetItem 并设置内容
item = QTableWidgetItem(cell.strip())
self.setItem(target_row, target_col, item)
def keyPressEvent(self, event):
"""重写键盘事件,支持 Ctrl+V 粘贴"""
if event.key() == Qt.Key.Key_V and event.modifiers() == Qt.KeyboardModifier.ControlModifier:
self.paste()
else:
super().keyPressEvent(event)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("QTableWidget 动态行粘贴示例")
self.setGeometry(100, 100, 600, 400)
# 创建一个空的表格,不指定初始行数,列数固定为 5
self.table = CustomTableWidget(0, 5, self) # 0 行,5 列
self.setCentralWidget(self.table)
# 设置固定的列标题
self.table.setHorizontalHeaderLabels(["Col 1", "Col 2", "Col 3", "Col 4", "Col 5"])
# 启用右键菜单
self.table.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
self.table.customContextMenuRequested.connect(self.show_context_menu)
def show_context_menu(self, pos):
"""显示右键菜单"""
context_menu = QMenu(self)
add_row_action = context_menu.addAction("增加行")
paste_action = context_menu.addAction("粘贴")
# 连接菜单项的信号
add_row_action.triggered.connect(self.add_row)
paste_action.triggered.connect(self.table.paste)
# 显示菜单
context_menu.exec_(self.table.viewport().mapToGlobal(pos))
def add_row(self):
"""动态增加行"""
current_rows = self.table.rowCount()
self.table.setRowCount(current_rows + 1)
self.table.setVerticalHeaderLabels([f"Row {i+1}" for i in range(self.table.rowCount())])
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())