How to connect carousel with navigation bar in kivymd? - kivy

I am making an app in kivymd where there is a bottom navigation bar with three bottom nav elements(home, plus, profile). I want That on pressing home a carousel with a three line avatar list get's shown. But if a write my code under navigation element (home) it sort of comes in middle. And if I write the code inside main boxlayout the content of other buttons comes underneath.
following is my code with code under nav element being commented:
from kivymd.app import MDApp
from kivy.core.window import Window
from kivy.lang import Builder
Window.size = (375, 667)
kv = """
BoxLayout:
orientation:'vertical'
padding: 0
MDToolbar:
title: "Ad 'O Square"
md_bg_color: 1, 1, 1, 1
specific_text_color: app.theme_cls.accent_color
elevation: 10
Carousel:
direction: "right"
Image:
source: "Colors/red.jpg"
Image:
source: "Colors/green.png"
Image:
source: "Colors/blue.png"
ThreeLineAvatarListItem:
text: "Product 1"
secondary_text: "Short Text"
tertiary_text: "Rating"
ImageLeftWidget:
source: "Colors/red.jpg"
ThreeLineAvatarListItem:
text: "Product 2"
secondary_text: "Short Text"
tertiary_text: "Rating"
ImageLeftWidget:
source: "Colors/blue.png"
ThreeLineAvatarListItem:
text: "Product 3"
secondary_text: "Short Text"
tertiary_text: "Rating"
ImageLeftWidget:
source: "Colors/green.png"
MDBottomNavigation:
panel_color: 1, 1, 1, 1
MDBottomNavigationItem:
name: 'screen 1'
text: 'home'
icon: 'home'
# Carousel:
# direction: "right"
# Image:
# source: "Colors/red.jpg"
# Image:
# source: "Colors/green.png"
# Image:
# source: "Colors/blue.png"
# ThreeLineAvatarListItem:
# text: "Product 1"
# secondary_text: "Short Text"
# tertiary_text: "Rating"
#
# ImageLeftWidget:
# source: "Colors/red.jpg"
#
#
# ThreeLineAvatarListItem:
# text: "Product 2"
# secondary_text: "Short Text"
# tertiary_text: "Rating"
#
# ImageLeftWidget:
# source: "Colors/blue.png"
#
#
# ThreeLineAvatarListItem:
# text: "Product 3"
# secondary_text: "Short Text"
# tertiary_text: "Rating"
#
# ImageLeftWidget:
# source: "Colors/green.png"
MDBottomNavigationItem:
name: 'screen 2'
icon: 'plus-circle-outline'
MDLabel:
text: "Screen 2"
halign: "center"
MDBottomNavigationItem:
name: 'screen 3'
text: 'profile'
icon: 'account'
MDLabel:
text: 'Profile'
halign: 'center'
"""
class App(MDApp):
def build(self):
self.theme_cls.accent_palette = "Red"
screen = Builder.load_string(kv)
return screen
if __name__ == '__main__':
App().run()
this is the output
and this is the output when I write the code inside bottom navigation element

Related

How can I modify the title of the MDTopAppBar when a button, located in a separate class, is clicked?

