KivyMD icon indicating copy to clipboard operation
KivyMD copied to clipboard

Can't add item to MDDropdownMenu after opening it once

Open Qwebeck opened this issue 3 years ago • 2 comments

Description of the Bug

Run the below example and click on button Open dropdown, which will open dropdown. Next, close it and click on button Add item. Open dropdown again and notice, that there was no items added.

The cause of problem is that it looks, like the menu when once rendered, will not be re rendered. Try run the example again, and firstly press button Add item multiple times, and after that open the dropdown. You will notice, that new items were added. Possible, the reason is that menu is rendered only once ( if i understand the code right ) in this lines https://github.com/kivymd/KivyMD/blob/648b3576fa97e5c7894790f56e33f654baa43caa/kivymd/uix/menu.py#L1004-L1009

Note: bug can be caused by something deeper, than what I've noticed above, because, when I was recording a video, I wasn't able to add items even when dropdown wasn't opened before. ( new items on video were added before record I started recording )

Code and Logs

from kivy.lang import Builder
from itertools import chain
from kivymd.app import MDApp
from kivymd.uix.menu import MDDropdownMenu

KV = '''
Screen:

    MDRaisedButton:
        id: button
        text: "Add item"
        pos_hint: {"center_x": .3, "center_y": .5}
        on_release: app.add_item()

    MDRaisedButton:
        id: button
        text: "Open dropdown"
        pos_hint: {"center_x": .5, "center_y": .5}
        on_release: app.menu.open()
'''


class Test(MDApp):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.screen = Builder.load_string(KV)
        self.item_count = 5
        menu_items = [{"text": f"Item {i}"} for i in range(self.item_count)]
        self.menu = MDDropdownMenu(
            caller=self.screen.ids.button,
            items=menu_items,
            width_mult=4,
        )
        self.menu.bind(on_release=self.menu_callback)

    def add_item(self):
        self.item_count += 1
        new_item = {'text': f'Item{self.item_count}'}
        self.menu.items = [item for item in chain(self.menu.items, [new_item])] 
    
    def menu_callback(self, instance_menu, instance_menu_item):
        print(instance_menu, instance_menu_item)

    def build(self):
        return self.screen


Test().run()

Screenshots

https://youtu.be/b3No-1kDYpo

Versions

  • OS: Windows 10
  • Python: Python 3.7.5
  • Kivy: 1.11.1
  • KivyMD: 0.104.2.dev0

Qwebeck avatar Oct 31 '20 01:10 Qwebeck

If you recreate the MDDropdownMenu on add_item, it should work.

def add_item(self):
    self.item_count += 1
    new_item = {'text': f'Item{self.item_count}'}
    menu_items = [item for item in chain(self.menu.items, [new_item])] 
    self.menu = MDDropdownMenu(
            caller=self.screen.ids.button,
            items=menu_items,
            width_mult=4,
        )
    self.menu.bind(on_release=self.menu_callback)

mp-007 avatar Oct 31 '20 02:10 mp-007

@marcets Hello, thank you ! Yes, this solution works, but nevertheless I think, that it is not an expected behavior, because items isListProperty of MDDropdownMenu, so updating it should cause menu re rendering.

Qwebeck avatar Oct 31 '20 09:10 Qwebeck