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

QListWidget.data()切换含Action数据的Task Item时程序崩溃求助

问题:切换含Action数据的Task Item时程序崩溃

每个Task Item通过QListWidgetItem[]存储Action列表,点击Task Item时,Action视图区域从taskitem.data()重新加载数据。当所有Task Item均无Action数据时切换正常;仅存在一个含Action数据的Task Item时也无崩溃,但切换回该含Action数据的Task Item时程序崩溃。

复现步骤

  • 添加一个Task Item并为其添加三个Action Item,多次点击该Task Item,程序无崩溃;
  • 添加第二个Task Item且不为其添加任何Action Item;
  • 切换回第一个含Action数据的Task Item时,程序崩溃。

原代码

# This Python file uses the following encoding: utf-8
import sys
from typing import List

from PySide6.QtCore import Qt
from PySide6.QtWidgets import QApplication, QMainWindow, QListWidgetItem

# Important:
# You need to run the following command to generate the ui_form.py file
#     pyside6-uic form.ui -o ui_form.py, or
#     pyside2-uic form.ui -o ui_form.py
from ui_form import Ui_MainWindow

class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        item1 = QListWidgetItem("task 1")
        item2 = QListWidgetItem("task 2")

        self.ui.listWidget.addItem(item1)
        self.ui.listWidget.addItem(item2)

        action_data_list: List[QListWidgetItem] = []
        action_data_list_2: List[QListWidgetItem] = []
        action_data_list.append(QListWidgetItem("action 1"))
        action_data_list.append(QListWidgetItem("action 2"))

        self.ui.listWidget_2.addItem(action_data_list[0])
        self.ui.listWidget_2.addItem(action_data_list[1])

        item1.setData(Qt.UserRole, action_data_list)
        item2.setData(Qt.UserRole, action_data_list_2)

        self.ui.listWidget.itemClicked.connect(self.reload)

    # reload item to listWidget_2
    def reload(self):
        current_item = self.ui.listWidget.currentItem()
        action_data_list = current_item.data(Qt.UserRole)
        for i in range(self.ui.listWidget_2.count()):
            self.ui.listWidget_2.takeItem(0)
        self.ui.listWidget_2.clear()
        for action_data in action_data_list:
            self.ui.listWidget_2.addItem(action_data)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    widget = MainWindow()
    widget.show()
    sys.exit(app.exec())

问题原因

QListWidgetItem不能被重复添加到QListWidget(包括同一列表多次)。第一次加载action_data_list到listWidget_2后,这些Item的父控件已经是listWidget_2。切换到无数据的Task Item时,通过takeItem和clear将这些Item从listWidget_2中移除,但Item的父控件关联并未完全清理。当再次尝试将这些Item添加回listWidget_2时,Qt的内部机制不允许重复添加同一Item,直接触发崩溃。

修复方案

方案1:存储Action文本数据而非QListWidgetItem对象

核心思路是分离数据与UI控件,存储Action的文本内容,每次加载时创建新的QListWidgetItem,避免复用同一Item对象。

修改后的完整代码:

# This Python file uses the following encoding: utf-8
import sys
from typing import List

from PySide6.QtCore import Qt
from PySide6.QtWidgets import QApplication, QMainWindow, QListWidgetItem

# Important:
# You need to run the following command to generate the ui_form.py file
#     pyside6-uic form.ui -o ui_form.py, or
#     pyside2-uic form.ui -o ui_form.py
from ui_form import Ui_MainWindow

class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        item1 = QListWidgetItem("task 1")
        item2 = QListWidgetItem("task 2")

        self.ui.listWidget.addItem(item1)
        self.ui.listWidget.addItem(item2)

        # 存储文本数据而非QListWidgetItem对象
        action_data_list: List[str] = ["action 1", "action 2"]
        action_data_list_2: List[str] = []

        # 初始化加载第一个Task的Action
        for text in action_data_list:
            self.ui.listWidget_2.addItem(QListWidgetItem(text))

        item1.setData(Qt.UserRole, action_data_list)
        item2.setData(Qt.UserRole, action_data_list_2)

        self.ui.listWidget.itemClicked.connect(self.reload)

    # reload item to listWidget_2
    def reload(self):
        current_item = self.ui.listWidget.currentItem()
        action_data_list = current_item.data(Qt.UserRole)
        # 清空现有Action列表
        self.ui.listWidget_2.clear()
        # 根据文本数据创建新的QListWidgetItem并添加
        for action_text in action_data_list:
            self.ui.listWidget_2.addItem(QListWidgetItem(action_text))

if __name__ == "__main__":
    app = QApplication(sys.argv)
    widget = MainWindow()
    widget.show()
    sys.exit(app.exec())

方案2:复用Item时手动管理父控件(不推荐)

如果必须复用QListWidgetItem对象,需要在移除时将Item的父控件设置为None,但这种方式容易引入其他问题,不如方案1简洁可靠,示例代码如下:
在reload函数的移除步骤后添加:

for i in range(self.ui.listWidget_2.count()):
    item = self.ui.listWidget_2.takeItem(0)
    item.setParent(None)  # 手动解除父控件关联

但依旧不建议使用此方案,因为Qt的UI控件生命周期管理复杂,存储数据而非UI对象是更合理的实践。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 18:03:23