How can I modify the title of the MDTopAppBar in response to a user selecting a button within the NavigationDrawer, such as updating the title to match the selected button's label (e.g. "Coffee")?
main.py
from kivy.lang import Builder
from kivy.properties import ObjectProperty
from kivy.uix.screenmanager import ScreenManager, Screen
from kivymd.app import MDApp
from kivymd.uix.scrollview import MDScrollView
class MainLayout(Screen):
pass
class NavigationDrawer(MDScrollView):
screen_manager = ObjectProperty()
nav_drawer = ObjectProperty()
class App(MDApp):
def build(self):
self.theme_cls.primary_palette = "Green"
self.theme_cls.theme_style = "Light"
kivy_layout = Builder.load_file("layout.kv")
return MainLayout()
if __name__ == "__main__":
App().run()
layout.kv
<NavigationDrawer>
MDNavigationDrawerMenu:
MDNavigationDrawerHeader:
title: "MyApp"
text: "Bottom Text"
source: "icon64.png"
spacing: "10dp"
MDNavigationDrawerDivider:
MDNavigationDrawerItem:
text: "Coffee"
icon: "coffee"
on_press:
root.nav_drawer.set_state("close")
root.screen_manager.current = "scr 1"
MDNavigationDrawerItem:
text: "History"
icon: "history"
on_press:
root.nav_drawer.set_state("close")
root.screen_manager.current = "scr 2"
MDNavigationDrawerItem:
text: "Settings"
icon: "cog"
on_press:
root.nav_drawer.set_state("close")
root.screen_manager.current = "scr 3"
MDNavigationDrawerDivider:
<MainLayout>
MDScreen:
MDTopAppBar:
id: top
title: "Title"
pos_hint: {"top": 1}
elevation: 4
left_action_items: [["menu", lambda x: nav_drawer.set_state("open")]]
MDNavigationLayout:
MDScreenManager:
id: screen_manager
MDScreen:
name: "scr 1"
MDLabel:
text: "Coffee"
halign: "center"
MDScreen:
name: "scr 2"
MDLabel:
text: "History"
halign: "center"
MDScreen:
name: "scr 3"
MDLabel:
text: "Settings"
halign: "center"
MDNavigationDrawer:
id: nav_drawer
radius: (0, 16, 16, 0)
NavigationDrawer:
screen_manager: screen_manager
nav_drawer: nav_drawer
After attempting to resolve the issue on my own through various means, including attempting to create a solution and conducting research online for potential solutions, I was unable to find a satisfactory resolution. As a result, I have determined it necessary to seek assistance through this platform.
You need to add an id to the MDNavigationDrawerHeader so you can access it from the class.
MDNavigationDrawerHeader:
id: drawer_header
title: "MyApp"
text: "Bottom Text"
source: "icon64.png"
spacing: "10dp"
Then you need to add a method to the NaviagtionDrawer class to make the update. You will access your NavDrawer Title by calling self.ids.drawer_header.title
class NavigationDrawer(MDScrollView):
screen_manager = ObjectProperty()
nav_drawer = ObjectProperty()
def set_title(self, title):
self.ids.drawer_header.title = title
Finally, you need to tell each button to call the set_title method that I created to actually do the update.
MDNavigationDrawerItem:
text: "Coffee"
icon: "coffee"
on_press:
root.nav_drawer.set_state("close")
root.set_title(self.text)
root.screen_manager.current = "scr 1"
To change the MDTopAppBar title add the following line to each of the on_press events:
app.change_title(self.text) # call method in main app
ie.
on_press:
root.nav_drawer.set_state("close")
root.set_title(self.text)
root.screen_manager.current = "scr 1"
app.change_title(self.text) # call method in main app
Then add the following method to your main app.
def change_title(self, title):
self.root.ids.top.title = title
ie.
def build(self):
self.theme_cls.primary_palette = "Green"
self.theme_cls.theme_style = "Light"
Builder.load_file("layout.kv")
return MainLayout()
def change_title(self, title):
self.root.ids.top.title = title

How to remove widget in Kivy and then create again?

