Search code examples
pythonpyqtpyqt5qt5

PyQt5: copy/paste from a QTableWidget, with ContextMenu and with KeyboardPress


I am trying to copy the data in my QTableWidget to other spreadsheets, and paste other data if necessary, with two possibilities, a right click on the mouse and clicking the copy Action or using the keyboard "ctrl+c".

I found an answer before and I did write the code provided on that answer, but I think I missed it, can someone please tell me what I did wrong, here is the answer that I found. when I copy the data from the QTableWidget and paste it, the following sentence is pasted: self.results_table_Specific.installEventFilter(self), not the selected data here is my code:

class Calculation_window_Specific(QMainWindow):
    def __init__(self):
        super().__init__()
        uic.loadUi("specific_calculation_window.ui",self)
        self.setStyleSheet(stylesheet2)
        self.setWindowTitle('specific calculation table')
        self.setWindowIcon(QtGui.QIcon("logo.ico"))
        self.actionExcel_xlsx.triggered.connect(self.Export_to_Excel2)
        self.results_table_Specific.installEventFilter(self)  

        self.clipboard = []           
    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.type() == QtCore.QEvent.ContextMenu:
            # a context menu for the copy/paste operations
            menu = QtWidgets.QMenu()
            copyAction = menu.addAction('Copy')
            copyAction.triggered.connect(self.copySelection)
            pasteAction = menu.addAction('Paste')
            pasteAction.triggered.connect(self.pasteSelection)
            if not self.results_table_Specific.selectedIndexes():
                # no selection available, both copy and paste are disabled
                copyAction.setEnabled(False)
                pasteAction.setEnabled(False)
            if not self.clipboard:
                # no clipboard contents, paste is disabled
                pasteAction.setEnabled(False)
            menu.exec(event.globalPos())
            return True
        return super(Calculation_window_Specific, self).eventFilter(source, event)
    
    def copySelection(self):
        # clear the current contents of the clipboard
        self.clipboard.clear()
        selected = self.results_table_Specific.selectedIndexes()
        rows = []
        columns = []
        # cycle all selected items to get the minimum row and column, so that the
        # reference will always be [0, 0]
        for index in selected:
            rows.append(index.row())
            columns.append(index.column())
        minRow = min(rows)
        minCol = min(columns)
        for index in selected:
            # append the data of each selected index
            self.clipboard.append((index.row() - minRow, index.column() - minCol, index.data()))

    def pasteSelection(self):
        if not self.clipboard:
            return
        current = self.results_table_Specific.currentIndex()
        if not current.isValid():
            # in the rare case that there is no current index, use the first row
            # and column as target
            current = self.model.index(0, 0)

        firstRow = current.row()
        firstColumn = current.column()

        # optional: get the selection model so that pasted indexes will be
        # automatically selected at the end
        selection = self.results_table_Specific.selectionModel()
        for row, column, data in self.clipboard:
            # get the index, with rows and columns relative to the current
            index = self.model.index(firstRow + row, firstColumn + column)
            # set the data for the index
            self.model.setData(index, data, QtCore.Qt.DisplayRole)
            # add the index to the selection
            selection.select(index, selection.Select)

        # apply the selection model
        self.results_table_Specific.setSelectionModel(selection)

I tried this


Solution

  • it's me answering my question, here is the code that I used to get a QTableWidget with the copy/paste options outside and within the App, with two possibilities, with ContextMenu and KeyPress. in addition to the answer I linked above on the post here are the links to other posts where I found some help link1 link2

    class Calculation_window_Specific(QMainWindow):
        def __init__(self):
            super().__init__()
            uic.loadUi("specific_calculation_window.ui",self)
            self.setStyleSheet(stylesheet2)
            self.setWindowTitle('specific calculation table')
            self.setWindowIcon(QtGui.QIcon("logo.ico"))
            self.actionExcel_xlsx.triggered.connect(self.Export_to_Excel2) 
    
            self.results_table_Specific.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.type() == QtCore.QEvent.ContextMenu:
                # a context menu for the copy/paste operations
                menu = QtWidgets.QMenu()
                copyAction = menu.addAction('Copy')
                copyAction.triggered.connect(self.copySelection)
                pasteAction = menu.addAction('Paste')
                pasteAction.triggered.connect(self.pasteSelection)
    
                if not self.results_table_Specific.selectedIndexes():
                    # no selection available, both copy and paste are disabled
                    copyAction.setEnabled(False)
                    pasteAction.setEnabled(False)
                menu.exec(event.globalPos())
                return True
            return super(Calculation_window_Specific, self).eventFilter(source, event)
        
        def copySelection(self):
            # clear the current contents of the clipboard
            self.clipboard=''
            copied_cells = sorted(self.results_table_Specific.selectedIndexes())
            max_column = copied_cells[-1].column()
            for c in copied_cells:
                self.clipboard += self.results_table_Specific.item(c.row(), c.column()).text()
                if c.column() == max_column:
                    self.clipboard += '\n'
                else:
                    self.clipboard += '\t'
            QApplication.clipboard().setText(self.clipboard)
    
        def pasteSelection(self):
            selection = self.results_table_Specific.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):
                        item = QTableWidgetItem(value)
                        self.results_table_Specific.setItem(row_anchor + indx_row, column_anchor + indx_col, item)