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

PyQt5 QTableWidget实现复制粘贴报AttributeError如何修复

错误原因
  • 事件分发优先级冲突:你为QTableWidget安装的事件过滤器优先级高于主窗口的keyPressEvent,当按下Ctrl+C时,事件会被事件过滤器优先捕获,执行完copySelection后返回True终止了事件传递,导致keyPressEvent中给self.copied_cells赋值的代码永远不会执行,粘贴时自然找不到该属性。
  • 调用对象错误:粘贴逻辑中self.setItem是错误写法,setItem是QTableWidget类的方法,你需要调用self.tableWidget.setItem才能正常写入单元格。
  • 缺少容错判断:没有判断copied_cells是否存在就直接访问,未复制就按Ctrl+V也会触发报错。
修复方案

直接合并复制粘贴逻辑到事件过滤器中,删掉冗余的keyPressEvent重复判断即可,完整可运行代码如下:

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QTableWidget, QApplication, QMainWindow, QTableWidgetItem,QFileSystemModel, QFileDialog,QVBoxLayout,QWidget
from PyQt5.QtCore import Qt
from PyQt5.uic import loadUi
import sys, csv, io


class Main_P(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        loadUi("test_copy&paste.ui",self)
        self.tableWidget.installEventFilter(self)
        # 初始化存储复制单元格的属性
        self.copied_cells = []
        
    def eventFilter(self, source, event):
        if event.type() == QtCore.QEvent.KeyPress:
            # 处理复制
            if event.matches(QtGui.QKeySequence.Copy):
                self.copySelection()
                return True
            # 处理粘贴
            elif event.matches(QtGui.QKeySequence.Paste):
                self.pasteSelection()
                return True
        return super(Main_P, self).eventFilter(source, event)
    
    def copySelection(self):
        selection = self.tableWidget.selectedIndexes()
        if not selection:
            return
        # 记录复制的单元格
        self.copied_cells = sorted(selection)
        # 同时写入剪贴板,支持粘贴到外部程序
        rows = sorted(index.row() for index in selection)
        columns = sorted(index.column() for index in selection)
        rowcount = rows[-1] - rows[0] + 1
        colcount = columns[-1] - columns[0] + 1
        table = [[''] * colcount for _ in range(rowcount)]
        for index in selection:
            row = index.row() - rows[0]
            column = index.column() - columns[0]
            table[row][column] = index.data() if index.data() else ''
        stream = io.StringIO()
        csv.writer(stream, delimiter='\t').writerows(table)
        QtWidgets.qApp.clipboard().setText(stream.getvalue())

    def pasteSelection(self):
        # 先判断有没有复制内容
        if not self.copied_cells:
            return
        # 计算粘贴的偏移量
        current_row = self.tableWidget.currentRow()
        current_col = self.tableWidget.currentColumn()
        if current_row < 0 or current_col < 0:
            return
        row_offset = current_row - self.copied_cells[0].row()
        col_offset = current_col - self.copied_cells[0].column()
        # 写入单元格,超出表格范围的自动忽略
        max_row = self.tableWidget.rowCount() - 1
        max_col = self.tableWidget.columnCount() - 1
        for cell in self.copied_cells:
            target_row = cell.row() + row_offset
            target_col = cell.column() + col_offset
            if 0 <= target_row <= max_row and 0 <= target_col <= max_col:
                self.tableWidget.setItem(target_row, target_col, QTableWidgetItem(cell.data()))

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    win = Main_P()
    win.show()
    sys.exit(app.exec_())
优化说明
  • 增加了边界判断,粘贴内容超出表格范围时不会触发索引报错
  • 复制时同时支持内部粘贴和粘贴到Excel、记事本等外部程序
  • 增加了未选中单元格、未复制就粘贴的容错处理,避免异常崩溃

内容的提问来源于stack exchange,提问作者daniel ajj

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 01:54:03