英文:
Pyside6: Copy paste, delete, undo of multiple cells to and from QTableWidget
问题
I want to be able to copy and paste to and from a Pyside6 table (QTableWidget) with control-C control-V, mainly from and to Excel.
我想要能够使用Ctrl-C和Ctrl-V复制和粘贴到Pyside6表格(QTableWidget),主要是从Excel复制和粘贴。
I found @Momo's post of January 2023. 1
我找到了@Momo在2023年1月的帖子。1
That did not appear to work for me, possibly because I am working with Pyside6 instead of PyQt5.
这似乎对我不起作用,可能是因为我正在使用Pyside6而不是PyQt5。
What would be a solution for that?
那么有什么解决方案吗?
英文:
I want to be able to copy and paste to and from a Pyside6 table (QTableWidget) with control-C control-V, mainly from and to Excel.
I found @Momo's post of January 2023. 1
That did not appear to work for me, possibly because I am working with Pyside6 instead of PyQt5.
What would be a solution for that?
答案1
得分: 1
对我自己的问题的回答:
我修改了Momo的代码,使其适用于我的需求,并添加了删除多个单元格和撤销操作的功能。撤销操作仅在光标所在的表格内有效。
是否有更好的方法来实现这一功能,或者是否有改进建议?
import PySide6.QtWidgets as QtWidgets
from PySide6 import QtCore, QtGui
from PySide6.QtGui import QGuiApplication
class CopyPasteDelTableWidget(QtWidgets.QTableWidget):
def __init__(self, n_rows, n_columns):
super().__init__(n_rows, n_columns)
self.forundo = []
self.setSelectionMode(QtWidgets.QAbstractItemView.ContiguousSelection)
self.installEventFilter(self)
def eventFilter(self, source, event):
if event.type() == QtCore.QEvent.KeyPress:
if event == QtGui.QKeySequence.Copy:
self.copySelection()
return True
elif event == QtGui.QKeySequence.Paste:
self.pasteSelection()
return True
elif event == QtGui.QKeySequence.Delete:
self.deleteSelection()
return True
elif event == QtGui.QKeySequence.Cut:
self.copySelection()
self.deleteSelection()
return True
elif event == QtGui.QKeySequence.Undo:
self.undoSelection()
return True
return super(QTableWidget, self).eventFilter(source, event)
def deleteSelection(self):
self.forundo.append([self.selectedRanges()[0].topRow(), self.selectedRanges()[0].leftColumn(), []])
for i_row in range(self.selectedRanges()[0].topRow(), self.selectedRanges()[0].bottomRow() + 1):
undorow = []
for i_col in range(self.selectedRanges()[0].leftColumn(), self.selectedRanges()[0].rightColumn() + 1):
undorow.append(self.item(i_row, i_col).text())
self.setItem(i_row, i_col, QtWidgets.QTableWidgetItem(''))
self.forundo[-1][2].append(undorow)
def copySelection(self):
copied = ''
for row in range(self.selectedRanges()[0].topRow(), self.selectedRanges()[0].bottomRow() + 1):
for col in range(self.selectedRanges()[0].leftColumn(), self.selectedRanges()[0].rightColumn() + 1):
copied += self.item(row, col).text() + '\t'
copied = copied[:-1] + '\n'
QGuiApplication.clipboard().setText(copied)
def pasteSelection(self):
if not QGuiApplication.clipboard():
return
copied = QGuiApplication.clipboard().text().split('\n')
self.forundo.append([self.selectedRanges()[0].topRow(), self.selectedRanges()[0].leftColumn(), []])
if copied[-1] == '':
copied = copied[:-1]
for i_line, line in enumerate(copied):
copied[i_line] = line.split('\t')
for i_row, row in enumerate(copied):
undorow = []
k_row = i_row + self.selectedRanges()[0].topRow()
if k_row < self.rowCount():
for i_col, col in enumerate(row):
k_col = i_col + self.selectedRanges()[0].leftColumn()
if k_col < self.columnCount():
undorow.append(self.item(k_row, k_col).text())
self.setItem(k_row, k_col, QtWidgets.QTableWidgetItem(col))
self.forundo[-1][2].append(undorow)
def undoSelection(self):
if len(self.forundo) > 0:
prevundo = self.forundo.pop()
self.setCurrentCell(prevundo[0], prevundo[1])
for i_row, row in enumerate(prevundo[2]):
for i_col, col in enumerate(row):
self.setItem(i_row + prevundo[0], i_col + prevundo[1], QtWidgets.QTableWidgetItem(col))
英文:
An answer to my own question:
I changed Momo's code to make it work for me, and I added the possibility to delete multiple cells and to undo mistakes with this paste or delete. The undo works within the table where your cursor is only.
Are there better ways to do this, or might you have advice for improvement?
import PySide6.QtWidgets as QtWidgets
from PySide6 import QtCore, QtGui
from PySide6.QtGui import QGuiApplication
class CopyPasteDelTableWidget(QtWidgets.QTableWidget):
def __init__(self, n_rows, n_columns):
super().__init__(n_rows, n_columns)
self.forundo = []
self.setSelectionMode(QtWidgets.QAbstractItemView.ContiguousSelection)
self.installEventFilter(self)
def eventFilter(self, source, event):
if event.type() == QtCore.QEvent.KeyPress:
if event == QtGui.QKeySequence.Copy:
self.copySelection()
return True
elif event == QtGui.QKeySequence.Paste:
self.pasteSelection()
return True
elif event == QtGui.QKeySequence.Delete:
self.deleteSelection()
return True
elif event == QtGui.QKeySequence.Cut:
self.copySelection()
self.deleteSelection()
return True
elif event == QtGui.QKeySequence.Undo:
self.undoSelection()
return True
return super(QTableWidget, self).eventFilter(source, event)
def deleteSelection(self):
self.forundo.append([self.selectedRanges()[0].topRow(), self.selectedRanges()[0].leftColumn(), []])
for i_row in range(self.selectedRanges()[0].topRow(), self.selectedRanges()[0].bottomRow() + 1):
undorow = []
for i_col in range(self.selectedRanges()[0].leftColumn(), self.selectedRanges()[0].rightColumn() + 1):
undorow.append(self.item(i_row, i_col).text())
self.setItem(i_row, i_col, QtWidgets.QTableWidgetItem(''))
self.forundo[-1][2].append(undorow)
def copySelection(self):
copied = ''
for row in range(self.selectedRanges()[0].topRow(), self.selectedRanges()[0].bottomRow() + 1):
for col in range(self.selectedRanges()[0].leftColumn(), self.selectedRanges()[0].rightColumn() + 1):
copied += self.item(row, col).text() + '\t'
copied = copied[:-1] + '\n'
QGuiApplication.clipboard().setText(copied)
def pasteSelection(self):
if not QGuiApplication.clipboard():
return
copied = QGuiApplication.clipboard().text().split('\n')
self.forundo.append([self.selectedRanges()[0].topRow(), self.selectedRanges()[0].leftColumn(), []])
if copied[-1] == '':
copied = copied[:-1]
for i_line, line in enumerate(copied):
copied[i_line] = line.split('\t')
for i_row, row in enumerate(copied):
undorow = []
k_row = i_row + self.selectedRanges()[0].topRow()
if k_row < self.rowCount():
for i_col, col in enumerate(row):
k_col = i_col + self.selectedRanges()[0].leftColumn()
if k_col < self.columnCount():
undorow.append(self.item(k_row, k_col).text())
self.setItem(k_row, k_col, QtWidgets.QTableWidgetItem(col))
self.forundo[-1][2].append(undorow)
def undoSelection(self):
if len(self.forundo) > 0:
prevundo = self.forundo.pop()
self.setCurrentCell(prevundo[0], prevundo[1])
for i_row, row in enumerate(prevundo[2]):
for i_col, col in enumerate(row):
self.setItem(i_row + prevundo[0], i_col + prevundo[1], QtWidgets.QTableWidgetItem(col))
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论