I'm new to kivy and I want to change my screen by clicking the image. I used the ButtonBehavior and call the on_press method of my class ImageButton but I can't figure it out what code to put. I tried on_press: screen_manager.current = 'window1' on my kivy file but its not working
Python Code
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.image import Image
from kivy.uix.behaviors import ButtonBehavior
class Window1(Screen):
pass
class Window2(Screen):
pass
class WindowManager(ScreenManager):
pass
class ImageButton(ButtonBehavior, Image):
def on_press(self):
# what to call
class Phone(FloatLayout):
pass
class MyApp(App):
def build(self):
return Phone()
if __name__ == '__main__':
MyApp().run()
kv file
<Phone>:
AnchorLayout:
anchor_x: 'center'
anchor_y: 'top'
WindowManager:
id: screen_manager
size_hint: 1, 0.9
anchor_y: 'top'
transition: FadeTransition()
Window1:
Window2:
AnchorLayout:
anchor_x: 'center'
anchor_y: 'bottom'
BoxLayout:
canvas:
Color:
rgba: 228, 241, 254, 1
Rectangle:
size: self.size
orientation: 'horizontal'
size_hint: 1, .1
ImageButton:
source: 'pic1.png'
on_press: self.on_press()
ImageButton:
source: 'pic2.png'
on_press: self.on_press()
<Window1>:
name: 'window1'
Label:
text: 'Window1'
<Window2>:
name: 'window2'
Label:
text: 'Window2'
Some one help me on this.. what im missing is in my kv file i should put
on_press: app.root.ids._screen_manager.current = 'window1'
Here is the explanation
When the kv code is parsed, the id fields go into a dict called ids, that stores pointers to the widget objects.
Each kivy rule has a sperate name space for ids.
Breaking it down:
app.root.ids.screen_manager
app is your app
root is the root widget, Phone
ids is the dict of ids defined at the root level
Credit for Elliot Garbus
Related
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivymd.uix.screen import MDScreen
from kivymd.app import MDApp
KV = '''
<Screen3>
MDBoxLayout:
orientation:'vertical'
MDToolbar:
title: "Home"
left_action_items: [["menu", lambda x: app.callback()]]
AnchorLayout:
anchor_x: 'center'
anchor_y: 'top'
ScrollView:
size_hint:0.8,0.7
do_scroll_x:False
do_scroll_y:True
GridLayout:
size_hint_y:None
height:self.minimum_height
cols:1
spacing:10
padding:10
id:gr
'''
Builder.load_string(KV)
class Screen3(MDScreen):
pass
class Test(MDApp):
def build(self):
screen_manager = ScreenManager()
screen_manager.add_widget(Screen3(name='screen3'))
return screen_manager
Test().run()
This is my basic code right now. For some reason the reference error is caused by the left_action_items option. When I remove it the code works. I honestly have no idea what causes this issue.
I am trying build an app in Python using Kivymd and i just started learning this kivymd framework so the problem i am facing is when i am trying to change screen from LoginScreen to HomeScreen, it raises error. I am unable to understand what's wrong in my code.
I wanted it to change screen to HomeScreen and then show the list on pressing button 'Join Chat'.
Here is the code:
main.py
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen,ScreenManager
from kivymd.uix.list import MDList, OneLineIconListItem,IconLeftWidget
class LoginScreen(Screen):
pass
class HomeScreen(Screen):
pass
class DemoApp(MDApp):
def build(self):
self.theme_cls.theme_style="Dark"
self.sm=ScreenManager()
self.sm.add_widget(LoginScreen(name="login"))
self.sm.add_widget(HomeScreen(name="home"))
screen=Builder.load_file("helper_file.kv")
return screen
def do_login(self):
self.sm.current = "home"
for i in range(20):
st_name="student "
list_item = OneLineIconListItem(text=f"student {str(i)}")
list_item.add_widget(IconLeftWidget(icon= "alpha-a-box"))
self.root.ids.users_lst.add_widget(list_item)
DemoApp().run()
helper_file.kv
ScreenManager:
LoginScreen:
HomeScreen:
<LoginScreen>:
name: "login"
Screen:
MDLabel:
text: "Demo App"
halign: "center"
pos_hint: {"center_x": .5, "center_y": .8}
theme_text_color: "Primary"
MDTextField:
hint_text: "Enter username"
helper_text: "to join the chat (test mode)"
helper_text_mode: "on_focus"
icon_right: "android"
icon_right_color: app.theme_cls.primary_color
pos_hint:{'center_x': 0.5, 'center_y': 0.5}
size_hint_x:None
width:311
MDRoundFlatButton:
text: "Join Chat"
pos_hint: {"center_x": .5, "center_y": .4}
on_release: app.do_login()
MDLabel:
text: "This is testing mode only"
halign: "center"
pos_hint: {"center_x": .5, "center_y": .2}
theme_text_color:"Hint"
<HomeScreen>:
name: "home"
Screen:
BoxLayout:
orientation: "vertical"
MDToolbar:
title: "Demo Chat Application"
ScrollView:
MDList:
id: users_lst
On running this, the login screen working well but on pressing the button 'Join Chat' it raises the following error:
self.root.ids.users_lst.add_widget(list_item)
File "kivy\properties.pyx", line 864, in kivy.properties.ObservableDict.__getattr__
AttributeError: 'super' object has no attribute '__getattr__'
| 1 |
class HomeScreen(Screen):
pass
<HomeScreen>:
name: "home"
Screen:
BoxLayout:
orientation: "vertical"
MDToolbar:
title: "Demo Chat Application"
ScrollView:
MDList:
id: users_lst
You have a screen which has a screen, that's not what you want to do.
<HomeScreen>:
name: "home"
BoxLayout:
orientation: "vertical"
MDToolbar:
title: "Demo Chat Application"
ScrollView:
MDList:
id: users_lst
#######################################################
#######################################################
| 2 |
Parent doesn't have access of the id of inner children children's. (Not clear I know, So I'm gonna give you a lot of print to help you understand).
def do_login(self):
self.root.current = "home"
for i in range(20):
st_name = "student "
list_item = OneLineIconListItem(text=f"student {str(i)}")
list_item.add_widget(IconLeftWidget(icon="alpha-a-box"))
print("this is my App:", self)
print("this is my ScreenManager:", self.sm)
print("this is my global app visual widget (which is equal to ScreenManager here):", self.root)
print("this is the ScreenManager's dictionnary containing the widgets referenced with their id:", self.root.ids)
print("this is the current Screen:",self.root.current_screen)
print("this is current Screen dictionnary containing the widgets referenced with their id:", self.root.current_screen.ids)
print("this is the actual MDList", self.root.current_screen.ids["users_lst"])
self.root.current_screen.ids["users_lst"].add_widget(list_item)
I'm trying to make the button click on_release: app.proximo () have the action to go to the next card MDFloatLayout, but I'm not getting it, could someone help me how could it work?
Below the main.py file, where to start the app, main.kv file, where is the main app and finally the dashboard.kv file where I am calling my card inside the app
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
class DashBoard(Screen):
pass
class FirstScreen(Screen):
pass
class Lavanderia(MDApp):
def build(self):
self.title="Texto Titulo"
self.theme_cls.primary_palette = "LightBlue"
return Builder.load_file("main.kv")
def proximo(self):
self.root.ids.carousel.load_next(mode="proximo")# Próximo Card
def fecharApp(self):
self.stop()# Fecha Aplicativo
Lavanderia().run()
#:import rgba kivy.utils.get_color_from_hex
#: include dashboard.kv
#: include firstscreen.kv
NavigationLayout:
id: nav_layout
ScreenManager:
Screen:
BoxLayout:
orientation:'vertical'
MDToolbar:
title: app.title
elevation:10
left_action_items:[["menu", lambda x: nav_drawer.set_state()]]
ScreenManager:
id: screen_manager
DashBoard:
id:dashboard
name:"dashboard"
FirstScreen:
id:first_screen
name:"first_screen"
MDNavigationDrawer:
id: nav_drawer
BoxLayout:
orientation:'vertical'
padding:"8dp"
spacing:"8dp"
Image:
pos_hint:{"x":.24,"y":.0}
size_hint: None, None
size:dp(146), dp(158)
source:"images/logo.png"
ScrollView:
MDList:
OneLineIconListItem:
text:"Tela 1"
on_release:
screen_manager.current = "dashboard"
nav_drawer.set_state()
IconLeftWidget:
icon:"dishwasher"
OneLineIconListItem:
text:"Tela 2"
on_release:
screen_manager.current = "first_screen"
nav_drawer.set_state()
IconLeftWidget:
icon:"dishwasher"
<DashBoard>:
MDFloatLayout:
MDCard:
size_hint: dp(.45), dp(.8)
pos_hint:{"center_x": .5, "center_y": .5}
Carousel:
id:carousel
MDFloatLayout:
MDTextField:
hint_text:"Texto 1"
size_hint_x:dp(.8)
pos_hint:{"center_x": .5, "center_y": .48}
MDRaisedButton:
text: "Proximo"
size_hint_x:dp(.8)
pos_hint:{"center_x":.5,"center_y":.2}
on_release: app.proximo() # Proximo step
MDFloatLayout:
MDLabel:
text:"Texto Final Conclusão"
theme_text_color:"Custom"
bold:True
pos_hint:{"center_x":.68,"center_y":.5}
font_style:"H5"
MDRaisedButton:
text: "Fechar Aplicativo"
text_color:rgba("#00FF69")
size_hint_x:dp(.8)
pos_hint:{"center_x":.5,"center_y":.4}
md_bg_color:rgba("#333333")
on_release: app.fecharApp() #fechar Aplicativo
You are trying to ger the carrousel through the root screen, but it is inside the dashboard screen.
So you will have to navigate there first, and only then you can call your function.
def proximo(self):
dashboard = self.root.ids.dashboard
carousel = dashboard.ids.carousel
carousel.load_next(mode="proximo")
# Same as
# self.root.ids.dashboard.ids.carousel.load_next(mode="proximo")
This question already exists on stackoverflow but the solutions for them didnt worked for me.
Based on what i read online this error occurs, when there is an unidentified child widget in the kv file, but i have already identified all my widgets in the 'py' file
I have tried moving down the "Builder.load_file" (by down i mean after the class-es) and it worked properly, but then i couldnt bind widgets with functions, it showed some other error. So this was not a permanent solution.
important parts of my 'py' and 'kv' files
py:
kv = Builder.load_file("pcapp.kv")
class ActionBar(ActionBar):
pass
class Manager(ScreenManager):
pass
class Screen_one(Screen):
pass
class Screen_two(Screen):
pass
class GoodsView(ScrollView):
pass
class Screen_three(Screen):
pass
class CalculatorApp(App):
def build(self):
return kv
kv:
BoxLayout:
orientation: 'vertical'
canvas.before:
Color:
rgba: .65, .75, .85, 1
Rectangle:
pos: self.pos
size: self.size
ActionBar:
...
Manager:
id: sm
Screen_one:
id: screen_one
name: 'screen1'
manager: 'sm'
Screen_two:
id: screen_two
name: 'screen2'
manager: 'sm'
Screen_three:
id: screen_three
name: 'screen3'
manager: 'sm'
<Screen_one>:
FloatLayout:
Button:
text: "Click1"
size_hint: .2, .05
pos_hint: {'x': .2, 'y': .4}
on_release: app.root.ids.sm.current = 'screen2'
Label:
text: 'Hello!'
pos_hint: {'x': -0.2, 'y': 0}
<Screen_two>:
FloatLayout:
canvas.before:
Color:
rgba: 1, 0, 0, 1
Rectangle:
size: self.size
pos: self.pos
GoodsView:
<GoodsView>:
...
You are getting the error, kivy.factory.FactoryException: Unknown class <Manager> because in the kv file, when it is creating the root it tries to instantiate the child, Manager: object but it could not find the implementation of class Manager() before the Builder.load_file() function.
Solution
Remove kv = Builder.load_file("pcapp.kv")
Replace return kv with return Builder.load_file("pcapp.kv")
I want to click MDMenuItem to get text or do something.
But an error say "AttributeError: 'MDMenuItem' object has no attribute 'text' "
.py file like this
class MDMenuItem(Widget):
pass
class MyScreen(Screen):
menu_items = [
{'viewclass': 'MDMenuItem',
'text': 'text1'},
{'viewclass': 'MDMenuItem',
'text': 'text2'},
]
def change_variable(self, value):
print("\nvalue=", value)
self.VARIABLE = value
print("\tself.VARIABLE=", self.VARIABLE)
.kv file like this:
#:import MDDropdownMenu kivymd.menu.MDDropdownMenu
#:import MDRaisedButton kivymd.button.MDRaisedButton
<MDMenuItem>:
on_release: root.change_variable(self.text)
<MyScreen>:
name: myscrn
MDRaisedButton:
size_hint: None, None
size: 3 * dp(48), dp(48)
text: 'MDButton'
opposite_colors: True
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
on_release: MDDropdownMenu(items=root.menu_items, width_mult=4).open(self)
What should I do?
Edit:
Thank you for your reply. In my case, this .py subprogram not content 'App'. I don't want to put the method into main.py because I want main.py to stay clean.(Just content import, builder.load_file, add_wiget...)
So I want to call method without use 'app.something'.
Can I use root.something or other methods to call change_variable and get text?
I removed class MDMenuItem and change "root.change_variable" to "app.root.get_screen('MyScreen').change_variable". It's work!!!
The "app.root" treated as "screen.manager" in this case. I don't know why but it just work.
.py
class MyScreen(Screen):
menu_items = [
{'viewclass': 'MDMenuItem',
'text': 'text1'},
{'viewclass': 'MDMenuItem',
'text': 'text2'},
]
def change_variable(self, value):
print("\nvalue=", value)
self.VARIABLE = value
print("\tself.VARIABLE=", self.VARIABLE)
.kv
#:import MDDropdownMenu kivymd.menu.MDDropdownMenu
#:import MDRaisedButton kivymd.button.MDRaisedButton
<MDMenuItem>:
on_release: app.root.get_screen("MyScreen").change_variable(self.text)
Note:
The following solution is using KivyMD version 0.1.2.
AttributeError
AttributeError: 'MDMenuItem' object has no attribute 'text'
The error was due wrong definition for class MDMenuItem. It was defined with an inheritance of a Widget which does not has the attribute, 'text'.
Actual Definition of MDMenuItem
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.button import ButtonBehavior
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty
class MDMenuItem(RecycleDataViewBehavior, ButtonBehavior, BoxLayout):
text = StringProperty()
Solution
There is no need to define class MDMenuItem in main.py. Remove it and the program will run.
Example
main.py
from kivy.app import App
from kivymd.theming import ThemeManager
from kivy.uix.screenmanager import Screen
class MyScreen(Screen):
VARIABLE = ""
menu_items = [
{'viewclass': 'MDMenuItem',
'text': 'text1'},
{'viewclass': 'MDMenuItem',
'text': 'text2'},
]
def change_variable(self, value):
print("\nvalue=", value)
self.VARIABLE = value
print("\tself.VARIABLE=", self.VARIABLE)
class MainApp(App):
title = "KivyMD MDDropdownMenu Demo"
theme_cls = ThemeManager()
def build(self):
return MyScreen()
if __name__ == "__main__":
MainApp().run()
main.kv
#:kivy 1.11.0
#:import MDDropdownMenu kivymd.menu.MDDropdownMenu
#:import MDRaisedButton kivymd.button.MDRaisedButton
<MDMenuItem>:
on_release: app.root.change_variable(self.text)
<MyScreen>:
name: 'myscrn'
MDRaisedButton:
size_hint: None, None
size: 3 * dp(48), dp(48)
text: 'MDButton'
opposite_colors: True
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
on_release: MDDropdownMenu(items=root.menu_items, width_mult=4).open(self)
Output