Kivy 命名空间

在 1.9.1 版本加入.

警告

此代码仍处于实验阶段,其API在未来的版本中可能会有所变动。

:类 KNSpaceBehavior 是一个 mixin 类,为 Kivy 对象提供命名空间功能。它允许 Kivy 对象被命名,并通过命名空间进行访问。

KNSpace 实例是存储 Kivy ObjectProperty 实例中命名对象的命名空间。此外,当从 KNSpaceBehavior 继承时,如果派生对象被命名,该名称将自动添加到关联的命名空间中,并指向派生对象的 proxy_ref

基本示例

默认情况下,只有一个命名空间:即 knspace 命名空间。最简单的示例是向该命名空间添加一个部件:

from kivy.uix.behaviors.knspace import knspace
widget = Widget()
knspace.my_widget = widget

这会在 knspace 命名空间中添加一个带有 rebind=Trueallownone=True 的 kivy ObjectProperty,属性名为 my_widget。并且该属性现在也指向此控件。

可以使用以下方式自动完成:

class MyWidget(KNSpaceBehavior, Widget):
    pass

widget = MyWidget(knsname='my_widget')

或者在kv中:

<MyWidget@KNSpaceBehavior+Widget>

MyWidget:
    knsname: 'my_widget'

现在,knspace.my_widget 将指向该控件。

当创建另一个同名的新控件时,命名空间也会更新以指向这个新控件。例如:

widget = MyWidget(knsname='my_widget')
# knspace.my_widget now points to widget
widget2 = MyWidget(knsname='my_widget')
# knspace.my_widget now points to widget2

设置命名空间

也可以通过直接设置 KNSpaceBehavior.knspace 来创建自己的命名空间,而不是使用默认的 knspace

class MyWidget(KNSpaceBehavior, Widget):
    pass

widget = MyWidget(knsname='my_widget')
my_new_namespace = KNSpace()
widget.knspace = my_new_namespace

最初,my_widget 被添加到默认命名空间中,但当小部件的命名空间更改为 my_new_namespace 时,对 my_widget 的引用会移动到该命名空间。当然,我们也可以先将命名空间设置为 my_new_namespace,然后再将小部件命名为 my_widget,从而避免初始分配到默认命名空间。

同样地,在kv中:

<MyWidget@KNSpaceBehavior+Widget>

MyWidget:
    knspace: KNSpace()
    knsname: 'my_widget'

继承命名空间

在之前的例子中,我们直接设置了想要使用的命名空间。在下面的例子中,我们从父级继承它,因此只需设置一次:

<MyWidget@KNSpaceBehavior+Widget>
<MyLabel@KNSpaceBehavior+Label>

<MyComplexWidget@MyWidget>:
    knsname: 'my_complex'
    MyLabel:
        knsname: 'label1'
    MyLabel:
        knsname: 'label2'

然后,我们执行以下操作:

widget = MyComplexWidget()
new_knspace = KNSpace()
widget.knspace = new_knspace

规则是:如果某个控件没有被分配 knspace,它会依次在其父控件、父控件的父控件等层级中查找命名空间,直到找到一个可用的为止。如果都没有找到,则使用默认的 knspace

当创建 MyComplexWidget 时,它仍然使用默认的命名空间。然而,当我们为根部件分配了新的命名空间后,其所有子部件也都切换到了使用该新命名空间。因此,new_knspace 现在包含了 label1label2 以及 my_complex

如果我们首先完成了:

widget = MyComplexWidget()
new_knspace = KNSpace()
knspace.label1.knspace = knspace
widget.knspace = new_knspace

那么,label1 由于是直接设置的,仍会保留在默认的 knspace 中,而 label2my_complex 则会被添加到新的命名空间中。

可以通过修改 KNSpaceBehavior.knspace_key 属性来自定义用于搜索父级树的属性。如果所需的 knspace 无法通过小部件的父级树访问,例如在不是小部件子级的弹出窗口中,可以使用 KNSpaceBehavior.knspace_key 来建立不同的搜索顺序。

