I am writing an application that makes use of a custom QWidget in place of regular listitems or delegates in PyQt. I have followed the answer in Render QWidget in paint() method of QWidgetDelegate for a QListView -- among others -- to implement a QTableModel with custom widgets. The resulting sample code is at the bottom of this question. There are some problems with the implementation that I do not know how to solve:
- Unloading items when they are not being displayed. I plan to build my application for a list that will have thousands of entries, and I cannot keep that many widgets in memory.
- Loading items that are not yet in view or at least loading them asynchronously. Widgets take a moment to render, and the example code below has some obvious lag when scrolling through the list.
- When scrolling the list in the implementation below, each newly loaded button when loading shows up at the top left corner of the QListView for a split second before bouncing into position. How can that be avoided?
--
import sys
from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import Qt
class TestListModel(QtCore.QAbstractListModel):
def __init__(self, parent=None):
QtCore.QAbstractListModel.__init__(self, parent)
self.list = parent
def rowCount(self, index):
return 1000
def data(self, index, role):
if role == Qt.DisplayRole:
if not self.list.indexWidget(index):
button = QtGui.QPushButton("This is item #%s" % index.row())
self.list.setIndexWidget(index, button)
return QtCore.QVariant()
if role == Qt.SizeHintRole:
return QtCore.QSize(100, 50)
def columnCount(self, index):
pass
def main():
app = QtGui.QApplication(sys.argv)
window = QtGui.QWidget()
list = QtGui.QListView()
model = TestListModel(list)
list.setModel(model)
list.setVerticalScrollMode(QtGui.QAbstractItemView.ScrollPerPixel)
layout = QtGui.QVBoxLayout(window)
layout.addWidget(list)
window.setLayout(layout)
window.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()