Добавить виджет к потомку наследуемого класса в динамическом классе kv - PullRequest
1 голос
/ 19 марта 2019

Если у меня есть динамически определенный класс, такой как этот:

<Foo@BoxLayout>:
    orientation: "vertical"

    ...some other child widgets...

    BoxLayout:
        id: target
        orientation: "horizontal"

        ...other children...

Как мне создать класс, который наследуется от этого, с единственным изменением, являющимся дополнительным виджетом, добавленным к BoxLayout с id: target?

Я попытался изменить динамические классы на правила и определить классы в питоне:

class Foo(BoxLayout):
    pass

class EditedFoo(Foo):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.ids["target"].add_widget(<the widget I want to add>, index=0)

однако идентификаторы были пустыми из функции __init__ (и из функции on_parent).

Есть ли способ сделать это без переопределения всего класса?

Редактировать:

from kivy.app import App
from kivy.lang.builder import Builder
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout

kv = """
BoxLayout:
    EditedFoo:

<Foo>:
    orientation: "vertical"

    BoxLayout:
        id: target
        orientation: "horizontal"
"""

class TestApp(App):
    def build(self):
        return Builder.load_string(kv)

class Foo(BoxLayout):
    pass

class EditedFoo(Foo):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.ids["target"].add_widget(Button(text="hello"), index=0)

TestApp().run()

Вот полный проверенный пример того, как он не работает

Ответы [ 2 ]

1 голос
/ 23 марта 2019

Код .kv реализует класс, созданный в Python, поэтому понятно, что он будет добавлен после того, как конструктор завершит выполнение, и, следовательно, идентификаторы будут пустыми в конструкторе, трюк заключается в использовании Clock, который будет вызывать функциючерез мгновение после рендеринга всего окна, поскольку в этот момент идентификаторы не будут пустыми:

# ...
from kivy.clock import Clock
# ...

class EditedFoo(Foo):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        Clock.schedule_once(self.callback)

    def callback(self, *args):
        self.ids["target"].add_widget(Button(text="hello"), index=0)
1 голос
/ 21 марта 2019

Коды в файле .kv инициализируются после выполнения кодов Python.

Следовательно, ваш EditedFoo(Foo) сначала унаследует Foo(BoxLayout) от кодов Python, затем будет повторно объявлен Foo в файле .kv.

Лучший способ - поместить начальные атрибуты Foo(BoxLayout) в коды Python, а затем наследовать Foo в .kv, например <EditedFoo@Foo>

Например,

В .py:

class Foo(BoxLayout):
    greeting = "hi"

В .kv:

<EditedFoo@Foo>
    greeting: "Goodbye World"

Foo:
    id: root_foo
    Button:
        text: root_foo.greeting
    EditedFoo:
        id: foo1
        Label:
            text: foo1.greeting
    EditedFoo:
        id: foo2
        greeting: "Hello Another World"
        Button:
            text: foo2.greeting

Таким образом, вы можете использовать EditedFoo класс в .kv, унаследованном от Foo.

enter image description here

...