PyQt5实现QML嵌套可展开子菜单 修改折叠状态UI无响应
问题根因
你的判断完全正确:
- 调用
collapseEditInputsMenu修改isCollapsed字段时,仅修改了Python端内部存储的字典值,没有触发QAbstractListModel规定的dataChanged变更通知,QML视图层感知不到数据变化,自然不会响应展开/折叠操作。 - QML内置
ListModel调用setProperty修改属性时会自动发送变更信号,因此内置模型版本运行正常,自定义PyQt模型必须手动触发通知才能同步UI。 - 代码还存在一个隐藏bug:
appendRow方法中将子模型赋值给self.subItem实例属性,每次新增行都会覆盖之前的子模型引用,多菜单场景下会出现子项数据错乱。
修复方案
1. 修改collapseEditInputsMenu方法,增加数据变更通知
找到MyListModel类下的collapseEditInputsMenu方法,修改为如下代码:
@pyqtSlot(int, str) def collapseEditInputsMenu(self, index, modelIndexName): self.itemNames[index][modelIndexName] = not self.itemNames[index][modelIndexName] # 构造对应行的模型索引,指定变更的角色为CollapsedRole,触发UI刷新 changed_index = self.index(index, 0) self.dataChanged.emit(changed_index, changed_index, [MyListModel.CollapsedRole]) print(f"From Backend: {self.itemNames}")
2. 修复appendRow的子模型引用覆盖bug
将appendRow方法中挂载到实例的子模型改为局部变量,避免覆盖历史数据:
@pyqtSlot(str, bool) def appendRow(self, name, isCollapsed): # 改用局部变量存储子模型,不要挂载到self上 sub_item = MySubListModel() sub_item.addRow() self.beginInsertRows(QModelIndex(), self.rowCount(), self.rowCount()) self.itemNames.append({'assetName': name, 'subItems': sub_item, 'isCollapsed': isCollapsed}) self.endInsertRows() print(self.itemNames) print(sub_item.subItemParams)
可选优化项
- 后续如果需要修改子列表
MySubListModel内的字段(比如修改cellSize值),同样需要在修改值后调用子模型的dataChanged信号,否则子项UI不会同步刷新。 - 建议调整后端对象注册逻辑,在加载QML之前通过
rootContext注入上下文属性,避免启动初期绑定为空的异常:
修改MainWindow初始化逻辑:
调整后可以删除QML根节点下的def __init__(self): app = QGuiApplication(sys.argv) self.engine = QQmlApplicationEngine() self.engine.quit.connect(app.quit) # 先注册后端属性,再加载QML文件 app_backend = Backend() self.engine.rootContext().setContextProperty("backendObjectInQML", app_backend) self.engine.load("main.qml") sys.exit(app.exec())property QtObject backendObjectInQML声明,所有引用位置直接用backendObjectInQML替换myApplicationWindow.backendObjectInQML即可,绑定稳定性更高。
内容的提问来源于stack exchange,提问作者Enes
相关产品推荐
相关产品推荐

