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
Related
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'm new working with kivymd and I need to generate an app with two screens, the second screen shows a TwoLineListItem inside a recycleview, I need to bind a function that takes the text on the selected row a put it in a text field of the main window, but I'm getting this error:
TypeError: click_supplier() missing 1 required positional argument: 'supplier_list_item'
Here's a similar example of my code:
PY
from kivy.lang import Builder
from kivymd.app import MDApp
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import Screen, ScreenManager
from kivymd.uix.list import OneLineListItem, TwoLineListItem
from kivy.uix.recycleview import RecycleView
from kivy.metrics import dp
suppliers=['Amazon', 'Ebay', 'Alibaba', 'Linio', 'Aliexpress']
suppliers_id=['198', '283', '343', '454', '203']
class MainWindow(Screen):
pass
class SelectSupplierWindow(Screen):
pass
class BrisaWindowManager(ScreenManager):
pass
class MainApp(MDApp):
#define build parameters
product_dialog=None
selected_products_list=[]
def build(self):
self.theme_cls.theme_style="Light"
self.theme_cls.primary_palette="Green"
return Builder.load_file('example.kv')
def go_to_screen(self, screen):
self.root.current=screen
#start suppliers list
def on_start(self):
self.set_list_of_suppliers()
#Autofill supplier search field--------------------------------------------------
def set_list_of_suppliers(self, text="", search=False):
def add_supplier_item(name_supplier):
self.root.get_screen('select_supplier').ids.suppliers_rv.data.append(
{
"viewclass": "TwoLineListItem",
"text": name_supplier,
"secondary_text": f'Code: {suppliers_id[suppliers.index(name_supplier)]}',
"on_release": self.click_supplier,
}
)
self.root.get_screen('select_supplier').ids.suppliers_rv.data = []
for name_supplier in suppliers:
if search:
if text.lower() in name_supplier.lower():
add_supplier_item(name_supplier)
else:
add_supplier_item(name_supplier)
def click_supplier(self, supplier_list_item):
self.root.get_screen('main').ids.oc_supplier.text=supplier_list_item.text
self.go_to_screen('main')
MainApp().run()
KV
BrisaWindowManager:
MainWindow:
id:main_window
SelectSupplierWindow:
<MainWindow>
name: 'main'
MDBoxLayout:
orientation: 'vertical'
MDToolbar:
title: 'Brisa'
MDBottomNavigation:
MDBottomNavigationItem:
id: oc_screen
name: 'screen 1'
text: 'Purchase'
icon: 'clipboard-list'
MDBoxLayout:
orientation: 'vertical'
padding:dp(20)
spacing: dp(15)
MDTextField:
id: oc_supplier
hint_text: 'Select'
helper_text: 'Select'
helper_text_mode: 'on_focus'
mode: 'fill'
halign:'center'
on_focus:
app.root.current='select_supplier'
root.manager.transition.direction='up'
MDBottomNavigationItem:
name: 'screen 2'
text: 'Check'
icon: 'truck-check'
<SelectSupplierWindow>
name:'select_supplier'
MDBoxLayout:
orientation: 'vertical'
MDToolbar:
title: 'Select'
left_action_items: [['arrow-left', lambda x: app.go_to_screen(screen='main'), 'back']]
MDBoxLayout:
orientation:'vertical'
spacing: dp(10)
padding: dp(20)
MDBoxLayout:
adaptive_height:True
MDIconButton:
icon: 'magnify'
MDTextField:
id: search_field
on_text: app.set_list_of_suppliers(self.text, True)
RecycleView:
id: suppliers_rv
key_viewclass: 'viewclass'
key_size: 'height'
RecycleBoxLayout:
padding: dp(10)
default_size: None, dp(60)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
The error triggered because the click item function needs the clicked row but I haven't been able to bind this event to the function.
How about changing your add_supplier_item() method to:
def add_supplier_item(name_supplier):
self.root.get_screen('select_supplier').ids.suppliers_rv.data.append(
{
"viewclass": "TwoLineListItem",
"text": name_supplier,
"secondary_text": f'Code: {suppliers_id[suppliers.index(name_supplier)]}',
"on_release": partial(self.click_supplier, name_supplier),
}
)
And your click_supplier() method to:
def click_supplier(self, supplier_list_item):
self.root.get_screen('main').ids.oc_supplier.text=supplier_list_item
self.go_to_screen('main')
Rather than trying to pass the item, just pass the text.
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
I have this python file
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty
from kivymd.app import MDApp
from kivy.lang import Builder
from kivymd.theming import ThemableBehavior, ThemeManager
from kivymd.uix.list import OneLineIconListItem, MDList
class ContentNavigationDrawer(BoxLayout):
pass
class ItemDrawer(OneLineIconListItem):
icon = StringProperty()
class MainApp(MDApp):
def on_start(self):
icons_item = {
'bug': 'Files'
}
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])
)
class DrawerList(ThemableBehavior, MDList):
def set_color_item(self, instance_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
MainApp().run()
And this .kv file
See Line 3, the error, comes there that screen_manager is not defined
<ItemDrawer>:
theme_text_color: "Custom"
on_release: screen_manager.current = 'screen2'
IconLeftWidget:
id: icon
icon: root.icon
theme_text_color: "Custom"
text_color: 0,0,0,1
<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: "250", "250"
source: "logo.jpg"
ScrollView:
DrawerList:
id: md_list
NavigationLayout:
ScreenManager:
id: screen_manager
Screen:
name: 'screen1'
BoxLayout:
orientation: 'vertical'
Widget:
canvas:
Color:
rgba: 0,1,0.2117647058823529,0.3
Rectangle:
size: self.size
pos: self.pos
MDNavigationDrawer:
id: nav_drawer
ContentNavigationDrawer:
id: content_drawer
Screen:
name: 'screen2'
When I click on the item in the navigation drawer, it says that screen_manager is not defined
What am I doing wrong? I searched the internet a lot but couldnot find anything useful
Help me please, how do i change screens?
The MDNavigation Drawer should be at the same indent level as the ScreenManager. Furthermore,
MDNavigationLayout:
screen_manager:screen_manager
ScreenManager:
id: screen_manager
Screen:
name: 'screen1'
BoxLayout:
orientation: 'vertical'
MDToolbar:
title: "Navigation Drawer"
elevation: 10
left_action_items: [['menu', lambda x:nav_drawer.set_state("open")]]
Widget:
Screen:
name: 'screen2'
MDNavigationDrawer:
id: nav_drawer
ContentNavigationDrawer:
id: content_drawer
add the
screen_manager:screen_manager
beneath the NavigationLayout so that it can be accessed as an ObjectProperty. Finally change the ItemDrawer callback from
on_release: screen_manager.current = 'screen2'
to
on_release: app.root.screen_manager.current = 'screen2'
Finally you can also add
nav_drawer: nav_drawer
beneath your root window and just ontop/below the line screen_manager: screen_manager
This enables for dismissing of the navigation drawer when the new screen pops up.
then update your callback to this:
on_release:
app.root.screen_manager.current = 'screen2'
app.root.nav_drawer.set_state('close')
I'm writing a kivy program/game. I've made one before, but was only 1 screen in total. I've started developing a new program with ideas of implementing a Screen Manager. I managed to build the Screen Manager inside of the python file, but it wasn't suitable for my long term usage, and I wanted to try my hand at a Screen Manager from the .kv file.
Any guidance will be greatly appreciated, not sure what I missed. I looked at this questionv(Kivy - Screen Manager - Accessing attribute in other class), and pieced together what I thought was right, but still can't get a screen to load - I feel this is a simple answer and I'm being blind...
main.py;
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
class MenuScreen(Screen):
pass
class NewGameScreen(Screen):
pass
class LoadGameScreen(Screen):
pass
class ASCIILifeApp(App):
pass
if __name__ == "__main__":
ASCIILifeApp().run()
ASCIILife.kv;
#: kivy 1.9
#: import ScreenManager kivy.uix.screenmanager.ScreenManager
#: import Screen kivy.uix.screenmanager.ScreenManager
#: import NewGameScreen screen
#: import LoadGameScreen screen
ScreenManager:
id: screen_manager
#transition: FadeTransition()
MenuScreen:
id: menu_screen
name: 'MenuScreen'
manager: 'screen_manager'
NewGameScreen:
id: newgame_screen
name: 'NewGameScreen'
manager: 'screen_manager'
LoadGameScreen:
id: loadgame_screen
name: 'LoadGameScreen'
manager: 'screen_manager'
<MenuScreen>:
BoxLayout:
orientation: 'vertical'
Label:
text: 'ASCII Life'
font_size: 50
Button:
text: 'New Game'
font_size: 30
on_release: app.root.current = 'newgame'
Button:
text: 'Load Game'
font_size: 30
on_release: app.root.current = 'loadgame'
Button:
text: 'Settings'
font_size: 30
on_release: app.root.current = 'something'
<NewGameScreen>:
BoxLayout:
orientation: 'vertical'
BoxLayout:
orientation: 'vertical'
Label:
text: 'Game Length in Days'
font_size: 30
BoxLayout:
orientation: 'horizontal'
ToggleButton:
text: '100'
state: 'down'
group: 'newgame_days'
font_size: 30
ToggleButton:
text: '200'
group: 'newgame_days'
font_size: 30
BoxLayout:
orientation: 'horizontal'
ToggleButton:
text: '365'
group: 'newgame_days'
font_size: 30
ToggleButton:
text: '3650'
group: 'newgame_days'
font_size: 30
ToggleButton:
text: 'Unlimited'
group: 'newgame_days'
font_size: 30
BoxLayout:
orientation: 'vertical'
size_hint: (1, .5)
Label:
text: 'Difficulty (Score Multiplier)'
font_size: 30
BoxLayout:
orientation: 'horizontal'
ToggleButton:
text: 'Easy (x1)'
state: 'down'
group: 'newgame_difficulty'
font_size: 30
ToggleButton:
text: 'Medium (x2.5)'
group: 'newgame_difficulty'
font_size: 30
ToggleButton:
text: 'Hard (x5)'
group: 'newgame_difficulty'
font_size: 30
<LoadGameScreen>:
BoxLayout:
orientation: 'vertical'
Label:
text: 'load a game'
font_size: 30
Widget:
canvas:
Ellipse:
pos: self.pos
size: self.size
BoxLayout:
Button:
text: 'Menu'
font_size: 30
on_release: app.root.current = 'menu'
Button:
text: 'text'
font_size: 30
Edit: Truncated kv file
The answer was using a builder to build the kv file. Knew it was something simple. File below;
main.py
#!/usr/bin/kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.properties import ObjectProperty
class MenuScreen(Screen):
pass
class NewGameScreen(Screen):
pass
class LoadGameScreen(Screen):
pass
class ScreenManager(ScreenManager):
pass
buildKV = Builder.load_file("ASCIILife.kv")
class ASCIILifeApp(App):
def build(self):
return buildKV
if __name__ == "__main__":
ASCIILifeApp().run()
To elaborate on Chazara's findings:
Either rename the kv code file according to the naming convension:
Kivy looks for a Kv file with the same name as your App class in
lowercase, minus “App” if it ends with ‘App’.
From the documentation:how to load kv language
Or just make it explicit with the builder function:
Builder.load_file('path/to/file.kv')
To elaborate on Chazara's findings even more:
i tested the code from Chazara with kivy 1.10.1dev0 and Python 3.6; i got an error saying:
kivy.uix.screenmanager.ScreenManagerException: No Screen with name "something".
to fix it, i changed in the .kv file
[...]
Button:
text: 'New Game'
font_size: 30
on_release: app.root.current = 'newgame'
[...]
to:
[...]
Button:
text: 'New Game'
font_size: 30
on_release: app.root.current = 'NewGameScreen'
[...]
it references the name of NewGameScreen given in the ScreenManager
ScreenManager:
[...]
NewGameScreen:
id: newgame_screen
*name: 'NewGameScreen'*
manager: 'screen_manager'