【问题标题】:Attaching Qt Property to Python Class After Definition; Not Accessible from QML [duplicate]定义后将 Qt 属性附加到 Python 类;无法从 QML 访问 [重复]
【发布时间】:2020-06-29 00:27:50
【问题描述】:

我正在使用 PySide2 和 QML。当我在 Python 对象中定义 QtCore.Property 时,它成功地为 QML 以及 Python 属性 get/set 方法设置了访问权限。但是,我有一种情况,在定义类之后附加属性会很有用,但这并没有像我预期的那样工作。

首先,一个有效的例子:

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

class Person(QObject):
    def get_name(self):
        print('trying to access name')
        return self._name

    def set_name(self, new_name):
        print('trying to set name')
        self._name = new_name

    name = Property(str, get_name, set_name)
    
bob = Person()
bob.name = 'Bob'
print(f'Name: "{bob.name}"')
print(bob.__dict__)

app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
engine.rootContext().setContextProperty('backend', bob)
engine.load("example.qml")
sys.exit(app.exec_())

还有一个简单的 QML 文件可供查看:

import QtQuick 2.15
import QtQuick.Window 2.15

Window {
    visible: true
    
    Component.onCompleted: { console.debug(JSON.stringify(backend)) }
    
    Text { text: backend.name }
}

生成的图形窗口显示“Bob”,控制台输出包括:

trying to set name
trying to access name
Name: "Bob"
{'_name': 'Bob'}
qml: {"objectName":"","name":"Bob"}

然而,看起来只是一个简单的改变,事情变得令人困惑。我将 Python 类定义替换为:

class Person(QObject):
    pass
    
def get_name(obj):
    print('trying to access name')
    return obj._name

def set_name(obj, new_name):
    print('trying to set name')
    obj._name = new_name

Person.name = Property(str, get_name, set_name)

也就是说,getter、setter 和 Property 是在类定义之外定义的,并在事后附加到它上面。奇怪的是QML看不到Property,但是Python还是知道它的正确用法:

trying to set name
trying to access name
Name: "Bob"
{'_name': 'Bob'}
qml: {"objectName":""}
file:///Users/charles/Projects/qt/property-test/example.qml:9:9: Unable to assign [undefined] to QString

对于QtCore.Property 如何正确设置 Python 属性,而不是 QML 属性,我摸不着头脑。我对它的实现有什么遗漏吗?

【问题讨论】:

    标签: python qt qml pyside2


    【解决方案1】:

    TL; DR; 无法在运行时定义 QProperties。


    QML 不使用 Python 内省来访问 QObjects 属性,而是 Qt 在 QMetaObject 中实现了自己的内省,这可以在以下代码中看到:

    class Person(QObject):
        def get_name(self):
            return self._name
    
        def set_name(self, new_name):
            self._name = new_name
    
        name = Property(str, get_name, set_name)
    
    
    bob = Person()
    bob.name = "Bob"
    
    print("qproperties:")
    print("============")
    mo = bob.metaObject()
    for i in range(mo.propertyOffset(), mo.propertyCount()):
        prop = mo.property(i)
        print(f"{i}: {prop.name()} = {prop.read(bob)}")
    

    输出:

    qproperties:
    ============
    1: name = Bob
    
    class Person(QObject):
        pass
    
    
    def get_name(obj):
        return obj._name
    
    
    def set_name(obj, new_name):
        obj._name = new_name
    
    
    Person.name = Property(str, get_name, set_name)
    
    
    bob = Person()
    bob.name = "Bob"
    
    print("qproperties:")
    print("============")
    mo = bob.metaObject()
    for i in range(mo.propertyOffset(), mo.propertyCount()):
        prop = mo.property(i)
        print(f"{i}: {prop.name()} = {prop.read(bob)}")
    

    输出:

    qproperties:
    ============
    

    PySide2(也叫PyQt5)在构建类时会创建QProperties,所以如果在类构建后添加QProperties,则不会添加QMetaObject。


    另一种方法是使用QQmlPropertyMap:

    import sys
    from PySide2.QtCore import QTimer
    from PySide2.QtGui import QGuiApplication
    from PySide2.QtQml import QQmlApplicationEngine, QQmlPropertyMap
    
    person_map = QQmlPropertyMap()
    person_map.insert("name", "Bob")
    
    app = QGuiApplication(sys.argv)
    engine = QQmlApplicationEngine()
    engine.rootContext().setContextProperty("backend", person_map)
    engine.load("example.qml")
    
    QTimer.singleShot(1000, lambda: person_map.setProperty("name", "Joe"))
    sys.exit(app.exec_())
    

    【讨论】:

    猜你喜欢
    • 2019-04-13
    • 2012-01-25
    • 1970-01-01
    • 2018-07-24
    • 2018-05-15
    • 2011-01-20
    • 1970-01-01
    • 2021-11-03
    相关资源
    最近更新 更多