Python Kivy: проблема с динамически присваиваемыми идентификаторами виджетов - PullRequest
0 голосов
/ 01 мая 2020

Я пишу приложение в Kivy, которое автоматически добавляет кнопки и дает им уникальный идентификатор, используя для l oop. Этот идентификатор затем используется в качестве ключа в словаре для ссылки. Таким образом, словарь работает нормально, и после его печати он выдает {'button0': 'somewebsite', 'button1': 'other website', 'button2': 'andanotherwebsite'}, что именно то, что я хочу, но функция кнопки callback всегда печатает button2 вместо своего собственного идентификатора. Я присвоил идентификаторы неправильно? Пример ниже демонстрирует мою проблему.

from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivymd.utils import asynckivy
from kivy.clock import Clock


class TestButton(Button):
    def callback(self):
        print(self.id)


class RootWidget(BoxLayout):
    def __init__(self):
        super().__init__()

        self.links = ["somewebsite", "other website", "andanotherwebsite"]
        self.dic_btn_to_lnk = {}

        self.size_hint = (None, None)
        self.size = ("600dp", "50dp")
        Clock.schedule_once(self.add_widgets, 0)

    def add_widgets(self, *args):
        async def update():
            number = 0
            for link in self.links:
                button = TestButton()

                button.text = link
                button.size = ("200dp", "50dp")
                button.pos_hint = {"center_x": .5}

                btn_id = "button" + str(number)
                button.id = btn_id
                button.bind(on_release=lambda x: button.callback())
                number += 1

                self.dic_btn_to_lnk[btn_id] = link

                self.add_widget(button)

                print(self.dic_btn_to_lnk)
        asynckivy.start(update())


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


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

1 Ответ

2 голосов
/ 01 мая 2020

Проблема в том, что ваша привязка on_release вызывает button.callback(), и button будет последним Button, добавленным к моменту запуска on_release. Решение состоит в том, чтобы использовать partial, который замораживает свои аргументы до их значений при выполнении partial, поэтому on_release вызывает правильный button.callback. Например:

button.bind(on_release=partial(button.callback))

И чтобы упростить вышесказанное, определение callback изменено на:

class TestButton(Button):
    def callback(self, instance):
        print(self.id)
...