Reputation: 3
So I have a Toolbar that work perfectly well on a single screen, but I need two screens. One main screen and one setup screen. This should be easy done with ScreenManager, I hoped.
When I run this code I get the following error: AttributeError: 'super' object has no attribute 'getattr' What I'm doing wrong?
from kivymd.app import MDApp
from kivy.lang.builder import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivymd.uix.menu import MDDropdownMenu
from kivy.metrics import dp
kv = """
ScreenManager:
MainScreen:
SetupScreen:
<MainScreen>:
name: 'main'
MDToolbar:
id: tool1
title:'My Demo App'
pos_hint:{'top':1}
right_action_items : [["dots-vertical", lambda x: app.menu.open()]]
<SetupScreen>:
name: 'setup'
"""
class MainScreen(Screen):
pass
class SetupScreen(Screen):
pass
# Create the screen manager
sm = ScreenManager()
sm.add_widget(MainScreen(name='main'))
sm.add_widget(SetupScreen(name='setup'))
class DemoApp(MDApp):
def build(self):
screen = Builder.load_file('test.kv')
menu_items = [
{
"text": f"Option {opt}",
"viewclass": "OneLineListItem",
"height": dp(40),
"on_release": lambda x=f"Option {opt}": self.menu_callback(x),
} for opt in range(4)
]
menu = MDDropdownMenu(
caller=sm.ids.tool1,
items=menu_items,
width_mult=3
)
return screen
def menu_callback(self, text_item):
print(text_item)
DemoApp().run()
Upvotes: 0
Views: 159
Reputation: 38857
I keep seeing this same error in many posts. When your build()
method returns the result from Builder.load_file()
or Builder.load_string()
, then your root widget (and your entire GUI) is defined in the kv
. So the lines:
# Create the screen manager
sm = ScreenManager()
sm.add_widget(MainScreen(name='main'))
sm.add_widget(SetupScreen(name='setup'))
are creating another instance of your GUI, but that instance is not used, and any references to that sm
will have no effect on the ScreenManager
that is actually in your GUI (the one built via the kv
). So, you can start by eliminating those lines completely.
Then, to fix the actual problem you need to change your construction of the MDDropdownMenu
to something like:
self.menu = MDDropdownMenu(
# caller=sm.ids.tool1,
caller=screen.get_screen('main').ids.tool1,
items=menu_items,
width_mult=3
)
using self.menu
instead of just menu
saves a reference to the menu
. Otherwise, the menu
is created, then discarded. Since sm
is not part of your GUI, you must use a reference to your actual GUI. The line:
caller=screen.get_screen('main').ids.tool1,
uses the ScreenMananger
(screen
) that is returned by the Builder
. Then using get_screen()
, it gets the main
Screen
(since that is the one that contains the tool1
id
). And finally uses that id
to get a reference to the MDToolbar
.
Upvotes: 1