访问命名空间

如前面的例子所示,如果未直接赋值,命名空间会通过搜索父级树来找到。因此,如果在父级树更上层分配了命名空间,其所有子级及以下层级都能通过它们的 KNSpaceBehavior.knspace 属性访问该命名空间。

这允许在给每个根部件实例分配新的命名空间时,创建多个具有相同名称的部件。例如:

<MyComplexWidget@KNSpaceBehavior+Widget>:
    Label:
        text: root.knspace.pretty.text if root.knspace.pretty else ''

<MyPrettyWidget@KNSpaceBehavior+TextInput>:
    knsname: 'pretty'
    text: 'Hello'

<MyCompositeWidget@KNSpaceBehavior+BoxLayout>:
    MyComplexWidget
    MyPrettyWidget

现在,当我们执行:

knspace1, knspace2 = KNSpace(), KNSpace()
composite1 = MyCompositeWidget()
composite1.knspace = knspace1

composite2 = MyCompositeWidget()
composite2.knspace = knspace2

knspace1.pretty = "Here's the ladder, now fix the roof!"
knspace2.pretty = "Get that raccoon off me!"

由于每个 MyCompositeWidget 实例都有不同的命名空间,它们的子部件也使用不同的命名空间。因此,每个实例的 pretty 和 complex 部件将具有不同的文本。

此外,由于命名空间 ObjectProperty 引用和 KNSpaceBehavior.knspace 都设置了 rebind=True,因此当根命名空间发生变化或 root.knspace.pretty 属性改变时,MyComplexWidget 标签的文本会按预期重新绑定,以匹配 MyPrettyWidget 的文本。

分叉命名空间

分叉命名空间提供了从父命名空间创建新命名空间的机会,这样分叉后的命名空间将包含原始命名空间中的所有内容,但原始命名空间将无法访问添加到分叉命名空间中的任何内容。

例如:

child = knspace.fork()
grandchild = child.fork()

child.label = Label()
grandchild.button = Button()

现在,标签(label)既可以通过子组件(child)访问,也可以通过孙组件(grandchild)访问,但不能通过 knspace 访问。而按钮(button)只能通过孙组件访问,不能通过子组件或 knspace 访问。最后,执行 grandchild.label = Label() 会使 grandchild.labelchild.label 指向不同的标签对象。

一个激励性的例子就是上面提到的那个例子:

<MyComplexWidget@KNSpaceBehavior+Widget>:
    Label:
        text: root.knspace.pretty.text if root.knspace.pretty else ''

<MyPrettyWidget@KNSpaceBehavior+TextInput>:
    knsname: 'pretty'
    text: 'Hello'

<MyCompositeWidget@KNSpaceBehavior+BoxLayout>:
    knspace: 'fork'
    MyComplexWidget
    MyPrettyWidget

注意添加了 knspace: 'fork'。这等同于执行 knspace: self.knspace.fork()。然而,这样做会导致无限递归,因为该 kv 规则会被递归执行,因为 self.knspace 会不断变化。但是,允许 knspace: 'fork' 可以规避这个问题。参见 KNSpaceBehavior.knspace

现在,既然已经完成了分叉,我们只需要执行:

composite1 = MyCompositeWidget()
composite2 = MyCompositeWidget()

composite1.knspace.pretty = "Here's the ladder, now fix the roof!"
composite2.knspace.pretty = "Get that raccoon off me!"

由于通过分叉,我们自动为每个`MyCompositeWidget`实例创建了唯一的命名空间。

class kivy.uix.behaviors.knspace.KNSpace(parent=None, keep_ref=False, **kwargs)[源代码]

基类:EventDispatcher

