I'm a coding beginner and I want to make a mobile app which contains a Toolbar with a Navigation Drawer and that one should bring the user to different screens in the app. I searched a lot around for a solution, but didn't really found one, because sometimes the whole code is in the .kv file, so it is hard to handle variables and print them for example such as in this code:
How to switch between screens within the NavigationDrawer using KivyMD
I tried to combine it with this code which uses only Kivy instead of KivyMD but I failed bacause it isn't really for mobile Apps:
https://www.techwithtim.net/tutorials/kivy-tutorial/multiple-screens/
I hope someone can help me.
Thx!
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
from kivymd.app import MDApp
KV = '''
<ContentNavigationDrawer>:
ScrollView:
MDList:
OneLineListItem:
text: "Screen 1"
on_press:
root.nav_drawer.set_state("close")
root.screen_manager.current = "scr 1"
OneLineListItem:
text: "Screen 2"
on_press:
root.nav_drawer.set_state("close")
root.screen_manager.current = "scr 2"
Screen:
MDToolbar:
id: toolbar
pos_hint: {"top": 1}
elevation: 10
title: "MDNavigationDrawer"
left_action_items: [["menu", lambda x: nav_drawer.set_state("open")]]
MDNavigationLayout:
x: toolbar.height
ScreenManager:
id: screen_manager
Screen:
name: "scr 1"
MDLabel:
text: "Screen 1"
halign: "center"
Screen:
name: "scr 2"
MDLabel:
text: "Screen 2"
halign: "center"
MDNavigationDrawer:
id: nav_drawer
ContentNavigationDrawer:
screen_manager: screen_manager
nav_drawer: nav_drawer
'''
class ContentNavigationDrawer(BoxLayout):
screen_manager = ObjectProperty()
nav_drawer = ObjectProperty()
class TestNavigationDrawer(MDApp):
def build(self):
return Builder.load_string(KV)
TestNavigationDrawer().run()
https://kivymd.readthedocs.io/en/latest/components/navigation-drawer/#switching-screens-in-the-screenmanager-and-using-the-common-mdtoolbar
Related
I am developing an app in KivyMD for Python and I'm having trouble implementing a single MDTopAppBar for multiple screens.
Here's my current code:
from kivymd.app import MDApp
from kivy.lang import Builder
from kivymd.uix.screenmanager import MDScreenManager
from kivymd.uix.screen import MDScreen
c = '''
<BuildApp>:
MDNavigationLayout:
MDScreenManager:
id: screener
FirstScreen:
SecondScreen:
MDNavigationDrawer:
id: nav_drawer
radius: (0, 16, 16, 0)
MDNavigationDrawerMenu:
MDNavigationDrawerItem:
icon: "android"
text: "Phone"
on_press: screener.current = "page2"
MDNavigationDrawerItem:
icon: "home"
text: "Home"
on_press: screener.current = "page1"
<FirstScreen>:
name: "page1"
MDBoxLayout:
orientation: 'vertical'
pos_hint: {"top": 1}
MDTopAppBar:
title: "Title"
elevation: 4
pos_hint: {"top": 1}
left_action_items: [["menu", lambda x: app.root.ids.nav_drawer.set_state("open")]]
MDFloatingActionButton:
icon: "home"
md_bg_color: app.theme_cls.primary_color
pos_hint: {"center_x":.5}
Widget:
<SecondScreen>:
name: "page2"
MDBoxLayout:
orientation: 'vertical'
pos_hint: {"top": 1}
MDTopAppBar:
title: "Title"
elevation: 4
pos_hint: {"top": 1}
left_action_items: [["menu", lambda x: app.root.ids.nav_drawer.set_state("open")]]
ScrollView:
MDList:
id: "stuffs"
OneLineListItem:
text: "Hi"
'''
class FirstScreen(MDScreen):
pass
class SecondScreen(MDScreen):
pass
sm= MDScreenManager()
sm.add_widget(FirstScreen(name="page1"))
class BuildApp(MDScreen):
pass
class DemoApp(MDApp):
def build(self):
global root_app
# self.theme_cls.theme_style = "Light"
self.theme_cls.primary_palette = "Yellow"
Builder.load_string(c)
root_app=BuildApp()
return root_app
DemoApp().run()
Since I can't accomplish the task, I manually coded a new MDTopAppBar for each MDScreen - It sucks, I know - but it's the only way I can implement my ideas given my limited knowledge of KivyMD. I hope you guys can help me. Thanks.
I'm trying to write an program for the phone in python using kivy md. The program dynamically adds modules to a page to be counted. I've already got that part sorted in simple kivy.
I'm now trying to replicate it in KivyMD because I can use a navigation drawer and it's screen manager. The program has 2 screens.
Is there way to change the state of the buttons in the action items according to the screen that is active?
So I'm trying to have 2 overlapped buttons on the right side of the toolbar and show button1 when screen 1 is active and hide button2 and vice-versa.
I used the example from KivyMD documentation on the NavDrawer with the Screen manager and built on that. The left action items is used for the navigation drawer and I am trying to add 2 more buttons on the right side an change their state according to the active screen.
I only managed to add one but I don't know how to add the second one and how to change their state.
Please see below the code I am using:
python file
from kivy.lang import Builder
from kivy.properties import ObjectProperty
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.app import MDApp
from kivymd.uix.scrollview import MDScrollView
class ContentNavigationDrawer(MDScrollView):
screen_manager = ObjectProperty()
nav_drawer = ObjectProperty()
class AbacApp(MDApp):
def build(self):
self.theme_cls.primary_palette = "Orange"
self.theme_cls.theme_style = "Dark"
return Builder.load_file('main.kv')
if __name__ == '__main__':
AbacApp().run()
kv file
<ContentNavigationDrawer>
MDBoxLayout:
orientation: "vertical"
MDAnchorLayout:
anchor_y: "top"
MDList:
TwoLineAvatarListItem:
text: "Abacu' lu' Lysu"
secondary_text: "Lisandru numara"
ImageLeftWidget:
source: "img.png"
MDList:
OneLineListItem:
text: "Module"
on_press:
root.nav_drawer.set_state("close")
root.screen_manager.current = "scr 1"
OneLineListItem:
text: "Printare"
on_press:
root.nav_drawer.set_state("close")
root.screen_manager.current = "scr 2"
MDScreen:
MDBottomAppBar:
MDTopAppBar:
pos_hint: {"bottom": 1}
elevation: 4
icon: "plus"
title: "Abacu' lu' Lisandru"
left_action_items: [["menu", lambda x: nav_drawer.set_state("open")]]
on_action_button:
id: add_module
app.callback()
on_action_button:
id: print_modules
app.callback()
mode: "end"
MDNavigationLayout:
MDScreenManager:
id: screen_manager
MDScreen:
name: "scr 1"
MDLabel:
text: "Screen 1"
halign: "center"
MDScreen:
name: "scr 2"
MDLabel:
text: "Screen 2"
halign: "center"
MDNavigationDrawer:
id: nav_drawer
radius: (0, 16, 16, 0)
ContentNavigationDrawer:
screen_manager: screen_manager
nav_drawer: nav_drawer
I know how to write an app with kivy and I understand how to make a KivyMD app that has a navigation drawer. I can make the apps run individually but how do I combine the two?
I am new to coding and I am stuck here. Below are the codes for two mock-up apps for training purposes only. The first is a very simple app called "+5 Game" that allows the user to click a button to add 5 to the total which is then displayed in the GUI.
The second is a KivyMD app with a navigation drawer that contains two buttons. One to go to the home screen and one to go to the "+5 Game"
How do I link the button in the navigation draw to the +5 game?
And what do I do about the imports at the top of the file?
This is the code for the +5 Game:
from kivymd.app import MDApp
from kivymd.uix.screen import Screen
from kivymd.uix.label import MDLabel
from kivymd.uix.button import MDRectangleFlatButton
class ClickToAdd(MDApp):
def build(self):
self.screen = Screen()
self.num = 0
self.display_number = MDLabel(text="0", font_style="H1", halign="center",
pos_hint={'center_x': 0.5, 'center_y': 0.8})
self.add5_BTN = MDRectangleFlatButton(text="+5", pos_hint={'center_x': 0.5, 'center_y': 0.65},
on_release=self.add5_CMD)
self.screen.add_widget(self.display_number)
self.screen.add_widget(self.add5_BTN)
return self.screen
def add5_CMD(self, *args):
self.num = self.num + 5
self.display_number.text = str(self.num)
ClickToAdd().run()
This is the main GUI of the KivyMD app with a navigation drawer and a screen manager:
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
from kivymd.app import MDApp
KV = '''
<ContentNavigationDrawer>:
ScrollView:
MDList:
OneLineListItem:
text: "Home"
on_press:
root.nav_drawer.set_state("close")
root.screen_manager.current = "home"
OneLineListItem:
text: "Play +5 Game"
on_press:
root.nav_drawer.set_state("close")
root.screen_manager.current = "plus5game"
Screen:
MDToolbar:
id: toolbar
pos_hint: {"top": 1}
elevation: 10
title: "Navigation Drawer Test"
left_action_items: [["menu", lambda x: nav_drawer.set_state("open")]]
MDNavigationLayout:
x: toolbar.height
ScreenManager:
id: screen_manager
Screen:
name: "home"
MDLabel:
text: "Home Screen Stuff Goes Here"
halign: "center"
Screen:
name: "plus5game"
MDLabel:
text: "+5 Game Goes here"
halign: "center"
MDNavigationDrawer:
id: nav_drawer
ContentNavigationDrawer:
screen_manager: screen_manager
nav_drawer: nav_drawer
'''
class ContentNavigationDrawer(BoxLayout):
screen_manager = ObjectProperty()
nav_drawer = ObjectProperty()
class TestNavigationDrawer(MDApp):
def build(self):
return Builder.load_string(KV)
TestNavigationDrawer().run()
You cannot run one App inside another App, but you can use the guts of another App inside the first. In your case, you can redefine the the Plus5 App like this:
from kivymd.app import MDApp
from kivymd.uix.screen import Screen
from kivymd.uix.label import MDLabel
from kivymd.uix.button import MDRectangleFlatButton
class Plus5Screen(Screen):
def __init__(self, **kwargs):
super(Plus5Screen, self).__init__(**kwargs)
self.num = 0
self.display_number = MDLabel(text="0", font_style="H1", halign="center",
pos_hint={'center_x': 0.5, 'center_y': 0.8})
self.add5_BTN = MDRectangleFlatButton(text="+5", pos_hint={'center_x': 0.5, 'center_y': 0.65},
on_release=self.add5_CMD)
self.add_widget(self.display_number)
self.add_widget(self.add5_BTN)
def add5_CMD(self, *args):
self.num = self.num + 5
self.display_number.text = str(self.num)
class ClickToAdd(MDApp):
def build(self):
self.screen = Plus5Screen()
return self.screen
if __name__=='__main__':
ClickToAdd().run()
and save this is a file named plus5.py.
Then in you main App, you can just reference this in the 'kv':
KV = '''
#:import Plus5Screen plus5 # import the guts of the Plus5 game
<ContentNavigationDrawer>:
ScrollView:
MDList:
OneLineListItem:
text: "Home"
on_press:
root.nav_drawer.set_state("close")
root.screen_manager.current = "home"
OneLineListItem:
text: "Play +5 Game"
on_press:
root.nav_drawer.set_state("close")
root.screen_manager.current = "plus5game"
Screen:
MDToolbar:
id: toolbar
pos_hint: {"top": 1}
elevation: 10
title: "Navigation Drawer Test"
left_action_items: [["menu", lambda x: nav_drawer.set_state("open")]]
MDNavigationLayout:
x: toolbar.height
ScreenManager:
id: screen_manager
Screen:
name: "home"
MDLabel:
text: "Home Screen Stuff Goes Here"
halign: "center"
Plus5Screen: # this creates the guts of the Plu5 game
name: "plus5game"
MDNavigationDrawer:
id: nav_drawer
ContentNavigationDrawer:
screen_manager: screen_manager
nav_drawer: nav_drawer
'''
I'm beginner in using kivymd and trying to switch between screens within the NavigationDrawer using KivyMD, I was reading some of the documents and ended up with this code but it's not working with me:
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
from kivymd.theming import ThemableBehavior
from kivymd.uix.list import MDList
from kivymd.app import MDApp
Window.size = (300, 500)
navigation_helper = """
Screen:
MDToolbar:
id: toolbar
pos_hint: {"top": 1}
elevation: 10
title: "MDNavigationDrawer"
left_action_items: [["menu", lambda x: nav_drawer.set_state("open")]]
NavigationLayout:
x: toolbar.height
ScreenManager:
id: screen_manager
Screen:
name: "scr 1"
MDLabel:
text: "Go to Hell"
halign: "center"
Screen:
name: "scr 2"
MDLabel:
text: "Hell"
halign: "center"
MDNavigationDrawer:
id: nav_drawer
ContentNavigationDrawer:
screen_manager: screen_manager
nav_drawer: nav_drawer
ScrollView:
MDList:
OneLineListItem:
text: "Screen 1"
on_press:
root.nav_drawer.set_state("close")
root.screen_manager.current = "scr 1"
OneLineListItem:
text: "Screen 2"
on_press:
root.nav_drawer.set_state("close")
root.screen_manager.current = "scr 2"
"""
class DemoApp(MDApp):
class ContentNavigationDrawer(BoxLayout):
screen_manager = ObjectProperty()
nav_drawer = ObjectProperty()
class DrawerList(ThemableBehavior, MDList):
pass
def build(self):
screen = Builder.load_string(navigation_helper)
return screen
def on_start(self):
pass
DemoApp().run()
But it's giving me this error " AttributeError: 'Screen' object has no attribute 'nav_drawer'", I'm not sure what I've done incorrect.
When you are referencing an object using an id within the same rule where the id is defined, you do not need to prepend it with root:
OneLineListItem:
text: "Screen 1"
on_press:
nav_drawer.set_state("close")
screen_manager.current = "scr 1"
OneLineListItem:
text: "Screen 2"
on_press:
nav_drawer.set_state("close")
screen_manager.current = "scr 2"
I am trying to add the new connect screen. I am using screen manager.
I also updated the kv file. I was able to run the app with one screen, when I added new screen, I am getting the below error :
raise FactoryException('Unknown class <%s>' % name)
kivy.factory.FactoryException: Unknown class <ConnectScreen>
Now My firstapp.kv is as below :
...
#:import AboutScreen screens
#:import ContactScreen screens
NavigationLayout:
id: nav_layout
MDNavigationDrawer:
id: nav_drawer
NavigationDrawerToolbar:
title: 'Menu'
NavigationDrawerIconButton:
icon: 'arrow-right-drop-circle'
text: 'About Us'
on_release: app.root.ids.scr_mngr.current = 'about'
NavigationDrawerIconButton:
icon: 'arrow-right-drop-circle'
text: 'Connect Us'
on_release: app.root.ids.scr_mngr.current = 'connect'
BoxLayout:
orientation: 'vertical'
Toolbar:
id: toolbar
title: 'Main Dashboard'
md_bg_color: app.theme_cls.primary_color
background_palette: 'Primary'
background_hue: '500'
left_action_items: [['menu', lambda x: app.root.toggle_nav_drawer()]]
ScreenManager:
id: scr_mngr
AboutScreen:
ConnectScreen:
Now I have also updated the Builder.load.string
my connect.py is as below :
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
Builder.load.string("""
<AboutScreen>
name: 'connect'
ScrollView:
id: scroll
do_scroll_x: False
BoxLayout:
orientation: 'vertical'
size_hint_y: None
height: dp(800)
padding: dp(15)
spacing: dp(15)
Image:
source: './img/connect.jpeg'
allow_stretch: True
""")
class ConnectScreen(Screen):
pass
How can I solve this?
Found the issue.
My __init__.py ( in screens folder) was not updated.
After I updated my __init__.py, it worked.
from .contact import ContactScreen