Torgeir
Torgeir

Reputation: 3

Kivy: Using Toolbar together with ScreenManager. What I'm doing wrong here?

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

Answers (1)

John Anderson
John Anderson

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

Related Questions