使用变量从 python 文件到 kv 文件的 kivy 错误
kivy error from using a variable from python file to kv file
我正在制作漫画 reader 它使用了 kivy 中的图像模块,我发现了一个错误,可以通过使用从 py 文件到 kv 文件的变量来解决。我在 App class 中有一个名为 sourceToImage
的变量,但是当我在 kv 文件中调用 sourceToImage
变量时 source: app.sourceToImage
给我一个很长的错误
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
但是当我使用 app.sourceToImage
时,它给我一个错误提示:
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,
完整的 kv 文件:
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()
完整的py文件:
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()
您的代码有几个问题:
您的 kv
代码引用了 app
,但是 kv
在创建 App
之前加载。这就是为什么您会收到有关 NoneType
的消息(app
是 None
的原因)。您可以通过将 kv = Builder.load_file("my.kv")
移动到 App
的 build()
方法中来解决这个问题。但是请看下面的注释。
您正在构建 App
小部件树两次。一次使用 kv = Builder.load_file("my.kv")
行,再次使用代码:
sm = WindowManager()
screens = [SelectingApp(name="selecting"), ReaderApp(name="reader")]
for screen in screens:
sm.add_widget(screen)
以上代码和Builder.load_file()
代码都可以去掉。见下文。
- 因为你将
kv
文件命名为my.kv
,它会被kivy自动加载,所以你不需要以上任何一种技术来构建App
小部件树。
所以你的 App
class 可以简单地是:
class MyApp(App):
sourceToImage = StringProperty(f"Manga/{Manga}/{page}.jpg")
根本没有 build()
方法。然后,在您引用 sm.current
的方法中,您可以使用 self.manager.current
.
我正在制作漫画 reader 它使用了 kivy 中的图像模块,我发现了一个错误,可以通过使用从 py 文件到 kv 文件的变量来解决。我在 App class 中有一个名为 sourceToImage
的变量,但是当我在 kv 文件中调用 sourceToImage
变量时 source: app.sourceToImage
给我一个很长的错误
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
但是当我使用 app.sourceToImage
时,它给我一个错误提示:
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,
完整的 kv 文件:
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()
完整的py文件:
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()
您的代码有几个问题:
您的
kv
代码引用了app
,但是kv
在创建App
之前加载。这就是为什么您会收到有关NoneType
的消息(app
是None
的原因)。您可以通过将kv = Builder.load_file("my.kv")
移动到App
的build()
方法中来解决这个问题。但是请看下面的注释。您正在构建
App
小部件树两次。一次使用kv = Builder.load_file("my.kv")
行,再次使用代码:sm = WindowManager() screens = [SelectingApp(name="selecting"), ReaderApp(name="reader")] for screen in screens: sm.add_widget(screen)
以上代码和Builder.load_file()
代码都可以去掉。见下文。
- 因为你将
kv
文件命名为my.kv
,它会被kivy自动加载,所以你不需要以上任何一种技术来构建App
小部件树。
所以你的 App
class 可以简单地是:
class MyApp(App):
sourceToImage = StringProperty(f"Manga/{Manga}/{page}.jpg")
根本没有 build()
方法。然后,在您引用 sm.current
的方法中,您可以使用 self.manager.current
.