How to Copy and Paste multiple Cells in QTableWidget in PyQt5?
Asked Answered
J

6

3

I have a Qtablewidget shown below. I want to copy multiple cells from the table and paste in other row in the same table.

So far, I can do the same on single cell, but is there a way i can do multiple cells at the same time??

Also, if possible, to copy multiple rows and paste it in same table below?

I tried looking at some answers in SO but quite didn't get it to implement in PyQt5.

Thanks in advance.

Snippet for Single Row Copy/Paste

Snippet for multiple Row Copy/Paste

Sample Code (By QtDesigner):

from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1048, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
        self.tableWidget.setGeometry(QtCore.QRect(40, 40, 861, 511))
        self.tableWidget.setEditTriggers(QtWidgets.QAbstractItemView.AnyKeyPressed|QtWidgets.QAbstractItemView.DoubleClicked|QtWidgets.QAbstractItemView.EditKeyPressed)
        self.tableWidget.setRowCount(5)
        self.tableWidget.setColumnCount(5)
        self.tableWidget.setObjectName("tableWidget")
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(1, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(2, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(3, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(4, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(0, 0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(0, 1, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(0, 2, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(0, 3, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(0, 4, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(1, 0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(1, 1, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(1, 2, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(1, 3, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(1, 4, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(2, 0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(2, 1, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(2, 2, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(2, 3, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(2, 4, item)
        self.tableWidget.horizontalHeader().setVisible(True)
        self.tableWidget.verticalHeader().setVisible(False)
        MainWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        item = self.tableWidget.horizontalHeaderItem(0)
        item.setText(_translate("MainWindow", "Name"))
        item = self.tableWidget.horizontalHeaderItem(1)
        item.setText(_translate("MainWindow", "ID"))
        item = self.tableWidget.horizontalHeaderItem(2)
        item.setText(_translate("MainWindow", "City"))
        item = self.tableWidget.horizontalHeaderItem(3)
        item.setText(_translate("MainWindow", "Number"))
        item = self.tableWidget.horizontalHeaderItem(4)
        item.setText(_translate("MainWindow", "Occupation"))
        __sortingEnabled = self.tableWidget.isSortingEnabled()
        self.tableWidget.setSortingEnabled(False)
        item = self.tableWidget.item(0, 0)
        item.setText(_translate("MainWindow", "Mark"))
        item = self.tableWidget.item(0, 1)
        item.setText(_translate("MainWindow", "1"))
        item = self.tableWidget.item(0, 2)
        item.setText(_translate("MainWindow", "Newyork"))
        item = self.tableWidget.item(0, 3)
        item.setText(_translate("MainWindow", "4796423643344"))
        item = self.tableWidget.item(0, 4)
        item.setText(_translate("MainWindow", "Teacher"))
        item = self.tableWidget.item(1, 0)
        item.setText(_translate("MainWindow", "Taylor"))
        item = self.tableWidget.item(1, 1)
        item.setText(_translate("MainWindow", "2"))
        item = self.tableWidget.item(1, 2)
        item.setText(_translate("MainWindow", "Chicago"))
        item = self.tableWidget.item(1, 3)
        item.setText(_translate("MainWindow", "43683284"))
        item = self.tableWidget.item(1, 4)
        item.setText(_translate("MainWindow", "Nurse"))
        self.tableWidget.setSortingEnabled(__sortingEnabled)


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

Derived Class:

from PyQt5 import QtWidgets

from demo import Ui_MainWindow

class demo_code(QtWidgets.QMainWindow, Ui_MainWindow):                    
    def __init__(self):
        super(demo_code, self).__init__()
        self.setupUi(self) 



if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    window = demo_code()    
    window.show()
    sys.exit(app.exec_())
Jodhpurs answered 17/3, 2020 at 2:27 Comment(7)
1) You say I can do the same on single cell and it would be good if you show it, 2) Will the rows that will be added always be the last rows?Andriaandriana
I think Single Cell Copy and Paste is by default. I will have a empty rows in table. So basically not inserting any rows, Just need to paste copied data in empty cells.Jodhpurs
You say: I think Single Cell Copy and Paste is by default, have you checked that it works? You should be more precise and instead of pointing: I can do the same on single cell if you haven't already.Andriaandriana
Yes, I just checked Copying single cell and paste it in other cell, It works!Jodhpurs
mmm, how strange, this functionality does not exist by default, do you select the row, press Ctrl + C, and then Ctrl + V to paste it? I have done that and it does not work.Andriaandriana
i meant only one cell not whole row or multiple cells. this can be done while entering values in table.Jodhpurs
@Jodhpurs that's not copying the cell, it's copying the text while the cell is being edited.Powerboat
B
6

Here is a solution subclassing QTableWidget. You have to reimplement the keyPressEvent, to catch the copy and paste key sequences. On copy, save the current selected items with QTableWidget.selectedIndexes(). On paste, set a new QTableWidgetItem for each cell in the list, translating the indexes to the new highlighted index. It will paste all the cells that were highlighted, they don't need to be in the same row. It assumes the cell with the smallest index will be placed in the highlighted cell on paste.

import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *

class Table(QTableWidget):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setRowCount(10)
        self.setColumnCount(10)
        # etc.

    def keyPressEvent(self, event):
        super().keyPressEvent(event)
        if event.key() == Qt.Key_C and (event.modifiers() & Qt.ControlModifier):
            self.copied_cells = sorted(self.selectedIndexes())
        elif event.key() == Qt.Key_V and (event.modifiers() & Qt.ControlModifier):
            r = self.currentRow() - self.copied_cells[0].row()
            c = self.currentColumn() - self.copied_cells[0].column()
            for cell in self.copied_cells:
                self.setItem(cell.row() + r, cell.column() + c, QTableWidgetItem(cell.data()))

if __name__ == '__main__':
    app = QApplication(sys.argv)
    gui = Table()
    gui.show()
    sys.exit(app.exec_())
Boden answered 17/3, 2020 at 4:47 Comment(1)
The copy function also works when sub-classing QTableView, didn't check the pastePartitive
I
3

Here is a solution written for PyQt6 and supporting copying onto the clipboard, so that you can paste multiple-cell selections from a QTableWidget into a popular spreadsheet program like Google Sheets, Apple Numbers, or Microsoft excel. These programs expect tab ('\t') delimiting for a new column and newline ('\n') delimiting for a new row

from PyQt6.QtCore import *
from PyQt6.QtWidgets import *
from PyQt6.QtGui import *

import sys

class TableWithCopy(QTableWidget):
    """
    this class extends QTableWidget
    * supports copying multiple cell's text onto the clipboard
    * formatted specifically to work with multiple-cell paste into programs
      like google sheets, excel, or numbers
    """

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def keyPressEvent(self, event):
        super().keyPressEvent(event)
        if event.key() == Qt.Key.Key_C and (event.modifiers() & Qt.KeyboardModifier.ControlModifier):
            copied_cells = sorted(self.selectedIndexes())

            copy_text = ''
            max_column = copied_cells[-1].column()
            for c in copied_cells:
                copy_text += self.item(c.row(), c.column()).text()
                if c.column() == max_column:
                    copy_text += '\n'
                else:
                    copy_text += '\t'
                    
            QApplication.clipboard().setText(copy_text)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    gui = TableWithCopy()
    gui.setColumnCount(10)
    gui.setRowCount(10)
    gui.show()
    sys.exit(app.exec())
Inconformity answered 31/7, 2021 at 1:35 Comment(0)
H
0

To extend boochbrain answere slightly with the paste function (in my use-case I needed the data to cover all rows and columns, to paste it):

from PyQt6.QtCore import *
from PyQt6.QtWidgets import *
from PyQt6.QtGui import *

import sys

class TableWithCopy(QTableWidget):
    """
    this class extends QTableWidget
    * supports copying multiple cell's text onto the clipboard
    * formatted specifically to work with multiple-cell paste into programs
      like google sheets, excel, or numbers
    """

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def keyPressEvent(self, event):
        super().keyPressEvent(event)
        if event.key() == Qt.Key.Key_C and (event.modifiers() & Qt.KeyboardModifier.ControlModifier):
            copied_cells = sorted(self.selectedIndexes())

            copy_text = ''
            max_column = copied_cells[-1].column()
            for c in copied_cells:
                copy_text += self.item(c.row(), c.column()).text()
                if c.column() == max_column:
                    copy_text += '\n'
                else:
                    copy_text += '\t'
                    
            QApplication.clipboard().setText(copy_text)

        if event.key() == Qt.Key_V and (event.modifiers() & Qt.KeyboardModifier.ControlModifier):
            rows = QApplication.clipboard().text().split('\n')[:-1]
            if len(rows) == 0:
                return
            if len(rows) != self.rowCount() or len(rows[0].split('\t')) != self.columnCount():
                QMessageBox.information(None, 'Error', 'The pasted data does not contain the correct data')
                return
            self.clear()
            self.setRowCount(len(rows))
            self.setColumnCount(len(rows[0].split('\t')))
            for i, row in enumerate(rows):
                row = row.split('\t')
                item1 = QTableWidgetItem(row[0])
                item2 = QTableWidgetItem(row[1])
                self.setItem(i, 0, item1)
                self.setItem(i, 1, item2)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    gui = TableWithCopy()
    gui.setColumnCount(10)
    gui.setRowCount(10)
    gui.show()
    sys.exit(app.exec())
Hong answered 22/9, 2022 at 13:43 Comment(0)
G
0
def copy_selected_cells(self):
    copied_cells = sorted(self.ui.tableWidget.selectedIndexes())
    copy_text = ''
    max_column = copied_cells[-1].column()
    max_row = copied_cells[-1].row()
    for c in copied_cells:
        copy_text += self.ui.tableWidget.item(c.row(), c.column()).text()
        if c.column() == max_column:
            if c.row() != max_row:
                copy_text += '\n'
        else:
            copy_text += '\t'
    QApplication.clipboard().setText(copy_text)
def paste_to_cells(self):
    selection = self.ui.tableWidget.selectedIndexes()
    if selection:
        row_anchor = selection[0].row()
        column_anchor = selection[0].column()
        clipboard = QApplication.clipboard()
        rows = clipboard.text().split('\n')
        for indx_row, row in enumerate(rows):
            values = row.split('\t')
            for indx_col, value in enumerate(values):
                if row_anchor + indx_row < self.ui.tableWidget.rowCount() and column_anchor + indx_col < self.ui.tableWidget.columnCount():
                    item = QTableWidgetItem(value)
                    self.ui.tableWidget.setItem(row_anchor + indx_row, column_anchor + indx_col, item)

I implemented copy and paste method using above code. if c.row() != max_row: copy_text += '\n' I fixed a bug like it for copy method.

Geese answered 16/10, 2023 at 13:49 Comment(0)
E
0

This is my solution for copying, pasting and cutting in Qtablewidget.

Copy:

def copy_selected_cells(self):
    copied_cells = sorted(self.tableWidget.selectedIndexes())
    copy_text = ''
    max_column = copied_cells[-1].column()
    max_row = copied_cells[-1].row()
    for c in copied_cells:
        copy_text += self.tableWidget.item(c.row(), c.column()).text()
        if c.column() == max_column:
            if c.row() != max_row:
                copy_text += '\n'
        else:
            copy_text += '\t'
    QApplication.clipboard().setText(copy_text)

Paste:

def paste_to_cells(self):
    selection = self.tableWidget.selectedIndexes()
    if selection:
        row_anchor = selection[0].row()
        column_anchor = selection[0].column()
        clipboard = QApplication.clipboard()
        rows = clipboard.text().split('\n')
        print(len(rows))
        current_row = self.tableWidget.currentRow()
        for n in range(len(rows)):
            self.tableWidget.insertRow(current_row + n)
        self.tableWidget.clearSelection()
        self.tableWidget.selectRow(current_row)
        for indx_row, row in enumerate(rows):
            values = row.split('\t')
            for indx_col, value in enumerate(values):
                if row_anchor + indx_row < self.tableWidget.rowCount() and column_anchor + indx_col < self.tableWidget.columnCount():
                    item = QTableWidgetItem(value)
                    self.tableWidget.setItem(row_anchor + indx_row, column_anchor + indx_col, item)

Cut:

    def cut_selected_cells(self):
        copied_cells = sorted(self.tableWidget.selectedIndexes())
        copy_text = ''
        max_column = copied_cells[-1].column()
        max_row = copied_cells[-1].row()
        current_row = self.tableWidget.currentRow()
        for c in copied_cells:
            copy_text += self.tableWidget.item(c.row(), c.column()).text()
            if c.column() == max_column:
                if c.row() != max_row:
                    copy_text += '\n'
            else:
                copy_text += '\t'
        index_list = []
        for model_index in self.tableWidget.selectionModel().selectedRows():
            index = QPersistentModelIndex(model_index)
            index_list.append(index)
        for index in index_list:
            self.tableWidget.removeRow(index.row())
        QApplication.clipboard().setText(copy_text)
        self.tableWidget.selectRow(current_row)
Eri answered 20/2, 2024 at 7:28 Comment(0)
T
0

Just wanted to share my copy/paste implementation for PyQt6 with the View-Model approach.

I wrote a subclass for the QTableView class and added the copy paste functions. The paste functions calls on the setData method of the QAbstractTableModel.

I also added a delete function and cells are added when the copied rows are larger than the current rows. Only for rows, not columns.

class Table(QTableView):
    def __init__(self):
        super().__init__()


    def keyPressEvent(self, event):
        """Add ctrl-c ctrl-v to table class"""
        super().keyPressEvent(event)
        if event.key() == Qt.Key.Key_C and (event.modifiers() & Qt.KeyboardModifier.ControlModifier):
            copied_cells = sorted(self.selectedIndexes())
            copy_text = ''
            max_column = copied_cells[-1].column()
            for c in copied_cells:
                copy_text += c.data()
                if c.column() == max_column:
                    copy_text += '\n'
                else:
                    copy_text += '\t'

            QApplication.clipboard().setText(copy_text)

        elif event.key() == Qt.Key.Key_V and (event.modifiers() & Qt.KeyboardModifier.ControlModifier):
            self.copied_text = QApplication.clipboard().text()
            rows = self.copied_text = self.copied_text.split("\n")[:-1]
            row_index = sorted(self.selectedIndexes())[0].row()

            for i, row in enumerate(rows):
                row = row.split('\t')
                for j, value in enumerate(row):
                    ri = self.currentIndex().row() + i
                    cj = self.currentIndex().column() + j
                    
                    itemIndex = self.model().createIndex(ri,cj)
                    if ri == self.model().rowCount(QModelIndex()):
                        self.model().insertRows([itemIndex])
                    self.model().setData(itemIndex, value)

        elif event.key() == Qt.Key.Key_Delete:
            rows_to_delete = sorted(self.selectedIndexes())
            self.model().removeRows(rows_to_delete)
Thirion answered 2/8, 2024 at 15:13 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.