是否可以通过QML从PySide2插槽(服务调用)中获取对象列表?

时间:2019-08-05 16:23:49

标签: python python-3.x qml pyside2

我正在尝试将现有的PySide2 / QtWidgets应用程序转换为PySide2 / QML。我试图通过QML MouseArea点击来从Python服务调用中获取自定义对象的列表。

我目前有一个主脚本(main.py),该脚本启动一个包含我的QML(包含在QQuickView中)的main.qml。它还为我的模型(在Role中定义的role.py注册了一个自定义类型,并向视图的根上下文公开了我的服务类的一个实例(包含在mock_role_service.py中)。

我的QML正确显示,我可以单击我的MouseArea,但是似乎没有得到List[Role]元组,而不是返回QVariant。更具体地说,QVariant(PySide::PyObjectWrapper, )

相关文件:
mock_role_service.py

class MockRoleService(QObject):
    def __init__(self):
        super().__init__()

        self.next_id = 5
        self.records = {
            1: Role(id_=1,
                    name='Admin'),
            2: Role(id_=2,
                    name='User')
        }

    @Slot(result=list)
    def find_all(self) -> List[Role]:
        return list(self.records.values())

main.py

...
app = QGuiApplication(sys.argv)
qmlRegisterType(Role, 'Models', 1, 0, 'Role')

view = QQuickView()
url = QUrl('Views/main.qml')
view.setSource(url)
view.setResizeMode(QQuickView.SizeRootObjectToView)

role_service = MockRoleService()
view.rootContext().setContextProperty("roleService", role_service)

if view.status() == QQuickView.Error:
    sys.exit(-1)

view.show()

sys.exit(app.exec_())

main.qml

...
MouseArea {
    onClicked: {
        console.log(roleService.find_all())
        for (role in roleService.find_all()) {
            console.log(role.get_id())
        }
    }
}
...

第一次console.log()调用的结果是QVariant(PySide::PyObjectWrapper, ),并且永远不会进入for循环。

我只能在线找到几个类似的问题,到目前为止,它们的常见解决方案(例如在this答案中)是将值设置为类的属性并指定它的类型为QVariantList。这是因为PySide2显然取消了类似QVariant的类型,所以我无法正确指定广告位的结果类型。

但是,我不确定此解决方案是否适合这种情况,因为我正在处理服务对象。在服务类上设置属性以保存返回值的感觉很脆弱。没有其他方法可以做到这一点吗?

1 个答案:

答案 0 :(得分:1)

由于您没有提供Role类,所以我将假定它是QObject,如果不是,那么您必须修改您的类,以便QML无法识别它,除了仅信号,qproperties和slot是在QML中得到认可。

另一方面,仅当您要在已注册类的QML中创建对象时,才需要qmlRegisterType,在您的情况下,我认为没有必要。

最后,如果您要将列表传递给QML,则必须使用签名'QVariantList'(如果列表有效,则在PyQt中使用)。

from typing import List
from PySide2.QtCore import Property, QObject, QUrl, Signal, Slot
from PySide2.QtGui import QGuiApplication
from PySide2.QtQml import qmlRegisterType
from PySide2.QtQuick import QQuickView


class Role(QObject):
    idChanged = Signal()
    nameChanged = Signal()

    def __init__(self, id_, name, parent=None):
        super().__init__(parent)

        self._id = id_
        self._name = name

    def get_id(self) -> int:
        return self._id

    def set_id(self, id_) -> None:
        if self._id != id_:
            self._id = id_
            self.idChanged.emit()

    def get_name(self) -> str:
        return self._name

    def set_name(self, name) -> None:
        if self._name != name:
            self._name = name
            self.nameChanged.emit()

    id_ = Property(int, fget=get_id, fset=set_id, notify=idChanged)
    name = Property(str, fget=get_name, fset=set_name, notify=nameChanged)


class MockRoleService(QObject):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.records = {
            1: Role(id_=1, name="Admin", parent=self),
            2: Role(id_=2, name="User", parent=self),
        }

    @Slot(result="QVariantList")
    def find_all(self) -> List[Role]:
        return list(self.records.values())


if __name__ == "__main__":
    import os
    import sys

    app = QGuiApplication(sys.argv)
    # qmlRegisterType(Role, "Models", 1, 0, "Role")
    view = QQuickView()
    current_dir = os.path.dirname(os.path.realpath(__file__))
    url = QUrl.fromLocalFile(os.path.join(current_dir, "Views/main.qml"))
    view.setSource(url)
    view.setResizeMode(QQuickView.SizeRootObjectToView)

    role_service = MockRoleService()
    view.rootContext().setContextProperty("roleService", role_service)

    if view.status() == QQuickView.Error:
        sys.exit(-1)

    view.show()

    sys.exit(app.exec_())
import QtQuick 2.12

Item{
    width: 640
    height: 480
    MouseArea {
        anchors.fill: parent
        onClicked: {
            var roles = roleService.find_all()
            console.log(roles)
            for (var i in roles) {
                var role = roles[i]
                console.log(role.id_, role.name);
            }
        }
    }
}

输出:

qml: [Role(0x55b5385589b0),Role(0x55b538558d40)]
qml: 1 Admin
qml: 2 User