Qt for python 的属性系统使用,并注册python到qml使用

Qt for python 的属性系统使用,并注册python到qml使用,第1张

文章目录
    • 前言
    • demo示例
      • 第一种实现方式
      • 第二种实现方式
    • 总结

前言

今天被这个python类注册给qml调用给搞晕了,本来写对了代码,但是死活不生效,废了好长时间才找到原因,就是因为某个原因,导致报如下错误:

QWindowsContext: OleInitialize() failed:  "COM error 0xffffffff80010106 RPC_E_CHANGED_MODE (Unknown error 0x080010106)"

不说这个了,说下正题,如何让pyside中的python类对象在qml中调用呢? 就像之前调用C++一样灵活,答案毋庸置疑肯定是可以的,现在网上很多都不知道怎么用,其实方法是和C++如何被Qml调用一样,首先python必须是继续于QObject,这点是必须的,其次就是调用QQmlApplicationEngine方法来注册上下文,如下代码:

engine.rootContext().setContextProperty("qml_c_object", xxxxx)
demo示例

这个过程已经说了,其实最重要的还是代码,下面我贴出两种方式的代码,记住,无论哪种方式,qml想要使用python类,只能通过属性,信号,槽,这三种方式,下面我说的就是如何通过属性来识别:

第一种实现方式

第一种方式是直接通过@Property实现调用

main.py文件内容如下:

import sys

from PySide2.QtCore import QObject, Signal, Property, QUrl
from PySide2.QtGui import QGuiApplication
from PySide2.QtQml import QQmlApplicationEngine

class Backend(QObject):
    textChanged = Signal(str)

    def __init__(self, parent=None):
        QObject.__init__(self, parent)
        self.m_text = ""

    @Property(str, notify=textChanged)
    def text(self):
        return self.m_text

    @text.setter
    def setText(self, text):
        if self.m_text == text:
            return
        self.m_text = text
        self.textChanged.emit(self.m_text)   

if __name__ == '__main__':
    app = QGuiApplication(sys.argv)
    backend = Backend()

    backend.textChanged.connect(lambda text: print(text))
    engine = QQmlApplicationEngine()
    engine.rootContext().setContextProperty("backend", backend)
    engine.load(QUrl.fromLocalFile('main.qml'))
    if not engine.rootObjects():
        sys.exit(-1)
    sys.exit(app.exec_())

main.qml文件如下:

import QtQuick 2.10
import QtQuick.Controls 2.1
import QtQuick.Window 2.2

ApplicationWindow {
    title: qsTr("Test")
    width: 640
    height: 480
    visible: true
    Column{
        TextField{
            id: tf
            text: "Hello"
        }
        Button {
            text: qsTr("Click Me")
            onClicked: backend.text = tf.text
        } 
    }
}
第二种实现方式

第二种方式,直接调用Property宏方式显示注明方法名称,和在C++使用Q_PROPERTY() 一样,不过python这边需要接收一个返回值,然后qml调用识别的是返回值名称,下面看代码实现,就一目了然了!

main.py内容如下:

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_())

main.qml文件如下:

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
总结

可以看到无论第一种还是第二种方式都是可以注册,第二种采用了QQuickView 方式加载,也是能识别注册的,基本python注册qml上下文使用,就是这两个demo诠释了!看不懂的可以留言评论,看到必回~

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/584866.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-12
下一篇 2022-04-12

发表评论

登录后才能评论

评论列表(0条)

保存