I'm learning KivyMD and I'm trying to add a dropdown menu but I get this error. It's probably because of my wrong usage of ids but I still cant figure it out. Here is my main py code:
from kivymd.app import MDApp
from kivy.lang import Builder
from kivymd.uix.screenmanager import ScreenManager
from kivymd.uix.screen import Screen
from kivymd.uix.menu import MDDropdownMenu
from kivy.metrics import dp
from kivy.core.window import Window
Window.size = (500, 800)
class HomePage(Screen):
pass
class SecondPage(Screen):
pass
class App(MDApp):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.screen = Builder.load_file("kivy.kv")
items_d = ['Settings', 'Profile', 'Log Out', 'Exit']
menu_items = [
{
"text": f"{i}",
"viewclass": "OneLineListItem",
"height": dp(40),
"on_release": lambda x=f"{i}": self.menu_callback(x),
} for i in items_d
]
self.menu = MDDropdownMenu(
caller = self.screen.ids.tool1,
items = menu_items,
width_mult =2
)
def menu_callback(self, text_item):
print(text_item)
self.menu.dismiss()
def build(self):
self.theme_cls.primary_palette = 'Red'
self.theme_cls.primary_hue = '500'
self.theme_cls.theme_style = 'Dark'
sm = ScreenManager()
sm.add_widget(HomePage(name='first'))
sm.add_widget(SecondPage(name='second'))
return self.screen
App().run()
and here is the kv file:
#:kivy 2.1.0
ScreenManager:
HomePage:
SecondPage:
<HomePage>
name: 'first'
MDNavigationLayout:
ScreenManager:
Screen:
BoxLayout:
orientation:'vertical'
MDTopAppBar:
id:tool1
title: 'Home Page'
left_action_items: [['menu', lambda x: nav_drawer.set_state('toggle')]]
right_action_items: [['dots-vertical'], lambda x: app.menu.open()]
elevation: 3
MDLabel:
text: "."
MDBottomAppBar:
MDTopAppBar:
icon: 'apps'
mode: 'center'
type: 'bottom'
MDNavigationDrawer:
id: nav_drawer
ScrollView:
MDList:
OneLineIconListItem:
text: 'Home Page'
on_press: nav_drawer.set_state('close')
on_press: root.manager.current = 'first'
IconLeftWidgetWithoutTouch:
icon:'bluetooth'
OneLineIconListItem:
text: 'Content Page'
on_press: root.manager.current = 'second'
on_press: nav_drawer.set_state('close')
IconLeftWidgetWithoutTouch:
icon:'content-copy'
<SecondPage>
name: 'second'
MDNavigationLayout:
ScreenManager:
Screen:
BoxLayout:
orientation:'vertical'
MDTopAppBar:
id:tool1
title: 'Content Page'
left_action_items: [['menu', lambda x: nav_drawer.set_state('toggle')]]
right_action_items: [['dots-vertical'], lambda x: app.menu.open()]
elevation: 3
MDLabel:
text: "."
MDBottomAppBar:
MDTopAppBar:
type: 'bottom'
icon: 'apps'
mode: 'center'
left_action_items: [['information']]
MDNavigationDrawer:
id: nav_drawer
ScrollView:
MDList:
OneLineIconListItem:
text: 'Home Page'
on_press: nav_drawer.set_state('close')
on_press: root.manager.current = 'first'
IconLeftWidgetWithoutTouch:
icon:'bluetooth'
OneLineIconListItem:
text: 'Second Page'
on_press: nav_drawer.set_state('close')
on_press: root.manager.current = 'second'
IconLeftWidgetWithoutTouch:
icon:'wifi'
I don't know why exactly but maybe because of self.screen doesn't really contain the ids? And please tell me what to use instead if I'm using wrong methods.
You are incorrectly trying to access the tool1
id
. First, note that the ids
defined in the kv
file become part of the ids
dictionary of the root of the rule where that id
is defined. So the tool1
id
(which is defined twice) ends up in the ids
of the HomePage
and also in the ids
of the SecondPage
. So you must reference that id
through the containing object. Assuming you want to reference the tool1
defined in HomePage
, just change:
caller = self.screen.ids.tool1,
to:
caller = self.screen.get_screen('first').ids.tool1,
Unrelated, but you can eliminate the lines:
sm = ScreenManager()
sm.add_widget(HomePage(name='first'))
sm.add_widget(SecondPage(name='second'))
since their result is unused.