I am new to Python and Kivy and have encountered a problem. My aim is to have buttons with bilingual texts that changes when proper buttons are pressed: button_polish and button_english. I wanted the 'logic' of the project in the .py file and the 'visual' in .kv file. In order to do so I have created a python file and a kivy file. But when I try to run it an error occurs: 'MainScreen' has no attribute 'metropolitalne_text'.
I believe that there's something wrong with the instantiation of the objects but I have no idea how to fix this. I would love to be able to refer to .kv objects in .py file using their ids.
I have tried instantiating objects in .py file but this didn't help. What I found out is that using StringProperty should help.
Here are my files:
Biletomat.py:
import kivy
kivy.require('1.11.1')
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.config import Config
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import StringProperty
from kivy.uix.behaviors import ButtonBehavior
from datetime import datetime
from datetime import timedelta
from kivy.clock import Clock
Config.set('graphics', 'resizable', '0')
Config.set('graphics', 'width', '1200')
Config.set('graphics', 'height', '700')
Config.set('graphics', 'fullscreen', '0')
Builder.load_file('1mainscreen.kv')
language = "polish"
# 1 the first and main screen - 1st click
class MainScreen (Screen):
def __init__(self,**kwargs):
super().__init__()
self.button_polish = Button(on_press=self.change_language_to_polish)
self.button_english = Button(on_press=self.change_language_to_english)
def change_language_to_polish(self):
main_title_text = StringProperty('BILETY JEDNOPRZEJAZDOWE I JEDNORAZOWE')
jednoprzejazdowy_text=StringProperty('Jednoprzejazdowy na linie zwyk\u0142e')
jednogodzinny_text=StringProperty('1-godzinny na linie zwyk\u0142e')
jednoprzejazdowylubjednoprzejazdowy_text=StringProperty('1-godzinny lub jednoprzejazdowy na linie nocne,\n pospieszne i zwyk\u0142e')
dwudziestoczterogodzinny_text="24-godzinny na linie nocne, pospieszne i zwyk\u0142e"
subtitle_text=StringProperty('BILETY OKRESOWE I METROPOLITALNE')
okresowe_text=StringProperty('Bilety okresowe')
metropolitalne_text=StringProperty('Bilety metropolitalne')
def change_language_to_english(self):
main_title_text = StringProperty('SINGLE TRIP AND TIME TICKETS')
jednoprzejazdowy_text=StringProperty('Single trip valid on standard lines')
jednogodzinny_text=StringProperty('1-hour ticket valid on standard lines')
jednoprzejazdowylubjednoprzejazdowy_text=StringProperty('1-hour ticket or single trip valid on night,\nrapid and standard lines')
dwudziestoczterogodzinny_text="24-hour ticket valid on night,\nrapid and standard lines"
subtitle_text=StringProperty('TIME AND METROPOLITAN TICKETS')
okresowe_text=StringProperty('Season tickets')
metropolitalne_text=StringProperty('Metropolitan tickets')
# Create the screen manager
sm = ScreenManager()
sm.add_widget(MainScreen(name='menu'))
class MyApp(App):
def build(self):
return sm
MyApp().run()
1mainscreen.kv:
<MainScreen>:
GridLayout:
cols: 1
rows: 5
canvas.before:
Rectangle:
pos: self.pos
size: self.size
source: 'port.jpg'
Color:
rgba: 0, 0, 0, 0.5
AnchorLayout:
anchor_x: 'center'
anchor_y: 'center'
Label:
id: main_title
text: root.main_title_text
color: 0, 0, 0, 1
font_size: '32dp'
bcolor: 1, 1, 1, 0.5
canvas.before:
Color:
rgba: self.bcolor
Rectangle:
pos: self.pos
size: self.size
AnchorLayout:
anchor_x: 'right'
anchor_y: 'top'
padding: [00, 40, 40, 0]
Button:
id:"button_polish"
size: 50, 50
size_hint: None, None # <---
background_normal: ''
background_color: 0, 0.7, 1, 0
on_press:
root.change_language_to_polish()
print("Polish".format(self.text))
Image:
source: 'poland_flag.png'
y: self.parent.y
x: self.parent.x
size: 75, 75
allow_stretch: True
AnchorLayout:
anchor_x: 'right'
anchor_y: 'top'
padding: [00, 40, 130, 0]
Button:
id:"button_english"
size: 50, 50
size_hint: None, None # <---
background_normal: ''
background_color: 0, 0.7, 1, 0
on_press:
root.change_language_to_english()
print("English".format(self.text))
Image:
source: 'uk_flag.png'
y: self.parent.y
x: self.parent.x
size: 75, 75
allow_stretch: True
GridLayout:
cols: 2
rows: 1
RelativeLayout:
SmoothButton:
id: jednoprzejazdowy
size: 550, 120
font_size: '24dp'
size_hint: None, None # <---
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
text: root.jednoprzejazdowy_text
on_press: root.manager.current = 'jednorazowe_screen1'
back_color: 0, 0.7, 1, 1
RelativeLayout:
SmoothButton:
id: jednogodzinny
size: 550, 120
font_size: '24dp'
size_hint: None, None # <---
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
text: root.jednogodzinny_text
on_press: root.manager.current = 'jednorazowe_screen2'
back_color: 0, 0.7, 1, 1
GridLayout:
cols: 2
rows: 1
RelativeLayout:
SmoothButton:
id: jednoprzejazdowylubjednoprzejazdowy
size: 550, 120
font_size: '24dp'
halign: 'center'
size_hint: None, None # <---
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
text: root.jednoprzejazdowylubjednoprzejazdowy_text
on_press: root.manager.current = 'jednorazowe_screen3'
back_color: 0, 0.7, 1, 1
RelativeLayout:
SmoothButton:
id: dwudziestoczterogodzinny
size: 550, 120
font_size: '24dp'
halign: 'center'
size_hint: None, None # <---
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
text: root.dwudziestoczterogodzinny_text
on_press: root.manager.current = 'jednorazowe_screen4'
back_color: 0, 0.7, 1, 1
Label:
id: subtitle
text: root.subtitle_text
color: 0, 0, 0, 1
font_size: '32dp'
bcolor: 1, 1, 1, 0.5
canvas.before:
Color:
rgba: self.bcolor
Rectangle:
pos: self.pos
size: self.size
GridLayout:
cols: 2
rows: 1
RelativeLayout:
SmoothButton:
id: okresowe
size: 550, 120
font_size: '24dp'
size_hint: None, None # <---
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
text: root.okresowe_text
on_press: root.manager.current = 'okresowe_screen'
back_color: 0, 0.7, 1, 1
RelativeLayout:
SmoothButton:
id: metropolitalne
size: 550, 120
font_size: '24dp'
size_hint: None, None # <---
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
text: root.metropolitalne_text
on_press: root.manager.current = 'metropolitalne_screen'
back_color: 0, 0.7, 1, 1
<SmoothButton@Button>:
background_color: (0,0,0,0)
background_normal: ''
back_color: (0, 0.7, 1, 1)
border_radius: [18]
canvas.before:
Color:
rgba: self.back_color
RoundedRectangle:
size: self.size
pos: self.pos
radius: self.border_radius
The error I get:
[INFO ] [Logger ] Record log in C:\Users\Andrea\.kivy\logs\kivy_19-12-29_30.txt
[INFO ] [Kivy ] v1.11.1
[INFO ] [Kivy ] Installed at "D:\ANACONDA\anaconda\lib\site-packages\kivy\__init__.py"
[INFO ] [Python ] v3.7.4 (default, Aug 9 2019, 18:34:13) [MSC v.1915 64 bit (AMD64)]
[INFO ] [Python ] Interpreter at "D:\ANACONDA\anaconda\pythonw.exe"
[INFO ] [Factory ] 184 symbols loaded
[INFO ] [Image ] Providers: img_tex, img_dds, img_sdl2, img_pil, img_gif (img_ffpyplayer ignored)
[INFO ] [Text ] Provider: sdl2
[INFO ] [Window ] Provider: sdl2
[INFO ] [GL ] Using the "OpenGL" graphics system
[INFO ] [GL ] GLEW initialization succeeded
[INFO ] [GL ] Backend used <glew>
[INFO ] [GL ] OpenGL version <b'4.5.0 - Build 24.20.100.6286'>
[INFO ] [GL ] OpenGL vendor <b'Intel'>
[INFO ] [GL ] OpenGL renderer <b'Intel(R) UHD Graphics 620'>
[INFO ] [GL ] OpenGL parsed version: 4, 5
[INFO ] [GL ] Shading version <b'4.50 - Build 24.20.100.6286'>
[INFO ] [GL ] Texture max size <16384>
[INFO ] [GL ] Texture max units <32>
[INFO ] [Window ] auto add sdl2 input provider
[INFO ] [Window ] virtual keyboard not allowed, single mode, not docked
[INFO ] [GL ] NPOT texture support is available
[INFO ] [GL ] Unpack subimage support is available
Traceback (most recent call last):
File "<ipython-input-1-6b1cf59579f0>", line 1, in <module>
runfile('D:/studia - semestr 9/Wizualizacja i multimedia w technice/laborki/biletomat/biletomat.py', args='1 2 3', wdir='D:/studia - semestr 9/Wizualizacja i multimedia w technice/laborki/biletomat')
File "D:\ANACONDA\anaconda\lib\site-packages\spyder_kernels\customize\spydercustomize.py", line 827, in runfile
execfile(filename, namespace)
File "D:\ANACONDA\anaconda\lib\site-packages\spyder_kernels\customize\spydercustomize.py", line 110, in execfile
exec(compile(f.read(), filename, 'exec'), namespace)
File "D:/studia - semestr 9/Wizualizacja i multimedia w technice/laborki/biletomat/biletomat.py", line 238, in <module>
sm.add_widget(MainScreen(name='menu'))
File "D:/studia - semestr 9/Wizualizacja i multimedia w technice/laborki/biletomat/biletomat.py", line 69, in __init__
super().__init__()
File "D:\ANACONDA\anaconda\lib\site-packages\kivy\uix\relativelayout.py", line 265, in __init__
super(RelativeLayout, self).__init__(**kw)
File "D:\ANACONDA\anaconda\lib\site-packages\kivy\uix\floatlayout.py", line 65, in __init__
super(FloatLayout, self).__init__(**kwargs)
File "D:\ANACONDA\anaconda\lib\site-packages\kivy\uix\layout.py", line 76, in __init__
super(Layout, self).__init__(**kwargs)
File "D:\ANACONDA\anaconda\lib\site-packages\kivy\uix\widget.py", line 361, in __init__
rule_children=rule_children)
File "D:\ANACONDA\anaconda\lib\site-packages\kivy\uix\widget.py", line 469, in apply_class_lang_rules
rule_children=rule_children)
File "D:\ANACONDA\anaconda\lib\site-packages\kivy\lang\builder.py", line 538, in apply
rule_children=rule_children)
File "D:\ANACONDA\anaconda\lib\site-packages\kivy\lang\builder.py", line 707, in _apply_rule
e), cause=tb)
BuilderException: Parser: File "D:\studia - semestr 9\Wizualizacja i multimedia w technice\laborki\biletomat\1mainscreen.kv", line 159:
...
157: size_hint: None, None # <---
158: pos_hint: {'center_x': 0.5, 'center_y': 0.5}
>> 159: text: root.metropolitalne_text
160: on_press: root.manager.current = 'metropolitalne_screen'
161: back_color: 0, 0.7, 1, 1
...
BuilderException: Parser: File "D:\studia - semestr 9\Wizualizacja i multimedia w technice\laborki\biletomat\1mainscreen.kv", line 159:
...
157: size_hint: None, None # <---
158: pos_hint: {'center_x': 0.5, 'center_y': 0.5}
>> 159: text: root.metropolitalne_text
160: on_press: root.manager.current = 'metropolitalne_screen'
161: back_color: 0, 0.7, 1, 1
...
AttributeError: 'MainScreen' object has no attribute 'metropolitalne_text'
File "D:\ANACONDA\anaconda\lib\site-packages\kivy\lang\builder.py", line 249, in create_handler
return eval(value, idmap), bound_list
File "D:\studia - semestr 9\Wizualizacja i multimedia w technice\laborki\biletomat\1mainscreen.kv", line 159, in <module>
text: root.metropolitalne_text
File "kivy\weakproxy.pyx", line 32, in kivy.weakproxy.WeakProxy.__getattr__
File "D:\ANACONDA\anaconda\lib\site-packages\kivy\lang\builder.py", line 692, in _apply_rule
rctx['ids'])
File "D:\ANACONDA\anaconda\lib\site-packages\kivy\lang\builder.py", line 254, in create_handler
cause=tb)
When you create a variable in a method, it is a local variable by default, and is not accessible outside that method. Your lines:
metropolitalne_text=StringProperty('Bilety metropolitalne')
and
metropolitalne_text=StringProperty('Metropolitan tickets')
create local variables named metropolitalne_text
. I suspect you really want metropolitalne_text
to be a property of MainScreen
. You can do this by adding a line to your definition of the MainScreen
class:
class MainScreen (Screen):
metropolitalne_text = StringProperty()
def __init__(self,**kwargs):
super().__init__()
self.button_polish = Button(on_press=self.change_language_to_polish)
self.button_english = Button(on_press=self.change_language_to_english)
Then, everywhare that you reference metropolitalne_text
in the MainScreen
class, change it to self.metropolitalne_text
.