I'm making a Manga reader it uses the Images module in kivy and I found a bug that can be solved by using a variable from a py file to a kv file. I have a Variable in the App class called sourceToImage
but when i call the sourceToImage
variable in a kv file source: app.sourceToImage
gives me a long error
py
class MyApp(App):
sourceToImage = "Source"
def build(self):
return sm
kv
<ReaderApp>:
name: "reader"
im: page
canvas:
Color:
rgba: 1,1,1,0.17
Rectangle:
size: (root.width, root.height)
pos: (0,0)
Image:
size: 500, 600
pos: 0, 0
id: page
source: app.sourceToImage
but when i use app.sourceToImage
it gives me an Error saying:
Traceback (most recent call last):
File "C:\Users\USER\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\lang\builder.py", line 242, in create_handler
return eval(value, idmap), bound_list
File "D:\GameDev-Programming\Python\kivyProjects\firstKivy\my.kv", line 20, in <module>
source: app.sourceToImage
File "C:\Users\USER\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\lang\parser.py", line 75, in __getattribute__
object.__getattribute__(self, '_ensure_app')()
File "C:\Users\USER\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\lang\parser.py", line 70, in _ensure_app
app.bind(on_stop=lambda instance:
AttributeError: 'NoneType' object has no attribute 'bind'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\USER\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\lang\builder.py", line 695, in _apply_rule
value, bound = create_handler(
File "C:\Users\USER\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\lang\builder.py", line 245, in create_handler
raise BuilderException(rule.ctx, rule.line,
kivy.lang.builder.BuilderException: Parser: File "D:\GameDev-Programming\Python\kivyProjects\firstKivy\my.kv", line 20:
...
18: pos: 0, 0
19: id: page
>> 20: source: app.sourceToImage
21:
22:
...
AttributeError: 'NoneType' object has no attribute 'bind'
File "C:\Users\USER\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\lang\builder.py", line 242, in create_handler
return eval(value, idmap), bound_list
File "D:\GameDev-Programming\Python\kivyProjects\firstKivy\my.kv", line 20, in <module>
source: app.sourceToImage
File "C:\Users\USER\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\lang\parser.py", line 75, in __getattribute__
object.__getattribute__(self, '_ensure_app')()
File "C:\Users\USER\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\lang\parser.py", line 70, in _ensure_app
app.bind(on_stop=lambda instance:
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "D:\GameDev-Programming\Python\kivyProjects\firstKivy\main.py", line 87, in <module>
kv = Builder.load_file("my.kv")
File "C:\Users\USER\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\lang\builder.py", line 306, in load_file
return self.load_string(data, **kwargs)
File "C:\Users\USER\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\lang\builder.py", line 408, in load_string
self._apply_rule(
File "C:\Users\USER\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\lang\builder.py", line 661, in _apply_rule
child.apply_class_lang_rules(
File "C:\Users\USER\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\uix\widget.py", line 463, in apply_class_lang_rules
Builder.apply(
File "C:\Users\USER\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\lang\builder.py", line 541, in apply
self._apply_rule(
File "C:\Users\USER\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\lang\builder.py", line 710, in _apply_rule
raise BuilderException(rule.ctx, rule.line,
kivy.lang.builder.BuilderException: Parser: File "D:\GameDev-Programming\Python\kivyProjects\firstKivy\my.kv", line 20:
...
18: pos: 0, 0
19: id: page
>> 20: source: app.sourceToImage
21:
22:
...
BuilderException: Parser: File "D:\GameDev-Programming\Python\kivyProjects\firstKivy\my.kv", line 20:
...
18: pos: 0, 0
19: id: page
>> 20: source: app.sourceToImage
21:
22:
...
AttributeError: 'NoneType' object has no attribute 'bind'
File "C:\Users\USER\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\lang\builder.py", line 242, in create_handler
return eval(value, idmap), bound_list
File "D:\GameDev-Programming\Python\kivyProjects\firstKivy\my.kv", line 20, in <module>
source: app.sourceToImage
File "C:\Users\USER\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\lang\parser.py", line 75, in __getattribute__
object.__getattribute__(self, '_ensure_app')()
File "C:\Users\USER\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\lang\parser.py", line 70, in _ensure_app
app.bind(on_stop=lambda instance:
File "C:\Users\USER\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\lang\builder.py", line 695, in _apply_rule
value, bound = create_handler(
File "C:\Users\USER\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\lang\builder.py", line 245, in create_handler
raise BuilderException(rule.ctx, rule.line,
full kv file:
WindowManager:
SelectingApp:
ReaderApp:
<ReaderApp>:
name: "reader"
im: page
canvas:
Color:
rgba: 1,1,1,0.17
Rectangle:
size: (root.width, root.height)
pos: (0,0)
Image:
size: 500, 600
pos: 0, 0
id: page
source: ""
<SelectingApp>
name: "selecting"
listSpin: spinnerId
canvas:
Color:
rgba: 1,1,1,0.17
Rectangle:
size: (root.width, root.height)
pos: (0,0)
FloatLayout:
Label:
text: app.sourceToImage
size_hint: 0.1,0.1
pos_hint: {"x": 0.4, "y": 0.5}
Button:
text: "Go to reader"
on_press: root.Change()
size_hint: 0.5, 0.05
pos_hint: {"x": 0.2}
Spinner:
id: spinnerId
text: "Choose Manga"
values: ["hey", "ey"]
size_hint: 0.3, 0.1
pos_hint: {"x":0.3, "y":0.4}
Button:
text: "refresh list"
size_hint: 0.5, 0.05
pos_hint: {"x": 0.2, "y": 0.2}
on_press: root.Refresh()
full py file:
import os
from kivy.app import App
from kivy.properties import ObjectProperty
from kivy.config import Config
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.properties import StringProperty
width = 360
height = 640 # How does this make the resolution 641
Config.set('graphics', 'width', width)
Config.set('graphics', 'height', height)
Manga = "Seirei Gensouki - Konna Sekai De Deaeta Kimi Ni"
page = 0
arr = os.listdir(f"Manga/{Manga}")
MangaList = os.listdir("Manga")
fileCount = len(arr)
class WindowManager(ScreenManager):
pass
class ReaderApp(Screen):
im = ObjectProperty(None)
def NextPage(self):
global page
if fileCount > page:
page += 1
if arr[0] == "1.jpg":
self.im.source = f"Manga/{Manga}/{page}.jpg"
else:
self.im.source = f"Manga/{Manga}/{page}.png"
print("next page")
def PreviousPage(self):
global page
if page > 1:
page -= 1
if arr[0] == "1.jpg":
self.im.source = f"Manga/{Manga}/{page}.jpg"
else:
self.im.source = f"Manga/{Manga}/{page}.png"
print("previous page")
def on_touch_down(self, touch):
global page
xPos, yPos, = touch.pos
xPos = int(xPos)
yPos = int(yPos)
print(f"X: {xPos}\nY: {yPos}")
if xPos > 300 and yPos > 600:
sm.current = "selecting"
f = open("Records", "r+")
f.writelines(f"{Manga};{page}")
f.close()
elif self.width * .30 > xPos:
self.PreviousPage()
elif xPos > self.width * .70:
self.NextPage()
class SelectingApp(Screen):
listSpin = ObjectProperty(None)
def Refresh(self):
self.listSpin.values = MangaList
def Change(self):
global page
f = open("Records", "r")
records = f.read().split("\n")
print(records)
for lines in records:
print(lines)
mangaTitle, mangaPage = lines.split(";")
print(mangaTitle, mangaPage)
if mangaTitle == Manga:
page = int(mangaPage)
sm.current = "reader"
kv = Builder.load_file("my.kv")
sm = WindowManager()
screens = [SelectingApp(name="selecting"), ReaderApp(name="reader")]
for screen in screens:
sm.add_widget(screen)
class MyApp(App):
sourceToImage = StringProperty(f"Manga/{Manga}/{page}.jpg")
def build(self):
return sm
if __name__ == "__main__":
MyApp().run()
Several problems with your code:
Your kv
code references app
, but the kv
is loaded before the App
is created. That is why you get the message about NoneType
(app
is None
at that point). You can fix that by just moving the kv = Builder.load_file("my.kv")
inside the build()
method of the App
. But see the following notes.
You are building the App
widget tree twice. Once with the line kv = Builder.load_file("my.kv")
, and again with the code:
sm = WindowManager()
screens = [SelectingApp(name="selecting"), ReaderApp(name="reader")]
for screen in screens:
sm.add_widget(screen)
You can eliminate both the above code and the Builder.load_file()
code. See below.
kv
file as my.kv
, it will be loaded automatically by kivy, so you don't need either of the above techniques for building the App
widget tree.So your App
class can be simply:
class MyApp(App):
sourceToImage = StringProperty(f"Manga/{Manga}/{page}.jpg")
with no build()
method at all. Then, in the methods where you reference sm.current
, you can use self.manager.current
.