Ошибка ключа KivyMD для вызывающего абонента для MDDropdownMenu

#python #python-3.x #kivy #keyerror #kivymd

#python #python-3.x #kivy #ошибка ключа #kivymd

Вопрос:

Я пытаюсь изменить свое существующее приложение Kivy, чтобы включить красивые виджеты KivyMD. Я удалил a Spinner для MDRaisedButton on_release caller with для MDDropdownMenu списка имен устройств, которые были сопряжены через Bluetooth с устройством (в зависимости от платформы). Для этого тестового примера я использую только список пунктов меню, как показано в MDDropdownMenu примере документов.

По какой-то причине я получаю KeyError: 'dev_button' MDRaisedButton id сообщение о инициализации MDDropdownMenu свойств. __init__ Метод находится в моем корневом классе, который находится в отдельных файлах с именем indexui.py и indexui.kv в файле main.py and main.kv . Но импортируется в main.py файл и включается в main.kv файл. Приложение действительно запускалось перед изменением Spinner .

indexui.py

 class RootLay(FloatLayout):
    this = ObjectProperty(None)  # App object
    bserial = ObjectProperty(None)  # Bluetooth variables starts
    recv_stream = ObjectProperty(None)
    send_stream = ObjectProperty(None)
    menu = ObjectProperty(None)
    rfsocket = ObjectProperty(None)
    device = ObjectProperty(None)
    pattern = ObjectProperty(None)
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.device = None
        self.pattern = re.compile(r'[GNSTUkg,s]')
        self.dev_list = []
        menu_items = [{"icon": "git", "text": f"Item {i}"} for i in range(5)]
        print(dir(self.ids))
        self.menu = MDDropdownMenu(
            caller=self.ids.dev_button, items=menu_items, width_mult=4
        )
        self.menu.bind(on_release=self.menu_callback)
  

indexui.kv

 <RootLay>:
    MDToolbar:
        pos_hint: {'top': 1, 'right': 1}
        title: "Bluetooth Weigh"
    MDRaisedButton:
        id: dev_button
        text: "SEE DEVICES"
        pos_hint: {'top': 0.76, 'right': 0.9}
        on_release: app.root.menu.open()
  

main.py

 from kivymd.app import MDApp
from views.indexui import RootLay
from kivy.properties import ObjectProperty

class MainApp(MDApp):
    def build(self):
        self.theme_cls.primary_palette = "Yellow"  # "Purple", "Red"
        self.theme_cls.primary_hue = "600"
        # self.icon = 'bluetooth-connected_326502.png'
        root = ObjectProperty(RootLay())
        return root

    def on_pause(self):
        return True
    
MainApp().run()
  

main.kv

 #:include views/indexui.kv

RootLay:
  

Может кто-нибудь, пожалуйста, помочь мне понять, почему существует KeyError ? MDRaisedButton Находится в RootLay области видимости класса как метод. Поэтому я должен иметь доступ ко всем его свойствам.

Комментарии:

1. Похоже, что ваш kv файл не загружается. Вы явно загружаете kv ? ваш kv файл назван main.kv ?

2. Привет, спасибо за ваш ответ. Да, я считаю, что он загружается, поскольку main.kv файл имеет то же имя, что и класс приложения. Я добавил код kv файлов выше. Есть ли что-то, что я должен сделать дополнительно? Или что-то, что я импортирую неправильно?

Ответ №1:

Я считаю, что проблема в том, что вы пытаетесь получить доступ к ids RootLay классу до того, как они станут доступны. Я предлагаю отложить этот доступ, используя Clock.schedule_once() следующее:

 class RootLay(FloatLayout):
    this = ObjectProperty(None)  # App object
    bserial = ObjectProperty(None)  # Bluetooth variables starts
    recv_stream = ObjectProperty(None)
    send_stream = ObjectProperty(None)
    menu = ObjectProperty(None)
    rfsocket = ObjectProperty(None)
    device = ObjectProperty(None)
    pattern = ObjectProperty(None)
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.device = None
        self.pattern = re.compile(r'[GNSTUkg,s]')
        self.dev_list = []
        Clock.schedule_once(self.setup_menu)  # delay until ids are available

    def setup_menu(self, dt):
        menu_items = [{"icon": "git", "text": f"Item {i}"} for i in range(5)]
        self.menu = MDDropdownMenu(
            caller=self.ids.dev_button,
            items=menu_items,
            width_mult=4
        )
        self.menu.bind(on_release=self.menu_callback)
  

Комментарии:

1. Это очень умное решение. Спасибо!

2. Если вы добавите функцию обратного вызова в menu_items и не привязываете ее, как в моем примере, повлияет ли это на работу функции или нет?

3. Это menu_items=[{'callback': self.menu_callback, 'text': f"Item {i}"} for i in range(5)}] вместо того, чтобы привязывать его к self.menu .

4. Причина, по которой я спрашиваю, заключается в том, что Эрик Сандберг создал пример, используя callback таким образом, но он не работает, когда callback для and viewclass установлен items ключ. Он работает только тогда, когда для него установлен callback ключ в MDDropdownMenu экземпляре. В MDDropdownMenu исходном коде я также не нахожу viewclass или callback , который может быть установлен для items ключа MDDropdownMenu экземпляра. Так что, возможно, он устарел,

5. Я не знаю ни одного способа включить обратный вызов в items список, однако вы можете добавить callback=self.menu_callback к MDDropdownMenu() вызову (и удалить self.menu.bind вызов).