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 [email protected]
http://www.riverbankcomputing.com/mailman/listinfo/pyqt