Python 如何在PySide中模块化属性创建
我在很大程度上遵循使用属性的说明,我可以使用那里给出的Person对象作为后端,但这不是很有用。我正试图找出如何做以下两件事:Python 如何在PySide中模块化属性创建,python,qt,qml,pyside2,Python,Qt,Qml,Pyside2,我在很大程度上遵循使用属性的说明,我可以使用那里给出的Person对象作为后端,但这不是很有用。我正试图找出如何做以下两件事: 在后端使用多个此类类的多个实例,并以PySide/QML不会抱怨的方式连接它们 允许在运行时根据要确定的模块定制后端(即,我最终希望将应用程序组件化-使用不同的组件实现一个接口,该组件分别对GUI和后端做出贡献;但这个问题只涉及后端) 这与简单地在主后端类上定义所有这些属性以及它们的setter和getter(我能够做到)形成对比,这就是我在问题中所说的模块化 我从链接
import QtQuick 2.0
import QtQuick.Layouts 1.12
import QtQuick.Controls 2.12
import QtQuick.Window 2.12
ApplicationWindow {
visible: true
ColumnLayout {
TextField {
implicitWidth: 200
onAccepted: {
backend.person1.name = text
}
}
TextField {
implicitWidth: 200
onAccepted: {
backend.person1.age = text
}
}
TextField {
implicitWidth: 200
onAccepted: {
backend.person2.name = text
}
}
TextField {
implicitWidth: 200
onAccepted: {
backend.person2.age = text
}
}
}
}
当我尝试在UI中设置任何值时,错误总是相同的(错误出现在QML文件中)
最终,我希望将这些对象嵌套到任意深度。有没有办法实现我在这里的目标?或者我可能完全偏离了我的设置方式?我不知道我是否有资格就GUI应用程序的总体架构设计向您提供建议,但我想我可以解释出哪里出了问题,并建议一种方法来完成您描述的工作。您的
registerProperty
方法添加了一个Python属性,但正如您所看到的,这并不能使它从QML中可见
坏消息:Qt属性在对象创建后无法添加到对象。好消息:您可以创建一个Qt属性,它是一个列表(或字典),并添加到其中 要注意的一个陷阱是,要向QML公开列表,您需要将其类型指定为
'QVariantList'
。(对于字典,请使用'QVariantMap'
,并确保键是字符串。)
下面是一个后端类的外观示例。(使用super()
访问父类意味着不必将self
传递给其初始值设定项。)
从Pyside2.QtCore导入QObject、属性、信号
类后端(QObject):
定义初始化(自):
super()。\uuuu init\uuuuu()
self.people=[]
人员变更=信号('QVariantList')
@属性('QVariantList',notify=people\u changed)
def人员(自我):
回归自我
@价值设定者
def人员(自我、新员工):
self.\u people=新人
self.people\u changed.emit(新的人)
def add_人员(本人、姓名、年龄):
self.people.append(Person(姓名、年龄、self))
#注意:只有分配才会自动触发更改的
#信号。如果你附加,你必须自己发射它。
self.people\u changed.emit(self.people)
这将使QML在您添加人员时保持最新;您还可以创建类似的方法来删除人员。将每个人作为后端对象的子对象可以确保只要后端仍然存在,Qt就会保留对他们的引用
对于一个真正的动态属性集合,也许您可以为顶级后端对象提供一个字典,供其他组件添加到其中。因此,backend.people
将成为backend.properties['people']
,一个特定的模块将负责将该键添加到properties
字典中,然后向其中添加和删除条目
指定所有这些getter和setter都很麻烦,不是吗?我花了很长时间觉得一定有更好的方法,直到最近才在堆栈溢出问题上找到了解决方案。使用,您的Person类和我在上面发布的后端可以简化为:
从PySide2.QtCore导入QObject
#假设将链接代码另存为properties.py:
从属性导入属性数据,属性
类Person(QObject,元类=PropertyMeta):
名称=属性(str)
年龄=财产(整数)
定义初始(自我、姓名、年龄、父母=无):
super()。\uuuu init\uuuu(父级)
self.name=名称
self.age=年龄
类后端(QObject,元类=PropertyMeta):
人员=财产(列表)
定义初始化(自):
super()。\uuuu init\uuuuu()
self.people=[]
def add_人员(本人、姓名、年龄):
self.people.append(Person(姓名、年龄、self))
#自动发出更改的信号,即使是就地更改
(我也把
age
改为int
,但如果你需要的话,它仍然可以是str
。我不知道我是否有资格就GUI应用程序的总体架构设计向你提供建议,但我想我可以解释出哪里出了问题,并建议一种方法来完成你描述的工作。您的registerProperty
方法添加了一个Python属性,但正如您所看到的,这并不能使它从QML中可见
坏消息:Qt属性在对象创建后无法添加到对象。好消息:您可以创建一个Qt属性,它是一个列表(或字典),并添加到其中 要注意的一个陷阱是,要向QML公开列表,您需要将其类型指定为
'QVariantList'
。(对于字典,请使用'QVariantMap'
,并确保键是字符串。)
这是考试
import sys
from os.path import abspath, dirname, join
from PySide2.QtCore import QObject, Property, Signal
from PySide2.QtGui import QGuiApplication
from PySide2.QtQml import QQmlApplicationEngine
from person import Person
class Backend(QObject):
def __init__(self):
QObject.__init__(self)
def registerProperty(self, name : str, prop):
setattr(self, name, prop)
person1 = Person("Jill", 29)
if __name__ == '__main__':
app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine()
context = engine.rootContext()
# Instance of the Python object
backend = Backend()
# simulate properties added by another module
backend.registerProperty("person2", Person("Jack", 30))
qmlFile = join(dirname(__file__), 'view3.qml')
engine.load(abspath(qmlFile))
# Expose the Python object to QML
context.setContextProperty("backend", backend)
# I tried this but it did nothing
# context.setContextProperty("backend.jack", backend.jack)
# context.setContextProperty("backend.jill", backend.jill)
if not engine.rootObjects():
sys.exit(-1)
sys.exit(app.exec_())
import QtQuick 2.0
import QtQuick.Layouts 1.12
import QtQuick.Controls 2.12
import QtQuick.Window 2.12
ApplicationWindow {
visible: true
ColumnLayout {
TextField {
implicitWidth: 200
onAccepted: {
backend.person1.name = text
}
}
TextField {
implicitWidth: 200
onAccepted: {
backend.person1.age = text
}
}
TextField {
implicitWidth: 200
onAccepted: {
backend.person2.name = text
}
}
TextField {
implicitWidth: 200
onAccepted: {
backend.person2.age = text
}
}
}
}
TypeError: Value is undefined and could not be converted to an object