动态控制 QItemDelegate 的大小

Posted

技术标签:

【中文标题】动态控制 QItemDelegate 的大小【英文标题】:controlling size of QItemDelegate dynamically 【发布时间】:2016-08-11 03:47:33 【问题描述】:

我有几个关于QItemDelegates 在QListView 中的大小的问题:

我有一个使用QItemDelegate 的QListView,它在委托的自定义paint() 方法中呈现一个小部件,如下所示:

self.thumbnail = MyCustomWidget()
self.thumbnail.render(painter, QtCore.QPoint(option.rect.x(), option.rect.y()))

然而,这会在 QListView 中显示具有 250x260 图像的项目,即使 MyCustomWidget().sizeHint() 是 250x250 并且它的 maximumSize() 也返回 250x250。

我发现罪魁祸首是 QListView 的 spacing,我设置为 10。如果我将 spacing 设置为 100,我仍然会得到 QItemDelegates 大小为 250x260,但如果我只是不要使用setSpacing(),它会按预期以250x250 呈现。 spacing 似乎改变了传递给paint方法的option.rect,导致大小不正确。 我确实需要那个spacing,所以我有点困惑为什么QListView 的间距会改变QItemDelegates 的大小?这是一个错误吗?

我可以通过首先渲染QPixmap 来解决这个问题,然后让painter 绘制QPixmap 而不是直接渲染到painter:

self.thumbnail = MyCustomWidget()
pixmap = QtGui.QPixmap(self.thumbnail.size())
self.thumbnail.render(pixmap)
painter.drawPixmap(option.rect.topLeft(), pixmap)

这会产生我需要的 250x250 图像,但我不明白为什么当我使用 setSpacing 时第一种方法无法呈现正确的尺寸?!

现在,更大的挑战是如何通过QSlider 动态缩放QItemDelegate 的大小: 我在QListView 中有一个QSlider,它应该缩放项目,以便用户可以选择在当前视图中查看更小但更多的项目。我测试了 MyCustomWidget() 独立实例的大小调整,它工作得很好。

但是,代表不会按预期进行扩展。这是我的委托代码: 类委托(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

在QListView我使用这个槽连接到滑块的valueChanges信号:

def scaleThumbnails(self, value):
    self.itemDelegate().setScaleValue(value)
    self.update()

结果是QSlider 将裁剪QItemDelegates 但不会缩放它们,因为QItemDelegate 的sizeHint() 仅在QListView 首次显示时被调用。 此外,我需要确保当小部件(最终)缩小时,QListView 的布局被重新计算,并且更多的项目适合可见区域。

简而言之,我的问题是:

    如何在QListView 内动态缩放QItemDelegates? 如何在代理大小更改后强制QListView 重新计算其布局?

编辑:至于问题 2:QAbstractItemView.doItemsLayout 似乎可以解决问题。不过仍然想知道问题 1

谢谢, 坦率的

【问题讨论】:

【参考方案1】:

原来问题在于我的代码上下文,而不是委托。 我在将小部件渲染为像素图之前对其进行了缩放,这当然可以使编辑器正确缩放,但在项目未处于编辑状态时则不能。 所以解决方案只是在从小部件渲染后缩放像素图,例如:

scaledPixmap = pixmap.scaled(pixmap.size() * self.scaleValue / 100.0)
painter.drawPixmap(option.rect.topLeft(), scaledPixmap)

【讨论】:

以上是关于动态控制 QItemDelegate 的大小的主要内容,如果未能解决你的问题,请参考以下文章

Qt入门教程数据模型篇QItemDelegate条目代理

Qt入门教程数据模型篇QItemDelegate条目代理

如何使用 QItemDelegate 更改 QTableView 文本颜色?

QItemDelegate 复选框

强制 QItemDelegate 重绘

样式不适用于 QItemDelegate