You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

QListWidgetItem内Widget在InternalMove拖拽后消失的解决方法

QListWidget内部拖拽时ItemWidget消失的解决方法

我通过.setItemWidget()方法向QListWidget中添加QLabel,并设置了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_widget = QListWidget()
    list_widget.setFixedHeight(400)
    list_widget.setDragDropMode(QListWidget.DragDropMode.InternalMove)

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

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

    list_widget.show()

    sys.exit(app.exec())

编辑

查阅.setItemWidget()的文档后发现说明:

该函数仅应用于在列表部件项的位置显示静态内容。如果要显示自定义动态内容或实现自定义编辑器部件,请使用QListView并子类化QStyledItemDelegate。

我想知道这是否与当前问题相关,此处的“静态内容”指什么,QLabel是否属于“动态内容”?

编辑#2

问题根源在于dropEvent()会调用dropMimeData(),而该方法会创建全新的项(触发rowsInserted)——这对内部项移动来说是不合理的,因为拖拽项中设置的部件不会被序列化存储到mimedata中,导致部件与项解耦。dropMimeData()原本是为跨列表拖拽场景设计的。

可行的解决方法是:在QListWidget.mimeData()中通过QMimeData.setData()将部件的关键数据手动序列化,以自定义MIME类型存储;然后在QListWidget.dropMimeData()中完成拖拽后,重新创建部件并绑定到对应项上。示例代码如下:

from PyQt5.QtWidgets import (
    QApplication, QLabel, QStyle,
    QListWidget, QListWidgetItem
)
from PyQt5.QtCore import QSize, QMimeData, QBuffer, QIODevice
from PyQt5.QtGui import QPixmap
import pickle
import sys

class ListWidget(QListWidget):
    def mimeData(self, items:list[QListWidgetItem]) -> QMimeData:
        mimedata = QListWidget.mimeData(self, items)
        # 序列化标签中的Pixmap
        custom_data = []
        for item in items:
            label:QLabel = self.itemWidget(item)
            buff = QBuffer()
            buff.open(QIODevice.OpenModeFlag.WriteOnly)
            label.pixmap().save(buff, 'PNG')
            buff.close()
            custom_data.append(buff.data())
        mimedata.setData('application/custommime', pickle.dumps(custom_data))
        return mimedata 


    def dropMimeData(self, index:int, mimedata:QMimeData, action) -> bool:
        result = QListWidget.dropMimeData(self, index, mimedata, action)
        # 重新创建标签并绑定Pixmap
        if mimedata.hasFormat('application/custommime'):
            for i, data in enumerate(
                    pickle.loads(mimedata.data('application/custommime')), 
                    start=index):
                pixmap = QPixmap()
                pixmap.loadFromData(data, 'PNG')
                label = QLabel()
                label.setPixmap(pixmap)
                self.setItemWidget(self.item(i), label)
        return result


if __name__ == '__main__':
    app = QApplication(sys.argv)
    list_widget = ListWidget()
    list_widget.setFixedHeight(400)
    list_widget.setDragDropMode(QListWidget.DragDropMode.InternalMove)
    list_widget.setSelectionMode(QListWidget.SelectionMode.ExtendedSelection)

    for i in range(8):
        item = QListWidgetItem()
        item.setSizeHint(QSize(40, 40))
        list_widget.addItem(item)
        label = QLabel()
        label.setPixmap(list_widget.style().standardIcon(
            QStyle.StandardPixmap.SP_DialogOkButton + i).pixmap(QSize(40,40)))
        list_widget.setItemWidget(item, label)

    list_widget.show()
    sys.exit(app.exec())

内容的提问来源于stack exchange,提问作者user12653758

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 02:35:19