PySide6从Slot返回自定义模型报错:属性非函数问题求助
解决QML调用Python Slot函数提示“不是函数”的问题
我在给QML的ListView组件配置详情窗口时,通过Qt.createComponent创建新Window并传递选中项信息,尝试将嵌套ListView的model绑定到带@Slot装饰的Python函数返回值(该函数返回自定义QAbstractListModel实例),但点击打开窗口时出现以下错误:
file:///home/cassidy/Projects/portmod/portmod/_gui/Manage/PackageDetailsWindow.qml:50: TypeError: Property 'get_local_flags_model' of object Config(0x55907ace9e70) is not a function
以下是具体的排查和修复方案:
1. 确保Config类继承自QObject
Python中带有@Slot装饰器的函数所在类必须继承QtCore.QObject,否则QML无法识别其为可调用的槽函数。修改Config类定义:
from PySide6.QtCore import QObject, Slot class Config(QObject): def __init__(self): super().__init__() # 其他初始化逻辑 @Slot(str, result=QObject) def get_local_flags_model(self, atom: str) -> FlagListModel: return FlagListModel(get_local_flags(Atom(atom)))
2. 确认Config实例已注册到QML上下文
要让QML访问config对象,必须在Python代码中将其注入QML上下文环境:
from PySide6.QtQml import QQmlApplicationEngine engine = QQmlApplicationEngine() config_instance = Config() # 将config实例注册为QML全局变量 engine.rootContext().setContextProperty("config", config_instance) engine.load("main.qml")
若缺少这一步,QML中的config变量可能指向无效对象,导致找不到目标槽函数。
3. 验证Slot装饰器参数匹配度
确保@Slot装饰器的参数与函数签名完全一致:
- 输入参数类型为
str(与函数的atom参数类型对应) result指定返回值类型为QObject(因为FlagListModel继承自QAbstractListModel,而后者是QObject的子类)
4. 修复QML模型角色引用错误
原QML代码中model.check的引用无效,因为自定义模型未定义对应角色。需补充角色定义并修正QML引用:
第一步:扩展FlagListModel的角色定义
from typing import Any, Dict, Tuple, Union from PySide6.QtCore import QAbstractListModel, QModelIndex, Qt, QObject class FlagListModel(QAbstractListModel): # 自定义角色 CheckRole = Qt.ItemDataRole.UserRole + 1 DescriptionRole = Qt.ItemDataRole.UserRole + 2 def __init__(self, use_flags: Dict[str, Tuple[bool, str]]): super().__init__() self._data = use_flags # 角色名称映射,供QML识别 self._roles = { Qt.ItemDataRole.DisplayRole: b"display", self.CheckRole: b"check", self.DescriptionRole: b"description" } def roleNames(self) -> Dict[int, bytes]: return self._roles def rowCount(self) -> int: return len(self._data) def data( self, index: Union[QModelIndex, QtCore.QPersistentModelIndex], role: int, ) -> Any: key = list(self._data.keys())[index.row()] value = self._data[key] if role == Qt.ItemDataRole.DisplayRole: return key elif role == self.CheckRole: return Qt.CheckState.Checked if value[0] else Qt.CheckState.Unchecked elif role == self.DescriptionRole: return value[1] return None
第二步:修正QML中的Delegate引用
delegate: CheckDelegate { text: model.display checkState: model.check width: ListView.view.width - 20 }
5. 延迟模型赋值(可选)
若窗口初始化时detailsWindow.atom尚未完成赋值,可能导致函数调用失败。可通过Component.onCompleted延迟绑定:
ListView { id: useListView clip: true width: parent.width height: parent.height Component.onCompleted: { model = config.get_local_flags_model(detailsWindow.atom) } ScrollBar.vertical: ScrollBar {} }
内容的提问来源于stack exchange,提问作者PopeRigby
相关产品推荐
相关产品推荐

