I am using python and kivy to make a simple app, but when I create multiple screen for my app, I cannot access the class attributes of some class.
I have problem accessing a method using screen manager.
main.py
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.widget import Widget
class MyGame(Widget):
def __init__(self, **kwargs):
super(MyGame, self).__init__(**kwargs)
def print_a_word(self):
print('a word')
class OptionWindow(Screen):
pass
class SecondWindow(Screen):
pass
class WindowManager(ScreenManager):
pass
kv = Builder.load_file('screen_manager.kv')
class MyMainApp(App):
def build(self):
return kv
if __name__ == "__main__":
MyMainApp().run()
kivy file (screen_manager.kv)
#:kivy 2.0.0
# File name: screen_manager.kv
#: import MyGame Widget
WindowManager:
OptionWindow:
SecondWindow:
<OptionWindow>:
name: "main"
GridLayout:
cols:1
canvas.before:
Color:
rgba: 1, 1, 1, 1
Rectangle:
pos: 0, 0
size: root.width, root.height
GridLayout:
rows: 5
padding: 50, 50
spacing: 20, 20
OptionBtn:
text: 'Americas'
on_release:
app.root.current = "second"
root.manager.transition.direction = "left"
<SecondWindow>:
name: "second"
MyGame
Button:
on_press: root.MyGame.print_a_word()
<OptionBtn@Button>
background_normal: 'Images/Other/white.png'
color: 0, 0, 0, 1
font_size: 20
canvas.after:
Color:
rgba: 0, 0, 0, 1
Line:
rectangle: self.x, self.y, self.size[0], self.size[1]
Everything works well until I press on the button of the second window. I cannot access the method from MyGame(Widget). I get'SecondWindow' object has no attribute 'MyGame'
This is part of a bigger issue because I made this file to solve my original issue which is... I have a big program in which I have two files main.py and my.kv and I want to add screens. In this main.py, everything is defined a class that inherits from Widget and the build method returns an instance of that class. This is why I made the files from above... it is to understand how I can access from the Widget class. Thank you
Here I fixed your example code now the print_my_word() method inside MyGame() object can be accessed and executed this should be enough to get you in the way.
Only the kv file needed change:
Used include instead of import in "MyGame" object:
#: include MyGame
Instantiate it inside <SecondWindow> object.
Added an id to it, to be able to access it.
WindowManager:
OptionWindow:
SecondWindow:
<OptionWindow>:
name: "main"
GridLayout:
cols:1
canvas.before:
Color:
rgba: 1, 1, 1, 1
Rectangle:
pos: 0, 0
size: root.width, root.height
GridLayout:
rows: 5
padding: 50, 50
spacing: 20, 20
OptionBtn:
text: 'Americas'
on_release:
app.root.current = "second"
root.manager.transition.direction = "left"
<SecondWindow>:
name: "second"
MyGame:
id: my_game
Button:
on_press: my_game.print_a_word()
<OptionBtn@Button>
background_normal: 'Images/Other/white.png'
color: 0, 0, 0, 1
font_size: 20
canvas.after:
Color:
rgba: 0, 0, 0, 1
Line:
rectangle: self.x, self.y, self.size[0], self.size[1]
Ok this next part below is an update to respond your question in the second comment.
main.py
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.widget import Widget
class MyGame(Widget):
def __init__(self, **kwargs):
super(MyGame, self).__init__(**kwargs)
def print_a_word(self):
print('My Game: print method')
class OptionWindow(Screen):
pass
class SecondWindow(Screen):
pass
class WindowManager(ScreenManager):
pass
kv = Builder.load_file('screen_manager.kv')
class MyMainApp(App):
def build(self):
self.my_game = MyGame() # <-- instantiated MyGame in the Main class to access it from any where
return kv
if __name__ == "__main__":
MyMainApp().run()
screen_manager.kv
WindowManager:
OptionWindow:
SecondWindow:
<OptionWindow>:
name: "main"
GridLayout:
cols:1
canvas.before:
Color:
rgba: 1, 1, 1, 1
Rectangle:
pos: 0, 0
size: root.width, root.height
GridLayout:
rows: 5
padding: 50, 50
spacing: 20, 20
OptionBtn:
text: 'Americas'
on_release:
app.root.current = "second"
root.manager.transition.direction = "left"
# ADDED EXTRA BUTTON TO SAMPLE ACCESSING MyGame OBJECT, FROM THIS CLASS
Button:
text: 'Access My Game Method'
on_release:
app.my_game.print_a_word() # <-- app can access main class attributes and methods
<SecondWindow>:
name: "second"
# USE A BOXLAYOUT TO LAYOUT THE BUTTONS
BoxLayout:
orientation: 'vertical'
spacing: 2
padding: 2
# ADDED BUTTON TO SAMPLE ACCESSING MyGame OBJECT
Button:
text: 'Access method from MyGame'
on_press: app.my_game.print_a_word() # <-- app can access main class attributes and methods
Button:
text: 'Return to Main'
on_press: app.root.current = "main"
<OptionBtn@Button>
background_normal: 'Images/Other/white.png'
color: 0, 0, 0, 1
font_size: 20
canvas.after:
Color:
rgba: 0, 0, 0, 1
Line:
rectangle: self.x, self.y, self.size[0], self.size[1]