【问题标题】:Widget inside QListWidgetItem disappears after internal moveQListWidgetItem 内的小部件在内部移动后消失
【发布时间】:2022-11-01 11:14:56
【问题描述】:

我有一个QListWidget,它由QLabel 通过.setItemWidget() 和一个拖放模式InternalMove 填充,当我在列表中移动一个项目时,它的标签会消失。

我该如何解决这个问题?

重现的最小示例

from PyQt5.QtWidgets import (
    QApplication, QLabel, QStyle,
    QListWidget, QListWidgetItem
)
from PyQt5.QtCore import QSize
import sys


if __name__ == '__main__':
    app = QApplication(sys.argv)

    list = QListWidget()
    list.setFixedHeight(400)
    list.setDragDropMode(QListWidget.DragDropMode.InternalMove)

    for _ in range(8):
        item = QListWidgetItem()
        item.setSizeHint(QSize(40, 40))
        list.addItem(item)

        label = QLabel()
        label.setPixmap(list.style().standardIcon(
            QStyle.StandardPixmap.SP_ArrowUp).pixmap(QSize(40,40)))
        list.setItemWidget(item, label)

    list.show()

    sys.exit(app.exec())

【问题讨论】:

  • 我在过去看到过这种行为as partially reported in this question,但我从来没有能够始终如一地重现它:大多数时候它都有效,但是有时它做你所展示的。值得注意的是,如果您尝试调整窗口大小,小部件会再次出现,因此索引小部件的几何形状似乎存在问题。也许在 dropEvent 覆盖上强制延迟 updateGeometries 可能会有所帮助,但我不太确定,因为如前所述,我只能完全随机地重现它。
  • @musicamante 对我来说,如果我将最后一个项目拖放到QListWidget 的空白区域,如我发布的图片所示,我一直在挖掘它,因为我已经发布了它似乎小部件只在从QListWidget 的模型中删除一行,基本上是在QListWidget.model().rowsRemoved 被释放时。
  • 但这不应该是你的情况,因为索引没有被删除,而只是被移动: QListWidget 在内部通过调用 beginMoveRows() 和相关函数开始,所以小部件与它一起移动,它只是没有正确更新。由于您始终能够重现问题,我们可以尝试了解问题出在哪里:首先创建一个打印所有项目小部件的几何形状的函数,并在移动行时使用延迟的 QTimer 调用它:list.model().rowsMoved.connect(lambda: QTimer.singleShot(100, somefunc))
  • 该函数可能只是一个简单的for i in range(list.count()):print(list.itemWidget(list.item(i)).geometry())。这显然是基于您上面的示例,为所有项目设置了一个小部件。查看几何图形是否一致(尤其是最后一个,即已移至末尾的项目):尺寸应全部相同,而 y 坐标应始终为先前高度的总和。如果是,则将上面的函数更改为检查可见性的函数 (list.itemWidget(list.item(i)).isVisible())。如果没有,请在您的问题中发布输出。
  • @musicamante 这就是问题所在,当我在已移动的item 上调用itemWidget() 时,结果是None 基本上item 本身仍在列表中,但widget 设置为setItemWidget() 得到解耦。

标签: python-3.x pyqt5 drag-and-drop qt5 qlistwidget


【解决方案1】:

这是由仅影响相当新版本的 Qt 错误引起的。我可以在使用 Qt-5.15.6 和 Qt-6.4.0 时始终如一地重现它 - 但不是例如Qt-5.12.1。该问题似乎与QTBUG-100128 密切相关。

AFAICS,这只影响将视图中的当前最后一个项目拖放到空白区域。其他项目和多项选择不受影响。这建议采用以下解决方法:

class ListWidget(QListWidget):
    def dropEvent(self, event):
        if (self.currentRow() < self.count() - 1 or
            self.itemAt(event.pos()) is not None):
            super().dropEvent(event)

list = ListWidget()
...

或使用事件过滤器:

class Monitor(QObject):
    def eventFilter(self, source, event):
        if event.type() == QEvent.Drop:
            view = source.parent()
            if (view.currentRow() == view.count() - 1 and
                view.itemAt(event.pos()) is None):
                return True
        return super().eventFilter(source, event)

monitor = Monitor()
list = QListWidget()
list.viewport().installEventFilter(monitor)
...

【讨论】:

    猜你喜欢
    • 2018-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-23
    • 2010-10-30
    相关资源
    最近更新 更多