Greetings, I'm interested in incorporating a QTableWidget into one of my applications and would like to give it the functionality to cut, copy, and paste a user selection. So far I've implemented the copy and paste actions to a functional level. However, I often deal with very large arrays (e.g. 250000) rows, as such when pasting an array of that size it seems to take on the order of 8-10 seconds to actually set the data in the table. I've attached a small example script that has the copy and paste functionality and was hoping some of the more experienced programmers out there could take a look and comment on whether it is possible to commit data to the QTableWidget in a more efficient manner. So far I've only been able to use the setItem() function iteratively. There doesn't seem to be a setItems() (i.e. setting a large list of items at one time). Thanks for your help.
Brian -ps I didn't attach a text file with 250000 rows as it is about 1MB compressed, though if anyone is interested let me know and I'll send it on.
from PyQt4.QtCore import * from PyQt4.QtGui import * import sys import time my_array = [['00','01','02'], ['10','11','12'], ['20','21','22'], ['30','31','32']] def main(): app = QApplication(sys.argv) w = MyWindow() w.show() sys.exit(app.exec_()) class MyWindow(QWidget): def __init__(self, *args): QWidget.__init__(self, *args) self.tableWidget = CustomTable(self) self.data = my_array self.numRows = 5 self.numCols = 5 self.tableWidget.setRowCount(self.numRows) self.tableWidget.setColumnCount(self.numCols) self.tableWidget.addData(self.data) self.tableWidget.setCurrentCell(0, 0)#needed so selectedRanges does not fail initially layout = QVBoxLayout(self) layout.addWidget(self.tableWidget) self.setLayout(layout) class CustomTable(QTableWidget): def __init__(self, parent = None): QTableWidget.__init__(self, parent) if parent: self.parent = parent self.__initActions__() self.__initContextMenus__() def __initContextMenus__(self): self.setContextMenuPolicy(Qt.CustomContextMenu) self.connect(self, SIGNAL("customContextMenuRequested(QPoint)"), self.tableWidgetContext) def tableWidgetContext(self, point): '''Create a menu for the tableWidget and associated actions''' tw_menu = QMenu("Menu", self) tw_menu.addAction(self.pasteAction) tw_menu.addAction(self.copyAction) tw_menu.addAction(self.insRowAction) tw_menu.addAction(self.insColAction) tw_menu.exec_(self.mapToGlobal(point)) def addData(self, data, startrow=None, startcol = None): if startcol: sc = startcol#start column else: sc = 0 # n is for columns if startrow: sr = startrow else: sr = 0 m = sr #print "Row, Col Commit:", sr, n for row in data: n = sc for item in row: #print repr(str(item)) newitem = QTableWidgetItem(item) self.setItem(m, n, newitem) n+=1 m+=1 def __initActions__(self): self.pasteAction = QAction("Paste", self) self.pasteAction.setShortcut("Ctrl+V") self.addAction(self.pasteAction) self.connect(self.pasteAction, SIGNAL("triggered()"), self.pasteClip) self.copyAction = QAction("Copy", self) self.copyAction.setShortcut("Ctrl+C") self.addAction(self.copyAction) self.connect(self.copyAction, SIGNAL("triggered()"), self.copyCells) self.insColAction = QAction("Insert Column", self) self.addAction(self.insColAction) self.connect(self.insColAction, SIGNAL("triggered()"), self.addColumns) self.insRowAction = QAction("Insert Row", self) self.addAction(self.insRowAction) self.connect(self.insRowAction, SIGNAL("triggered()"), self.addRows) ############################### def addRows(self): selRange = self.selectedRanges()[0] topRow = selRange.topRow() bottomRow = selRange.bottomRow() for i in xrange(topRow, (bottomRow+1)): self.insRow(i) #print topRow, bottomRow #print selRange def addColumns(self): selRange = self.selectedRanges()[0] rightColumn = selRange.rightColumn() leftColumn = selRange.leftColumn() for i in xrange(leftColumn, (rightColumn+1)): self.insCol(i) #print topRow, bottomRow #print selRange def inCol(self, col = None): if type(col) is int: self.insertColumn(col) else: self.insertColumn(self.currentColumn()) def insRow(self, row = None): if type(row) is int: self.insertRow(row) else: self.insertRow(self.currentRow()) #################################### def pasteClip(self): cb = QApplication.clipboard() clipText = cb.text() t0 = time.time() clip2paste = self.splitClipboard(clipText) selRange = self.selectedRanges()[0]#just take the first range topRow = selRange.topRow() bottomRow = selRange.bottomRow() rightColumn = selRange.rightColumn() leftColumn = selRange.leftColumn() #test to ensure pasted area fits in table t1 = time.time() print "Clipboard split time:", (t1-t0) if (len(clip2paste)+topRow) >= self.rowCount(): self.setRowCount(len(clip2paste)+topRow) t2 = time.time() print "Row set time:", (t2-t1) if (len(clip2paste[0])+rightColumn) >= self.columnCount(): self.setColumnCount(len(clip2paste[0])+rightColumn) t3 = time.time() print "Column set time:", (t3-t2) self.addData(clip2paste, topRow, leftColumn) print "Data Add Time:", (time.time()-t3) def splitClipboard(self, clipText): #create list to be returned returnClip = [] #split by carriage return which makes the rows clipList = clipText.split("\r\n") #split each item by tab (aka columns) for item in clipList: returnClip.append(item.split("\t")) return returnClip ###################################### def copyCells(self): selRange = self.selectedRanges()[0]#just take the first range topRow = selRange.topRow() bottomRow = selRange.bottomRow() rightColumn = selRange.rightColumn() leftColumn = selRange.leftColumn() #item = self.tableWidget.item(topRow, leftColumn) clipStr = QString() for row in xrange(topRow, bottomRow+1): for col in xrange(leftColumn, rightColumn+1): cell = self.item(row, col) if cell: clipStr.append(cell.text()) else: clipStr.append(QString("")) clipStr.append(QString("\t")) clipStr.chop(1) clipStr.append(QString("\r\n")) cb = QApplication.clipboard() cb.setText(clipStr) if __name__ == "__main__": main()
_______________________________________________ PyQt mailing list PyQt@riverbankcomputing.com http://www.riverbankcomputing.com/mailman/listinfo/pyqt