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

Posted

技术标签:

【中文标题】PyQt:QTableView + QSqlTableModel - 将所有选定的行或列复制并粘贴到记事本或 Excel 中【英文标题】:PyQt: QTableView + QSqlTableModel - Copy and Paste All Selected Rows or Columns into Notepad or Excel 【发布时间】:2017-06-21 04:23:04 【问题描述】:

首先,我已经查看了 ekhumoro 的代码,主题几乎相似 Here。但是,当我尝试实现此代码时,我得到了不同的结果。而不是复制和粘贴我选择的所有内容,它只分别复制所选行的第一个单元格。我需要用户能够选择多行或多列并将这些值粘贴到 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()  

【问题讨论】:

【参考方案1】:

您的实现在多个方面被破坏,因此您复制的代码永远不会被执行。结果使用了表格内置的复制功能,不处理多个选中项。

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

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)

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

【讨论】:

@ekhumoro 男人,你真棒!!!非常感谢您为我提供的所有帮助。我无法表达我的感激之情。 =D【参考方案2】:

这要快得多:

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())

【讨论】:

请注意,此代码已损坏,因为它无法正确处理非连续选择。此外,它更慢,因为它使用 pyperclip 而不是 qt 剪贴板。 (即使没有pyperclip,它仍然不会运行得更快)。

以上是关于PyQt:QTableView + QSqlTableModel - 将所有选定的行或列复制并粘贴到记事本或 Excel 中的主要内容,如果未能解决你的问题,请参考以下文章

如何将数据发送到 QTableView/QTableWidget (PyQt)

PyQt4 qTableView 对齐

基于 PyQt4 QTableView 模型

PySide/pyQt 在 QTableView 中显示数据

QTableView 和 QStyledItemDelegate 类的使用 (PyQt5)

PyQt4中的QTableView选定元素