Reputation: 1
I'm using Kivy and KivyMD, I'm trying to implement MDToolbar. After running my program I get this error: AttributeError: 'NoneType' object has no attribute 'theme_cls'
. I included only the relevant code from my program. Everything works perfectly up until adding the MDToolbar. How can I get MDToolbar to work? Please help!
My Full Error:
Parser: File "<inline>", line 22:
...
20:<MDToolbar>
21: size_hint_y: None
>> 22: height: root.theme_cls.standard_increment
23: padding: [root.theme_cls.horizontal_margins - dp(12), 0]
24: opposite_colors: True
...
AttributeError: 'NoneType' object has no attribute 'theme_cls'
File "C:\Users\kelleym\AppData\Local\Continuum\anaconda3\lib\site-packages\kivy\lang\builder.py", line 696, in _apply_rule
setattr(widget_set, key, value)
File "kivy\weakproxy.pyx", line 35, in kivy.weakproxy.WeakProxy.__setattr__
File "kivy\properties.pyx", line 497, in kivy.properties.Property.__set__
File "kivy\properties.pyx", line 544, in kivy.properties.Property.set
File "kivy\properties.pyx", line 599, in kivy.properties.Property.dispatch
File "kivy\_event.pyx", line 1214, in kivy._event.EventObservers.dispatch
File "kivy\_event.pyx", line 1120, in kivy._event.EventObservers._dispatch
File "kivy\properties.pyx", line 1318, in kivy.properties.ReferenceListProperty.trigger_change
File "kivy\properties.pyx", line 1333, in kivy.properties.ReferenceListProperty.trigger_change
File "kivy\properties.pyx", line 599, in kivy.properties.Property.dispatch
File "kivy\_event.pyx", line 1214, in kivy._event.EventObservers.dispatch
File "kivy\_event.pyx", line 1120, in kivy._event.EventObservers._dispatch
File "C:\Users\kelleym\AppData\Local\Continuum\anaconda3\lib\site-packages\kivymd\uix\behaviors\elevation.py", line 105, in _update_shadow
self._shadow = App.get_running_app().theme_cls.quad_shadow
File "C:\Users\kelleym\Desktop\Actual Inventory App\main.py", line 313, in <module>
sm.add_widget(inventory(name='inventory'))
My Code:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivymd.theming import ThemeManager
Builder.load_string("""
<inventory>:
NavigationLayout:
id: "nav_layout"
MDToolbar:
title: "test"
MDNavigationDrawer:
drawer_logo: "test.png"
id: "nav_drawer"
NavigationDrawerSubheader:
text: "[color=#black]Categories[/color]"
NavigationDrawerIconButton:
icon: 'printer'
text: "Printers"
on_release: root.manager.current = 'printers'
NavigationDrawerIconButton:
text: "PCs"
icon: "laptop"
NavigationDrawerIconButton:
text: "Monitors"
icon: "monitor"
NavigationDrawerIconButton:
text: "Tablets"
icon: "tablet"
NavigationDrawerIconButton:
text: "Non-HP"
icon: "close-circle-outline"
NavigationDrawerIconButton:
text: "Supplies"
icon: "water"
NavigationDrawerIconButton:
text: "Misc."
icon: "paperclip"
Button:
text: "test"
on_release: app.nav_drawer.toggle()
""")
class inventory(BoxLayout, Screen):
pass
sm = ScreenManager()
sm.add_widget(inventory(name='inventory'))
class TestApp(App):
theme_cls = ThemeManager()
def build(self):
return sm
if __name__ == "__main__":
TestApp().run()
Upvotes: 0
Views: 1776
Reputation: 124
Another example that works
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty, ListProperty
from kivymd.app import MDApp
from kivymd.theming import ThemableBehavior
from kivymd.uix.list import OneLineIconListItem, MDList
KV = '''
# Menu item in the DrawerList list.
<ItemDrawer>:
theme_text_color: "Custom"
on_release: self.parent.set_color_item(self)
IconLeftWidget:
id: icon
icon: root.icon
theme_text_color: "Custom"
text_color: root.text_color
<ContentNavigationDrawer>:
orientation: "vertical"
padding: "8dp"
spacing: "8dp"
AnchorLayout:
anchor_x: "left"
size_hint_y: None
height: avatar.height
Image:
id: avatar
size_hint: None, None
size: "56dp", "56dp"
source: "data/logo/kivy-icon-256.png"
MDLabel:
text: "KivyMD library"
font_style: "Button"
size_hint_y: None
height: self.texture_size[1]
MDLabel:
text: "[email protected]"
font_style: "Caption"
size_hint_y: None
height: self.texture_size[1]
ScrollView:
DrawerList:
id: md_list
Screen:
MDNavigationLayout:
ScreenManager:
Screen:
BoxLayout:
orientation: 'vertical'
MDToolbar:
title: "Navigation Drawer"
elevation: 10
left_action_items: [['menu', lambda x: nav_drawer.set_state("open")]]
Widget:
MDNavigationDrawer:
id: nav_drawer
ContentNavigationDrawer:
id: content_drawer
nav_drawer: nav_drawer
'''
class ContentNavigationDrawer(BoxLayout):
pass
class ItemDrawer(OneLineIconListItem):
icon = StringProperty()
text_color = ListProperty((0, 0, 0, 1))
class DrawerList(ThemableBehavior, MDList):
def set_color_item(self, instance_item):
"""Called when tap on a menu item."""
# Set the color of the icon and text for the menu item.
for item in self.children:
if item.text_color == self.theme_cls.primary_color:
item.text_color = self.theme_cls.text_color
break
instance_item.text_color = self.theme_cls.primary_color
class TestNavigationDrawer(MDApp):
def build(self):
return Builder.load_string(KV)
def on_start(self):
icons_item = {
"folder": "My files",
"account-multiple": "Shared with me",
"star": "Starred",
"history": "Recent",
"checkbox-marked": "Shared with me",
"upload": "Upload",
}
for icon_name in icons_item.keys():
self.root.ids.content_drawer.ids.md_list.add_widget(
ItemDrawer(icon=icon_name, text=icons_item[icon_name])
)
TestNavigationDrawer().run()
Upvotes: 0
Reputation: 1090
All code here works with Kivy 1.11.1 and KivyMD 0.102.0. KivyMD is in alpha status and API can be changed in future.
def build(self):
sm = ScreenManager()
sm.add_widget(inventory(name='inventory'))
return sm
NavigationLayout:
MDNavigationDrawer:
# ...
NavigationDrawerSubheader:
# ...
BoxLayout:
orientation: "vertical"
MDToolbar:
title: "test"
Button:
text: "test"
on_release: app.nav_drawer.toggle()
NavigationLayout:
id: nav_layout
MDNavigationDrawer:
id: nav_drawer
To call widget by id you should use app.root.ids.nav_drawer
.
To toggle NavigationDrawer you should call NavigationLayout: app.root.ids.nav_layout.toggle_nav_drawer()
.
Usually NavigationLayout used as root widget. Add ScreenManager to BoxLayout.
You can add screens to ScreenManager using kv code:
ScreenManager:
id: screen_manager
Inventory:
name: "inventory"
class Inventory(BoxLayout, Screen):
. Create BoxLayout inside your screen:<Inventory>:
BoxLayout:
orientation: "vertical"
Final code will be:
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import ObjectProperty
from kivy.uix.screenmanager import Screen
from kivymd.theming import ThemeManager
root_kv = """
NavigationLayout:
id: nav_layout
MDNavigationDrawer:
id: nav_drawer
drawer_logo: "test.png"
NavigationDrawerSubheader:
text: "Categories"
NavigationDrawerIconButton:
text: "Printers"
icon: "printer"
on_release: app.screen_manager.current = "printers"
NavigationDrawerIconButton:
text: "PCs"
icon: "laptop"
NavigationDrawerIconButton:
text: "Monitors"
icon: "monitor"
NavigationDrawerIconButton:
text: "Tablets"
icon: "tablet"
NavigationDrawerIconButton:
text: "Non-HP"
icon: "close-circle-outline"
NavigationDrawerIconButton:
text: "Supplies"
icon: "water"
NavigationDrawerIconButton:
text: "Misc."
icon: "paperclip"
BoxLayout:
orientation: "vertical"
ScreenManager:
id: screen_manager
Inventory:
name: "inventory"
<Inventory>:
BoxLayout:
orientation: "vertical"
MDToolbar:
title: "test"
Button:
text: "test"
on_release: app.root.toggle_nav_drawer()
"""
class Inventory(Screen):
pass
class MainApp(App):
theme_cls = ThemeManager()
screen_manager = ObjectProperty()
def build(self):
self.root = Builder.load_string(root_kv)
self.screen_manager = self.root.ids.screen_manager
if __name__ == "__main__":
MainApp().run()
Upvotes: 1