Kivy:在更新功能中操作动态创建的小部件

Kivy: Manipulating dynamically created widgets in update function

我正在尝试扩展 Nykakin 提供的答案 here 中的代码,其中小部件在 Kivy 中动态定义,动态分配 ID,然后根据 ID 进行操作。

'end game' 是通过根据 ID 改变小部件的位置来实现一些基本的 2D 物理。

我无法从更新功能'walk' 小部件树(内联错误)。

这样的事情可以做吗?

代码如下:

#code begins here
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.stacklayout import StackLayout
from kivy.uix.button import Button 
from kivy.uix.label import Label 
from kivy.clock import Clock
from kivy.factory import Factory

class MyWidget(BoxLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        button = Button(text="Print IDs", id="PrintIDsButton")
        button.bind(on_release=self.print_label)
        self.add_widget(button)

        # crate some labels with defined IDs
        for i in range(5):
            self.add_widget(Button(text=str(i), id="button no: " + str(i)))

        # update moved as per inclement's recommendation
        Clock.schedule_interval(MyApp.update, 1 / 30.0)

    def print_label(self, *args):
        children = self.children[:]
        while children:
            child = children.pop()
            print("{} -> {}".format(child, child.id))
            # we can change label properties from here! Woo!
            children.extend(child.children)
            if child.id == "PrintIDsButton":
                child.text = child.text + " :)"

class MyApp(App):
    def build(self):
        return MyWidget()

    def update(self, *args):
        #ERROR# AttributeError: 'float' object has no attribute 'root'
        children = self.root.children[:]

        #ERROR# TypeError: 'kivy.properties.ListProperty' object is not subscriptable
        #children = MyWidget.children[:]
        #while children:
        #    child = children.pop()
        #    print("{} -> {}".format(child, child.id))
        #    children.extend(child.children)

        #ERROR#  TypeError: 'kivy.properties.ListProperty' object is not iterable
        #for child in MyWidget.children:
        #    print("{} -> {}".format(child, child.id))
if __name__ == '__main__':
    MyApp().run()

如果我的术语不正确,我深表歉意! (感谢您的宝贵时间)

children = MyWidget.children[:]

MyWidget 是 class 本身,而不是它的一个实例,因此 children 是一个 ListProperty 对象,而不是您想要的实际列表。

您想要的是作为您的根小部件的 MyWidget 实例的子项,self.root.children

此外,您时钟将更新功能安排在 class 级别;我认为这是不好的做法,可能会导致细微的错误。在小部件的 __init__ 方法中执行它会更正常。

因此,将更新函数放在 'MyWidget' class 中,然后通过调用 self.children 访问 'MyWidget' 中的元素!

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.stacklayout import StackLayout
from kivy.uix.button import Button 
from kivy.uix.label import Label 
from kivy.clock import Clock
from kivy.factory import Factory

class MyWidget(BoxLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        button = Button(text="Print IDs", id="PrintIDsButton")
        button.bind(on_release=self.print_label)
        self.add_widget(button)

        # crate some labels with defined IDs
        for i in range(5):
            self.add_widget(Button(text=str(i), id="button no: " + str(i)))

        # update moved as per inclement's recommendation
        Clock.schedule_interval(self.update, 1 / 5.0)

    def print_label(self, *args):
        children = self.children[:]
        while children:
            child = children.pop()
            print("{} -> {}".format(child, child.id))
            # Add smiley by ID
            children.extend(child.children)
            if child.id == "PrintIDsButton":
                child.text = child.text + " :)"

    def update(self, *args):
        children = self.children[:]
        while children:
            child = children.pop()
            # remove smiley by ID
            if child.id == "PrintIDsButton":
                child.text  = "Print IDs"

class MyApp(App):
    def build(self):
        return MyWidget()

if __name__ == '__main__':
    MyApp().run()

再次感谢 inclement!