PyQt:QTableView + QSqlTableModel - 将所有选定的行或列复制并粘贴到记事本或 Excel

PyQt: QTableView + QSqlTableModel - Copy and Paste All Selected Rows or Columns into Notepad or Excel

首先,我已经看过 ekhumoro 关于几乎相似主题的代码 。但是,当我尝试实现此代码时,我得到了不同的结果。它不是复制和粘贴所有 I selected,而是分别复制 selected 行的第一个单元格。我需要用户能够 select 多行或多列并将这些值粘贴到 excel 或记事本中。有什么想法吗?

界面:

代码:

from PyQt4 import QtCore, QtGui, QtSql
import sys  
import sqlite3
import time
import csv


import Search  # This file holds our MainWindow and all design related things

# it also keeps events etc that we defined in Qt Designer
import os 
try:
    from PyQt4.QtCore import QString
except ImportError:
    QString = str

class TableEditor(QtGui.QMainWindow, Search.Search_MainWindow):
    def __init__(self, tableName, parent=None):
        # Explaining super is out of the scope of this article
        # So please google it if you're not familar with it
        # Simple reason why we use it here is that it allows us to
        # access variables, methods etc in the design.py file
        super(self.__class__, self).__init__()
        self.setupUi(self)  # This is defined in design.py file automatically
        # It sets up layout and widgets that are defined
        self.model = QtSql.QSqlTableModel(self)
        self.model.setTable('CAUTI')
        self.model.setEditStrategy(QtSql.QSqlTableModel.OnManualSubmit)
        self.model.select()
        self.model.setHeaderData(0, QtCore.Qt.Horizontal, "MRN")
        self.model.setHeaderData(1, QtCore.Qt.Horizontal, "Last Name")
        self.model.setHeaderData(2, QtCore.Qt.Horizontal, "First Name")
        self.model.setHeaderData(3, QtCore.Qt.Horizontal, "Date of Event")
        self.model.setHeaderData(4, QtCore.Qt.Horizontal, "Facility")
        self.model.setHeaderData(5, QtCore.Qt.Horizontal, "Unit")
        self.model.setHeaderData(6, QtCore.Qt.Horizontal, "User")
        #self.tableView.verticalHeader().setVisible(False)
        self.tableView.setModel(self.model)
        self.setWindowTitle("HAI Table")
        self.tableView.setColumnWidth(0,100)
        self.tableView.setColumnWidth(1,100)
        self.tableView.setColumnWidth(2,100)
        self.tableView.setColumnWidth(3,100)
        self.tableView.setColumnWidth(4,100)
        self.tableView.setColumnWidth(5,100)
        self.tableView.setColumnWidth(6,83)
        self.tableView.setSortingEnabled(True)
        self.tableView.setDropIndicatorShown(True)
        self.tableView.setAcceptDrops(True)
        self.tableView.setDragEnabled(True)
        self.tableView.setDragDropMode(QtGui.QAbstractItemView.InternalMove)
        self.tableView.horizontalHeader().setMovable(True)       
        self.tableView.horizontalHeader().setDragEnabled(True)
        self.clip = QtGui.QApplication.clipboard()

     ## Note: ** When I unblock this line of code, I get an error.
        #self.tableView.installEventFilters(self)




        self.tableView.horizontalHeader().setDragDropMode(QtGui.QAbstractItemView.InternalMove)
        self.tableView.verticalHeader().setMovable(True)
        self.tableView.verticalHeader().setDragEnabled(True)
        self.tableView.verticalHeader().setDragDropMode(QtGui.QAbstractItemView.InternalMove)
        self.tableView.setSelectionBehavior(QtGui.QTableView.SelectRows)
        self.submitButton.clicked.connect(self.submit)
        self.revertButton.clicked.connect(self.model.revertAll)
        self.quitButton.clicked.connect(self.close)

        self.tableView.horizontalHeader().setSortIndicatorShown(True)
        self.tableView.horizontalHeader().setClickable(True)
    def eventFilter(self, source, event):
        if (event.type() == QtCore.QEvent.KeyPress and
            event.matches(QtGui.QKeySequence.Copy)):
            self.copySelection()
            return True
        return super(Window, self).eventFilter(source, event)

    def copySelection(self):
        selection = self.tableView.selectedIndexes()
        if selection:
            rows = sorted(index.row() for index in selection)
            columns = sorted(index.column() for index in selection)
            rowcount = rows[-1] - rows[0] + 1
            colcount = columns[-1] - columns[0] + 1
            table = [[''] * colcount for _ in range(rowcount)]
            for index in selection:
                row = index.row() - rows[0]
                column = index.column() - columns[0]
                table[row][column] = index.data()
            stream = io.StringIO()
            csv.writer(stream).writerows(table)
            QtGui.qApp.clipboard().setText(stream.getvalue())

    def flags(self, index):
        return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsDropEnabled    


def main():
    app = QtGui.QApplication(sys.argv)  
    #app.setStyle( "Plastique" )
    db = QtSql.QSqlDatabase.addDatabase('QSQLITE')
    db.setDatabaseName('HAI.db')

    editor = TableEditor('CAUTI')
    editor.show()
    app.exec_()  


if __name__ == '__main__': 
    main()  

您的实现在几个方面有问题,因此您复制的代码永远不会执行。结果,使用了table的built-in复制功能,不处理多选项。

我复制多个 table 项目的原始代码是 。我认为您应该能够通过更改以下行来使您的示例工作:

from PyQt4 import QtCore, QtGui, QtSql
# fix imports
import sys, io
...

class TableEditor(QtGui.QMainWindow, Search.Search_MainWindow):
    def __init__(self, tableName, parent=None):
        # do not ever use self.__class__ here
        super(TableEditor, self).__init__()
        ...
        # install event-filter properly
        self.tableView.installEventFilter(self)

    def eventFilter(self, source, event):
        ...
        # call super properly
        return super(TableEditor, self).eventFilter(source, event)

显然,我无法 运行 您的实际示例代码,因此可能还有其他我没有发现的错误。

这要快得多:

def copySelection(self):
    clipboardString = StringIO()
    selectedIndexes = self.ui.tableView.selectedIndexes()
    if selectedIndexes:
        countList = len(selectedIndexes)         
        for r in range(countList):
            current = selectedIndexes[r]
            displayText = current.data(QtCore.Qt.DisplayRole)
            if r+1 < countList:
                next_ = selectedIndexes[r+1]
                if next_.row() != current.row():
                    displayText += ("\n")
                else:
                    displayText += ("\t")
            clipboardString.write(displayText)
        pyperclip.copy(clipboardString.getvalue())