0

I am displaying a dataframe in GUI using QTableView in Pyqt5. How should I code it up so that users can copy paste multiple rows/columns at the same time together with the row index (for row) and headers (for columns)?

I have put up a simple example below. I assume we will need a subclass of QTableView and define a keyPressEvent for it.

import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt
import pandas as pd

class TableModel(QtCore.QAbstractTableModel):

    def __init__(self, data):
        super(TableModel, self).__init__()
        self._data = data

    def data(self, index, role):
        if role == Qt.DisplayRole:
            value = self._data.iloc[index.row(), index.column()]
            return str(value)

    def rowCount(self, index):
        return self._data.shape[0]

    def columnCount(self, index):
        return self._data.shape[1]

    def headerData(self, section, orientation, role):
        # section is the index of the column/row.
        if role == Qt.DisplayRole:
            if orientation == Qt.Horizontal:
                return str(self._data.columns[section])

            if orientation == Qt.Vertical:
                return str(self._data.index[section])

class View(QTableView):
    def __init__(self):
        super(View, self).__init__(parent=None)

    def keyPressEvent(self, event):
        if event.matches(QKeySequence.Copy):
            # some code to get copy_text?  
            QApplication.clipboard().setText(copy_text)


        QTableView.keyPressEvent(self, event)

class MainWindow(QtWidgets.QMainWindow):

    def __init__(self):
        super().__init__()

        self.table = View() # use subclass View() instead of self.table = QtWidgets.QTableView()

        data = pd.DataFrame([
          [1, 9, 2],
          [1, 0, -1],
          [3, 5, 2],
          [3, 3, 2],
          [5, 8, 9],
        ], columns = ['A', 'B', 'C'], index=['Row 1', 'Row 2', 'Row 3', 'Row 4', 'Row 5'])

        self.model = TableModel(data)
        self.table.setModel(self.model)
        self.setCentralWidget(self.table)


app=QtWidgets.QApplication(sys.argv)
window=MainWindow()
window.show()
app.exec_()
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
wwj123
  • 365
  • 2
  • 12

1 Answers1

0

You can cycle through the selectedIndexes(), then eventually sort them.

def keyPressEvent(self, event):
    if event.matches(QtGui.QKeySequence.Copy):
        data = []
        for index in sorted(self.selectedIndexes()):
            data.append(('{}\t\t{}\t\t{}'.format(
                index.row(), index.column(), index.data())))
        if data:
            QtWidgets.QApplication.clipboard().setText(
                'Row\t\tCol\t\tValue:\n' + '\n'.join(data))
            return
    QtWidgets.QTableView.keyPressEvent(self, event)

Note that the default QModelIndex implementation supports sorting first by rows and then by columns, but you can alter the behavior with a lambda:

for index in sorted(self.selectedIndexes(), key=lambda i: (i.column(), i.row())):
musicamante
  • 41,230
  • 6
  • 33
  • 58