I am using Kivy and Kivymd.
There is a class Detail in my code where I am creating a card. I need to remove any card before creating a new card.
I have a func remove. I can use it to remove any cards, then create a new card. But I need to implement removing and creating in one func add.
My py file
from kivymd.app import MDApp
from kivy.uix.screenmanager import Screen, ScreenManager
from kivymd.uix.label import MDLabel
from kivymd.uix.card import MDCard
class WindowManager(ScreenManager):
pass
class Detail(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def add(self, instance):
# self.remove()
article = self.ids.article.text
card = MDCard(size_hint=(None, None), padding=20)
my_label = MDLabel(text=article)
card.add_widget(my_label)
self.ids.box.add_widget(card)
def remove(self):
self.ids.boxlayout_1.clear_widgets()
self.add_widget(Detail())
class Container(Screen):
pass
class App(MDApp):
def build(self):
return WindowManager()
App().run()
my app.kv
<WindowManager>:
Container:
name: 'container'
Detail:
name: 'detail'
<Container>
MDRaisedButton:
pos_hint: {'center_x': .5, 'center_y': .5}
text: 'Go To Detail'
on_release: root.manager.current = 'detail'
<Detail>
BoxLayout:
id: boxlayout_1
orientation: 'vertical'
MDToolbar:
title: 'App'
Button:
id: btn
text: 'Remove Cards'
on_release: root.remove()
MDTextField:
id: article
hint_text: 'Input article'
helper_text_mode: "on_focus"
mode: 'rectangle'
MDRaisedButton:
id: me
text: 'add'
pos_hint: {'center_x': .5, 'center_y': .5}
on_release: root.add(root)
ScrollView:
MDList:
spacing: 5
id: box
Your remove() method is removing more than just the cards. Try changing it to just remove the Widgets in the MDList, like this:
def remove(self):
self.ids.box.clear_widgets()
Then the add() method can just call remove(), like this:
def add(self, instance):
self.remove()
article = self.ids.article.text
card = MDCard(size_hint=(None, None), padding=20)
my_label = MDLabel(text=article)
card.add_widget(my_label)
self.ids.box.add_widget(card)

How do I re-use MDNavigationDrawer without re-typing the code kivymd

I've got the below MDNavigationDrawer code but the problem is I repeat it on every screen, which is just making the code longer unessecarily. How do I write the below code once and re-use it on every screen?
<Example>:
name: "example"
NavigationLayout:
id: nav_layout
MDNavigationDrawer:
NavigationDrawerIconButton:
text: "My Conversations"
on_release: app.root.current = "conversations"
icon: "chat-outline"
NavigationDrawerIconButton:
text: "Personal Details"
on_release: app.root.current = "details"
icon: "settings"
NavigationDrawerIconButton:
text: "Logout"
on_release: root.clear_details()
on_release: app.root.current = "login"
icon: "account"
Try using a dynamic class:
<MyNavDrawer#MDNavigationDrawer>:
NavigationDrawerIconButton:
text: "My Conversations"
on_release: app.root.current = "conversations"
icon: "chat-outline"
NavigationDrawerIconButton:
text: "Personal Details"
on_release: app.root.current = "details"
icon: "settings"
NavigationDrawerIconButton:
text: "Logout"
on_release: root.clear_details()
on_release: app.root.current = "login"
icon: "account"
Then use it as:
<Example>:
name: "example"
NavigationLayout:
id: nav_layout
MyNavDrawer:
There may be an issue with the line on_release: root.clear_details(), since root may not end up pointing at the correct instance.

Reusing code in kivy

how can I reuse such code in kv lang?
<Search_type_panel>:
max1_optn: max1
max2_optn: max2
both_optn: both
BoxLayout:
padding: "10dp"
orientation: 'vertical'
BoxLayout:
orientation: 'horizontal'
CheckBox:
id: max1
active: True
group: 'search_type'
Label:
text: "[ref=max1]max1[/ref]"
size_hint_x: "10"
markup: True
on_ref_press: root.setstatus(max1)
CheckBox:
id: max2
active: False
group: 'search_type'
Label:
text: "[ref=max2]max2[/ref]"
size_hint_x: "10"
markup: True
on_ref_press: root.setstatus(max2)
CheckBox:
id: both
active: False
group: 'search_type'
Label:
text: "[ref=both]both[/both]"
size_hint_x: "10"
markup: True
on_ref_press: root.setstatus(max2)
As you can see Label and Checkbox can be a grouped composite panel and I have to just supply different parameters to each one, so on the long run maintenance is simple enough, but How do I pass new parameters to these guys? While I know I can group them as:
<custom>:
CheckBox:
id: both
active: False
group: 'search_type'
Label:
text: "[ref=both]both[/both]"
size_hint_x: "10"
markup: True
on_ref_press: root.setstatus(max2)
I don't really know how to pass new parameters to the widgets and reuse the kv lang code.
Reuse code in kv File
Dynamic Classes
Since each CheckBox has a different active value (True or False), it is not recommended to create a dynamic class containing both CheckBox and Label because it is difficult to reference the CheckBox and assign different id and active value to each of them when it is instantiated as a children.
Snippets
<Custom>:
CheckBox:
active: False
group: 'search_type'
Label:
size_hint_x: "10"
markup: True
on_ref_press: app.root.setstatus(self)
Example
The example below creates two dynamice classes for CheckBox and Label respectively.
main.py
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
class Search_type_panel(BoxLayout):
max1_optn = ObjectProperty(None)
max2_optn = ObjectProperty(None)
both_optn = ObjectProperty(None)
def setstatus(self, label):
print("\nsetstatus:")
for key in label.refs:
print("\tUser clicked on refs =", key)
class TestApp(App):
def build(self):
return Search_type_panel()
if __name__ == "__main__":
TestApp().run()
test.kv
#:kivy 1.10.0
<CustomCheckBox#CheckBox>:
active: False
group: 'search_type'
<CustomLabel#Label>:
size_hint_x: "10"
markup: True
on_ref_press: app.root.setstatus(self)
<Search_type_panel>:
max1_optn: max1
max2_optn: max2
both_optn: both
BoxLayout:
padding: "10dp"
orientation: 'vertical'
BoxLayout:
orientation: 'horizontal'
CustomCheckBox:
id: max1
active: True
CustomLabel:
text: "[ref=max1]max1[/ref]"
CustomCheckBox:
id: max2
CustomLabel:
text: "[ref=max2]max2[/ref]"
CustomCheckBox:
id: both
CustomLabel:
text: "[ref=both]both[/ref]"
Output

Cannot access class variable outside class - kivy

Anytime i try to run my app i get error.
Error: AttributeError: 'NoneType' object has no attribute 'text'
See code snippet below
class Login(Screen):
email_obj = ObjectProperty()
password_obj = ObjectProperty()
conn = lite.connect("database/nairamanager.db")
cursor = conn.cursor()
def init(self, **kwargs):
super().__init__(**kwargs)
# Display an alert on login validation
def login_alert(self):
p = LoginAlert()
p.open()
# Get user from database
def login_nm_user(self):
self.cursor.execute("SELECT * FROM user_tb WHERE email_db = ? AND password_db = ?;", (self.email_obj.text, self.password_obj.text))
if self.cursor.fetchall():
self.manager.current = "news_feed_screen"
else:
return self.login_alert()
self.conn.commit()
# self.conn.close
# Get user email
def get_user_email(self):
self.cursor.execute("SELECT * FROM user_tb WHERE email_db = ?;", (self.email_obj.text))
self.user_email = self.cursor.fetchone()[0]
self.conn.commit()
print(self.user_email)
login = Login()
login.get_user_email()
print(login.user_email)
.kv code
Below is the Login class in the kivy lang file
<Login>:
email_obj: email_text
password_obj: password_text
GridLayout:
size: root.size
rows: 2
rows_minimum: {0:0,1:root.height*.7}
spacing: 50
GridLayout:
rows: 2
row_default_minimum: True
rows_minimum: {0:root.height*.1,1:root.height*.01}
BoxLayout:
orientation: "horizontal"
BackButton:
text: "L"
size_hint: (.1,1)
halign: "center"
markup: True
on_press:
root.manager.current = "login_signup_screen"
root.manager.transition.direction = "left"
TopLabel:
text: "[b]Lets get you logged in...[/b]"
size_hint: (.9,1)
BorderLabel:
# Login form
BoxLayout:
orientation: "vertical"
spacing: 20
UniTextInput:
id: email_text
hint_text: "Email"
size_hint: (.6,1)
pos_hint: {"center_x":.5}
UniTextInput:
id: password_text
hint_text: "Password"
password: True
size_hint: (.6,1)
pos_hint: {"center_x":.5}
GreenButton
id: main_login_button
text: "Login"
size_hint: (.6,1)
pos_hint: {"center_x":.5}
on_press:
root.login_nm_user()
root.get_user_email()
# Fake widget for spacing
Widget:
Widget:
Widget:
Please, how do i fix this?
To share a variable to all screens, you can make it an attribute of the screenmanager.
Like this:
from kivy.app import App
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.lang import Builder
from kivy.properties import StringProperty
class MyScreenManager(ScreenManager):
user_email = StringProperty()
class Login(Screen):
def login(self, user, pw):
# login
# if pass
self.manager.user_email = user
self.manager.current = "screen2"
root = Builder.load_string('''
MyScreenManager:
Login:
name: "login"
id: login
BoxLayout:
orientation: 'vertical'
TextInput:
id: email_input
TextInput:
id: password_input
Button:
text: "Login"
on_release: login.login(email_input.text, password_input.text)
Screen:
name: "screen2"
BoxLayout:
orientation: "vertical"
Label:
text: "Wellcome {}!".format(root.user_email)
Button:
text: "Go to screen 3"
on_release: root.current = "screen3"
Screen:
name: "screen3"
BoxLayout:
orientation: "vertical"
Label:
text: "Wellcome {}!".format(root.user_email)
Button:
text: "Go back to screen 2"
on_release: root.current = "screen2"
''')
class MyApp(App):
def build(self):
return root
MyApp().run()
That said, I see you define a init method. If you really want to overite the __init__, remember the underscores.
In this particular example, you dont really do anything in the init. super().__init__() gets executed anyways when you create a new Screen

Resources