每个 KNSpace 实例都是一个命名空间,用于存储与该命名空间关联的命名 Kivy 对象。每个命名对象都作为该实例的一个 Kivy ObjectProperty 属性的值存储,该属性的名称即为对象的给定名称。对于该属性,rebindallownone 均设置为 True

关于命名空间如何与命名对象关联的详细信息,请参阅 KNSpaceBehavior.knspace

在命名空间中存储对象时,如果该对象具有 proxy_ref 属性,则存储的是该对象的 proxy_ref

参数:
parent:(内部)一个 KNSpace 实例或 None。

如果指定了,它是一个父命名空间,在这种情况下,当前命名空间将包含其所有命名对象,以及其父命名空间和父的父命名空间等的命名对象。更多详情请参阅 fork()

fork()[源代码]

返回一个新的 KNSpace 实例,该实例将能够访问当前命名空间中的所有命名对象,同时也会拥有一个独立且唯一的命名空间。

例如:

forked_knspace1 = knspace.fork()
forked_knspace2 = knspace.fork()

现在,添加到`knspace`中的任何名称都将通过常规方式在`forked_knspace1`和`forked_knspace2`命名空间中可访问。然而,添加到`forked_knspace1`中的任何名称将无法从`knspace`或`forked_knspace2`中访问。对于`forked_knspace2`也是如此。

keep_ref = False

是否应保留对存储对象的直接引用。若为 True,则使用直接对象;否则,在存在 proxy_ref 时使用该代理引用。

默认为 False。

parent = None

(内部)父命名空间实例,KNSpace,或 None。参见 fork()

property(self, name, quiet=False)[源代码]

根据属性名获取属性实例。如果 quietTrue,当 name 不是属性时,返回 None 而不是抛出异常。默认值为 False

在 1.0.9 版本加入.

返回:

与名称对应的 Property 派生实例。

在 1.9.0 版本发生变更: 已添加 quiet。

class kivy.uix.behaviors.knspace.KNSpaceBehavior(knspace=None, **kwargs)[源代码]

基类:object

继承自该类的对象可以被命名,并随后添加到关联的命名空间 knspace 中,通过该命名空间即可访问它们。

请参阅 knspace 行为模块 的文档以获取更多信息。

knsname

赋予此实例的名称。若已命名,该名称将被添加到关联的 knspace 命名空间中,并指向此实例的 proxy_ref

命名后,可以通过例如 self.knspace.name 来访问此对象,其中 name 是该实例的给定名称。更多详情请参阅 knspace 及模块描述。

knspace

与此控件关联的命名空间实例,即 KNSpace。当使用 knsname 为此控件命名时,knspace 命名空间会存储该控件。

如果命名空间已通过 KNSpace 实例设置,例如使用 self.knspace = KNSpace(),则返回该实例(使用 None 设置不算)。否则,如果 knspace_key 不为 None,我们会在存储于该实例的 knspace_key 属性所命名的属性中查找要使用的命名空间。即 object = getattr(self, self.knspace_key)

如果该对象具有`knspace`属性,则返回其值。否则,我们继续向上查找,例如使用`getattr(object, self.knspace_key)`,并寻找其`knspace`属性。

最后,如果我们得到的值为 None,或者 knspace_key 本身就是 None,则返回默认的 knspace 命名空间。

如果 knspace 被设置为字符串 'fork',则 knspace 中的当前命名空间将通过 KNSpace.fork() 进行分叉,并将结果命名空间分配给此实例的 knspace。请参阅模块示例以获取一个启发性的示例。

rebindallownone 均为 True

knspace_key

此实例的属性名称,用于向上搜索该实例所使用的命名空间。默认值为 'parent',因此我们将搜索父级树。参见 knspace

当设置为 None 时,我们将不会在父级树中搜索命名空间。allownoneTrue

kivy.uix.behaviors.knspace.knspace = <kivy.uix.behaviors.knspace.KNSpace object>

默认的 KNSpace 命名空间。更多详情请参阅 KNSpaceBehavior.knspace