получить доступ к динамически добавленному виджету с идентификатором - PullRequest
0 голосов
/ 13 июня 2019

Цель
Я хочу создать небольшой скрипт, который динамически добавляет кнопки, но все же позволяет мне выполнять функции для определенных из них через root.


Мои методы
Я сделал этот скрипт.

Он способен динамически добавлять большие кнопки вдоль верхней части.
Каждая из этих кнопок при нажатии слегка меняет свой цвет.

Он имеет две маленькие кнопки внизу.
Первая кнопка динамически добавляет новые большие кнопки вверху.
Вторая кнопка сбрасывает цвет первой большой кнопки сверху.

Мой код

#!/usr/bin/env python3
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout

Builder.load_string('''
<RootWidget>:  
    Button:
        text: 'Add'
        size_hint: (None, None)
        size: (40, 40)
        pos: (40, 40)
        group: 'action'
        on_press: root.createNextTarget()
    Button:
        text: 'res'
        size_hint: (None, None)
        size: (40, 40)
        pos: (100, 40)
        group: 'action'
        on_press: root.resetTarget()
''')

class RootWidget(FloatLayout):
    def __init__(self, **kwargs):
        super(RootWidget, self).__init__(**kwargs)
        #note: self.ids isn't populated yet. I guess we can't use it yet.
        self.createNextTarget()

    def resetTarget(self):
        f_target = self.ids['targetbutton0']
        f_target.background_color = (1.0, 1.0, 1.0, 1.0)
        return True

    def countTargets(self):
        return [str(x.__class__.__name__) for x in self.children if x != None].count('TargetButton')

    def createNextTarget(self):
        f_nextButton = TargetButton(id="targetbutton"+str(self.countTargets()),
                               size_hint=(None, None),
                               pos=(80 + (10 + 60) * self.countTargets(), 100),
                               size=(60, 60),
                               background_normal = '',
                               background_color = (1, 1, 1, 1),
                               group = 'target')
        self.add_widget(f_nextButton)
        f_nextButton.bind(on_press=TargetButton.lowerAllRGB)

class TargetButton(Button):
    def __init__(self, **kwargs):
        super(TargetButton, self).__init__(**kwargs)

    def lowerAllRGB(self):
        f_r, f_g, f_b, f_a = self.background_color
        if f_r >= 0.1: f_r = f_r - 0.1
        if f_g >= 0.1: f_g = f_g - 0.1
        if f_b >= 0.1: f_b = f_b - 0.1
        self.background_color = (f_r, f_g, f_b, f_a)
        return True

class TestApp(App):
    def build(self):
        return RootWidget()

    def on_stop(self):
        print("TestApp.on_stop: finishing", self.root.ids)

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

Проблема
Если я пытаюсь нажать кнопку сброса (которая получает доступ к виджету через root.ids), я получаю ошибку: KeyError: 'targetbutton0'

После нахождения сообщения о подобной проблеме я подумал, что root.ids просто не будет работать во время RootWidget.__init__.
Но когда я использую кнопку для добавления кнопок после RootWidget.__init__,готово, TestApp.on_stop() по-прежнему печатает: TestApp.on_stop: finish {}

Так что root.ids все еще пусто и, похоже, не содержит никаких динамически добавленных виджетов, несмотря на то, что я назначил атрибут id каждому из них.

Мои вопросы к вам

  1. Учитывая то, как я динамически добавляю виджеты, использование root.ids просто бесполезно для моих целей?
  2. Есть ли для меня достойный способ доступа к моим виджетам через id?
    Я видел другой вопрос hпрежде чем просить что-то подобное.Но он не ответил на мой вопрос о динамически добавляемых виджетах.

1 Ответ

1 голос
/ 14 июня 2019

Вопрос 1 - root.ids / self.ids

Учитывая то, как я динамически добавляю виджеты, просто использую root.ids ничего не стоит для моих целей?

Ответ

id, назначенные динамически добавленным виджетам, не сохраняются в self.ids или root.ids. Поэтому вы не можете получить доступ к динамически добавленным виджетам, используя self.ids['targetbutton0'] или self.ids.targetbutton0. Если вы сделаете это, вы получите KeyError, потому что он не найден в self.ids, который является свойством словарного типа.

Когда ваш файл kv анализируется, Kivy собирает все виджеты, помеченные идентификаторами, и помещает их в это self.ids свойство типа словаря.

Примечание: Этот тип id (то есть id, назначенный динамически созданному виджету) устарел и будет удален в будущей версии Kivy.

[WARNING] Deprecated property "<StringProperty name=id>" of object "<kivy.uix.button.Button object at 0x7feeec0968d0>" has been set, it will be removed in a future version

Вопрос 2

Есть ли у меня приличный способ доступа к моим виджетам через id?

Решение

Вы можете создать свой собственный список идентификаторов свойства словарного типа.

Отрывки

from kivy.properties import DictProperty

class RootWidget(FloatLayout):
    dynamic_ids = DictProperty({})    # declare class attribute, dynamic_ids

    def __init__(self, **kwargs):
        super(RootWidget, self).__init__(**kwargs)
        self.createNextTarget()

    def resetTarget(self):
        f_target = self.dynamic_ids['targetbutton0']
        f_target.background_color = (0.0, 1.0, 1.0, 1.0)    # cyan colour
        return True

    ...

    def createNextTarget(self):
        id = "targetbutton" + str(self.countTargets())
        f_nextButton = TargetButton(id=id,
                               size_hint=(None, None),
                               pos=(80 + (10 + 60) * self.countTargets(), 100),
                               size=(60, 60),
                               background_normal = '',
                               background_color = (1, 1, 1, 1),    # white colour
                               group = 'target')
        self.add_widget(f_nextButton)
        self.dynamic_ids[id] = f_nextButton
        f_nextButton.bind(on_press=TargetButton.lowerAllRGB)

выход

Result

...