这个答案扩展了@learncode 和@Frederick Li 的答案,以满足以下情况
- 行和列不按升序排列
- 某些行和/或列隐藏在视图中。
它还包括扩展事件过滤器以处理粘贴的代码。
class TableView(QTableView):
def __init__(self, *args, **kwargs):
super(TableView, self).__init__(*args, **kwargs)
self.installEventFilter(self)
def eventFilter(self, source, event):
if event.type() == QEvent.KeyPress and event.matches(QKeySequence.Copy):
self.copy_selection()
return True
elif event.type() == QEvent.KeyPress and event.matches(QKeySequence.Paste):
self.paste_selection()
return True
return super(TableView, self).eventFilter(source, event)
def copy_selection(self):
selection = self.selectedIndexes()
if selection:
all_rows = []
all_columns = []
for index in selection:
if not index.row() in all_rows:
all_rows.append(index.row())
if not index.column() in all_columns:
all_columns.append(index.column())
visible_rows = [row for row in all_rows if not self.isRowHidden(row)]
visible_columns = [
col for col in all_columns if not self.isColumnHidden(col)
]
table = [[""] * len(visible_columns) for _ in range(len(visible_rows))]
for index in selection:
if index.row() in visible_rows and index.column() in visible_columns:
selection_row = visible_rows.index(index.row())
selection_column = visible_columns.index(index.column())
table[selection_row][selection_column] = index.data()
stream = io.StringIO()
csv.writer(stream, delimiter="\t").writerows(table)
QApplication.clipboard().setText(stream.getvalue())
def paste_selection(self):
selection = self.selectedIndexes()
if selection:
model = self.model()
buffer = QApplication.clipboard().text()
all_rows = []
all_columns = []
for index in selection:
if not index.row() in all_rows:
all_rows.append(index.row())
if not index.column() in all_columns:
all_columns.append(index.column())
visible_rows = [row for row in all_rows if not self.isRowHidden(row)]
visible_columns = [
col for col in all_columns if not self.isColumnHidden(col)
]
reader = csv.reader(io.StringIO(buffer), delimiter="\t")
arr = [[cell for cell in row] for row in reader]
if len(arr) > 0:
nrows = len(arr)
ncols = len(arr[0])
if len(visible_rows) == 1 and len(visible_columns) == 1:
# Only the top-left cell is highlighted.
for i in range(nrows):
insert_rows = [visible_rows[0]]
row = insert_rows[0] + 1
while len(insert_rows) < nrows:
row += 1
if not self.isRowHidden(row):
insert_rows.append(row)
for j in range(ncols):
insert_columns = [visible_columns[0]]
col = insert_columns[0] + 1
while len(insert_columns) < ncols:
col += 1
if not self.isColumnHidden(col):
insert_columns.append(col)
for i, insert_row in enumerate(insert_rows):
for j, insert_column in enumerate(insert_columns):
cell = arr[i][j]
model.setData(model.index(insert_row, insert_column), cell)
else:
# Assume the selection size matches the clipboard data size.
for index in selection:
selection_row = visible_rows.index(index.row())
selection_column = visible_columns.index(index.column())
model.setData(
model.index(index.row(), index.column()),
arr[selection_row][selection_column],
)
return