The problem is that setCellWidget
is just a convenience method: it is not optimized for adding hundreds of widgets to a single table, and so the slow-down in performance that you are seeing is inevitable.
To get the best performance, you will have to create a custom delegate and use QStyle
to draw the button in its paint
method. Of course, this also means you will have to implement all the mouse-handling and so forth yourself as well.
To give you an idea of what's involved, some example code can be found here.
EDIT:
Here is a test script based on the original code in the question. For me, this completes in a fraction of a second for 325 rows:
import time
from PyQt4 import QtCore, QtGui
class MyPushButton(QtGui.QPushButton):
def __init__(self, value1, value2, value3, main):
super(MyPushButton, self).__init__()
self.__value1 = value1
self.__value2 = value2
self.__value3 = value3
self.__main = main
self.connect(self, QtCore.SIGNAL('clicked()'), self, QtCore.SLOT("triggerOutput()"))
@QtCore.pyqtSlot()
def triggerOutput(self):
self.__main.emit(QtCore.SIGNAL("DoSomethingSignal(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)"), self.__value1 , self.__value2 , self.__value3)
class Window(QtGui.QWidget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.table = QtGui.QTableWidget(self)
self.button = QtGui.QPushButton('Populate', self)
self.button.clicked.connect(self.handleButton)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.table)
layout.addWidget(self.button)
def handleButton(self):
self.populateTable(325)
def populateTable(self, numberOfRows):
self.table.setVisible(0)
self.table.setSortingEnabled(0)
self.table.setRowCount(numberOfRows)
self.table.setColumnCount(10)
for i in range(0, numberOfRows):
for colNum in range(10):
text = 'Text(%d, %d)' % (i, colNum)
self.table.setItem(i, colNum, QtGui.QTableWidgetItem(text))
button = MyPushButton(1, 2, 3, self)
button.setText("Click")
startTime = time.time()
self.table.setCellWidget(i,9, button)
print i," self.tableWidget.setCellWidget(i,9, button) time: ", time.time() - startTime
self.table.resizeColumnsToContents()
self.table.setSortingEnabled(1)
self.table.sortByColumn(0, QtCore.Qt.AscendingOrder)
self.table.setVisible(1)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.setGeometry(600, 300, 1000, 600)
window.show()
sys.exit(app.exec_())
UPDATE:
I'm not sure exactly what you want, but the row resizing issue can probably be resolved by setting the resize-mode to Fixed
before populating the table, and then setting it to ResizeToContents
afterwards:
...
self.tableWidget.horizontalHeader().setResizeMode(QtGui.QHeaderView.Fixed)
self.tableWidget.verticalHeader().setResizeMode(QtGui.QHeaderView.Fixed)
# populate table
self.table.verticalHeader().setResizeMode(QtGui.QHeaderView.ResizeToContents)
self.table.resizeColumnsToContents()
self.tableWidget.setSortingEnabled(1)
self.tableWidget.sortByColumn(0, QtCore.Qt.AscendingOrder)