I have a couple of questions regarding the sizes of QItemDelegates in a QListView:
I have a QListView using a QItemDelegate which renders a widget in the delegate's custom paint() method like so:
self.thumbnail = MyCustomWidget()
self.thumbnail.render(painter, QtCore.QPoint(option.rect.x(), option.rect.y()))
This, however, shows the item with a 250x260 image in a QListView, even though the MyCustomWidget().sizeHint() is 250x250 and it's maximumSize() returns 250x250 as well.
I found that the culprit is the QListView's spacing, which I had set to 10. If I set the spacing to 100, I still get the QItemDelegates size of 250x260, but if I just don't use setSpacing() at all it renders as expected at 250x250. The spacing seems to alter the option.rect that is passed into the paint method, causing the incorrect size. I do need that spacing, so I'm a bit confused why the QListView's spacing alters the QItemDelegates's size? Is this a bug?
I can work around this by rendering a QPixmap first, then have the painter draw the QPixmap instead of rendering to the painter directly:
self.thumbnail = MyCustomWidget()
pixmap = QtGui.QPixmap(self.thumbnail.size())
self.thumbnail.render(pixmap)
painter.drawPixmap(option.rect.topLeft(), pixmap)
This yields 250x250 images which is what I need, but I don't understand why the first method doesn't render the correct size when I use setSpacing?!
Now, the bigger challenge is how to dynamically scale the size of the QItemDelegate's via a QSlider: I have a QSlider in the QListView that is supposed to scale the items so the user can chose to see smaller but more items in the current view. I tested the resizing of a standalone instance of MyCustomWidget() and it works just fine.
However, the delegates won't scale as expected. This is my delegate code: class Delegate(QtGui.QItemDelegate):
def __init__(self, parent = None):
super(Delegate, self).__init__(parent)
self.scaleValue = 100 # size in percent (as returned by QSlider)
def paint(self, painter, option, index):
proxyModel = index.model()
item = proxyModel.sourceModel().itemFromIndex(proxyModel.mapToSource(index))
self.thumbnail = ElementThumbnail(item)
self.thumbnail.scale(self.scaleValue)
pixmap = QtGui.QPixmap(self.thumbnail.size())
self.thumbnail.render(pixmap)
painter.drawPixmap(option.rect.topLeft() * self.scaleValue / 100.0, pixmap)
super(Delegate, self).paint(painter, option, index)
def setScaleValue(self, value):
self.scaleValue = value
def sizeHint(self, option, index):
return ElementThumbnail.thumbSize * self.scaleValue / 100.0
and in the QListView I am using this slot connected to the slider's valueChanges signal:
def scaleThumbnails(self, value):
self.itemDelegate().setScaleValue(value)
self.update()
The result is that the QSlider will crop the QItemDelegates but not scale them, because the QItemDelegate's sizeHint() is only called when the QListView is first shown. Additionally, I need to make sure that when the widgets are (eventually) scaled down, the layout of QListView is recalculated and more items are fit inside the visible area.
So in a nutshell my questions are:
- How can I scale QItemDelegates dynamically inside a QListView?
- How can I force the QListView to recalculate it's layout after the delegate size has been changed?
edit: as for issue 2: QAbstractItemView.doItemsLayout seems to do the trick. Still wondering about issue 1 though
Thanks, frank