如何在 kivy 中使用在另一个 .py 模块(不是 main.py)中定义的变量?
How to use variables in kivy, that are defined in another .py module (not main.py)?
我想在与 main.py 文件分开的 .py 模块中定义应用程序的所有变量。然后我想在 kivy 文件中使用这些变量。
我已经尝试了以下代码的几个变体,但总是有错误。该模块可以很好地定义例如不同的字体,但是当涉及到属性(ObjectProperty)时,它不起作用。
项目结构:
Kivy文件夹
模块(文件夹)
- variables.py
屏幕(文件夹)
screen1.kv
screen2.kv
main.py
- main.kv
代码:
main.py
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from os import listdir
from kivy.lang import Builder
kv_screens = './screens/'
for kv in listdir(kv_screens):
Builder.load_file(kv_screens+kv)
class Screen1(Screen):
pass
class Screen2(Screen):
pass
class ScreenManagement(ScreenManager):
pass
presentation = Builder.load_file('main.kv')
class MainApp(App):
import modules.variables
def build(self):
return presentation
if __name__ == '__main__':
MainApp().run()
main.kv
#:kivy 1.10.1
ScreenManagement:
Screen1:
Screen2:
screen1.kv
#:kivy 1.10.1
<Screen1>:
name: 's1'
BoxLayout:
orientation: 'vertical'
Label:
text: 'Screen 1'
font_size: app.font_size_one
Button:
text: 'Go To Screen 2'
on_press:
root.manager.current = 's2'
screen2.kv
#:kivy 1.10.1
<Screen2>:
name: 's2'
BoxLayout:
orientation: 'vertical'
Label:
text: 'Screen 2'
font_size: '20dp'
Button:
text: 'Go To Screen 1'
on_press:
root.manager.current = 's1'
variables.py
from kivy.properties import ObjectProperty
font_size_one = ObjectProperty('40dp')
font_size_two = ObjectProperty('60dp')
现在这样做会产生这个错误:
AttributeError: 'NoneType' 对象没有属性 'bind'
我希望能够调用一个变量,因为它是在 MainApp(App) 中导入的,所以 'app.variable 名称应该读取它。
我也试过:
font_size: app.variables.font_size_one
和:
font_size: app.modules.variables.font_size_one
然后我尝试先导入模块,结果相同。
我也试过将它放入 class 并在 .kv 中调用 class 像这样:
variables.py
from kivy.properties import ObjectProperty
class FVArs():
font_size_one = ObjectProperty('40dp')
font_size_two = ObjectProperty('60dp')
screen1.kv
#:kivy 1.10.1
<Screen2>:
name: 's2'
BoxLayout:
orientation: 'vertical'
Label:
text: 'Screen 2'
font_size: FVars().font_size_two
Button:
text: 'Go To Screen 1'
on_press:
root.manager.current = 's1'
错误:
NameError: 名称 'FVars' 未定义
感谢您的回答。
再见
编辑:由于下面的答案适用于示例代码,但不适用于我的实际项目,因此我添加了相关的项目代码:
项目结构:
Kivy文件夹
模块(文件夹)
- global_variables.py
屏幕(文件夹)
Intro.kv
(和其他屏幕作为单独的 .kv 文件
main.py
- main.kv
main.py
from kivy.app import App
from modules.global_variables import globalVariables
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.uix.label import Label
from kivy.properties import StringProperty, NumericProperty, ObjectProperty, Property
from kivy.core.window import Window
background_color = (0.1, 0.1, 0.1, 1)
Window.clearcolor = background_color
from os import listdir
from kivy.lang import Builder
kv_screens = './screens/'
for kv in listdir(kv_screens):
Builder.load_file(kv_screens+kv)
kv_elements = './elements/'
for kv in listdir(kv_elements):
Builder.load_file(kv_elements+kv)
class IntroScreen(Screen):
user_name = StringProperty("Troll")
class ScreenManagement(ScreenManager):
pass
presentation = Builder.load_file("main.kv")
class MainApp(App):
title_size = globalVariables.title_size
def build(self):
self.title = 'Kivy Omnia!'
return presentation
if __name__ == "__main__":
app = MainApp()
app.run()
global_variables.py
from kivy.properties import ObjectProperty
class globalVariables():
title_size = ObjectProperty('101sp')
main.kv
#:kivy 1.10.1
ScreenManagement:
IntroScreen:
intro.kv
#:kivy 1.10.1
<IntroScreen>:
name: "intro"
BoxLayout:
orientation: 'vertical'
Label:
text: "Hello " + root.user_name + "!"
font_size: app.title_size
错误:
kivy.lang.builder.BuilderException: Parser: File
"C:\Users\Ghost\CodeProjects\phyton\kivyomnia\screens\Intro.kv", line
10: ...
8: Label:
9: text: "Hello " + root.user_name + "!"
10: font_size: app.title_size
11: font_name: "Exo-B"
12: AnchorLayout: ... BuilderException: Parser: File "C:\Users\Ghost\CodeProjects\phyton\kivyomnia\screens\Intro.kv", line
10: ...
8: Label:
9: text: "Hello " + root.user_name + "!"
10: font_size: app.title_size
11: font_name: "Exo-B"
12: AnchorLayout: ... AttributeError: 'NoneType' object has no attribute 'bind' File
"C:\Python37-32\lib\site-packages\kivy\lang\builder.py", line 249, in
create_handler
return eval(value, idmap), bound_list File "C:\Users\Ghost\CodeProjects\phyton\kivyomnia\screens\Intro.kv", line
10, in
font_size: app.title_size File "C:\Python37-32\lib\site-packages\kivy\lang\parser.py", line 75, in
getattribute
object.getattribute(self, '_ensure_app')() File "C:\Python37-32\lib\site-packages\kivy\lang\parser.py", line 70, in
_ensure_app
app.bind(on_stop=lambda instance:
文件"C:\Python37-32\lib\site-packages\kivy\lang\builder.py",行
615,在 _apply_rule
rctx['ids']) 文件 "C:\Python37-32\lib\site-packages\kivy\lang\builder.py",第 254 行,在
create_handler
原因=tb)
因此,如果只是重新定位:
title_size = globalVariables.title_size
... 在 IntroScreen(Screen) 内部,然后在 Intro.kv:
内部
font_size: root.title_size
...有效。但关键是让所有的全局变量在所有屏幕上都可用。
另一个问题:
if app.something 获取主应用程序中的内容 class
root.something 获取该文件的根目录 class 中的内容,那么您如何从另一个 class 中调用非应用程序或根目录的内容。如果说得通。
您可以使用此行导入您的 FVars
class:
from modules.variables import FVars
然后在 MainApp
class 中,您可以使用 FVars
的 class 变量的数据创建一个 class 变量。
class MainApp(App):
f1 = FVars.font_size_one
然后您可以在您的 kv 文件上访问它:
font_size: app.f1
这里是一些基本的例子:
main.py
from kivy.app import App
from kivy.lang import Builder
from modules.variables import FVars
class Test(App):
f1 = FVars.font_size_one
def build(self):
return Builder.load_file("test.kv")
Test().run()
test.kv
BoxLayout:
Label:
text: "Hello"
font_size: app.f1
modules/variables.py
from kivy.properties import ObjectProperty
class FVars():
font_size_one = ObjectProperty('40dp')
font_size_two = ObjectProperty('60dp')
更新
为防止错误,您可以在 build
方法中加载 kv 文件。
def build(self):
self.title = 'Kivy Omnia!'
kv_screens = './screens/'
for kv in listdir(kv_screens):
Builder.load_file(kv_screens+kv)
kv_elements = './elements/'
for kv in listdir(kv_elements):
Builder.load_file(kv_elements+kv)
presentation = Builder.load_file("main.kv")
return presentation
有很多方法可以访问既不是 app
也不是 root
的 class 中的变量,您可以只设置 id
属性那个小部件。
这是一个基本示例:
main.py
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
class SecondClass(BoxLayout):
someNumber = 123 # Let's say we wanted to print the value of this variable when we press the button.
class FirstClass(BoxLayout):
pass
class TestApp(App):
def build(self):
return FirstClass()
TestApp().run()
test.kv
<SecondClass>:
<FirstClass>:
Button:
text: "Print the Numbah"
on_press: print(app.root.ids.secondclass.someNumber) # We can do something like this
SecondClass:
id: secondclass
我们也可以这样做:
<SecondClass>:
<FirstClass>:
Button:
text: "Print the Numbah"
on_press: print(root.ids.secondclass.someNumber)
SecondClass:
id: secondclass
或者这样:
<SecondClass>:
<FirstClass>:
Button:
text: "Print the Numbah"
on_press: print(secondclass.someNumber)
SecondClass:
id: secondclass
甚至这样:
<SecondClass>:
<FirstClass>:
second: secondclass
Button:
text: "Print the Numbah"
on_press: print(app.root.second.someNumber)
SecondClass:
id: secondclass
还有这个:
<SecondClass>:
<FirstClass>:
second: secondclass
Button:
text: "Print the Numbah"
on_press: print(root.second.someNumber)
SecondClass:
id: secondclass
我想在与 main.py 文件分开的 .py 模块中定义应用程序的所有变量。然后我想在 kivy 文件中使用这些变量。
我已经尝试了以下代码的几个变体,但总是有错误。该模块可以很好地定义例如不同的字体,但是当涉及到属性(ObjectProperty)时,它不起作用。
项目结构:
Kivy文件夹
模块(文件夹)
- variables.py
屏幕(文件夹)
screen1.kv
screen2.kv
main.py
- main.kv
代码:
main.py
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from os import listdir
from kivy.lang import Builder
kv_screens = './screens/'
for kv in listdir(kv_screens):
Builder.load_file(kv_screens+kv)
class Screen1(Screen):
pass
class Screen2(Screen):
pass
class ScreenManagement(ScreenManager):
pass
presentation = Builder.load_file('main.kv')
class MainApp(App):
import modules.variables
def build(self):
return presentation
if __name__ == '__main__':
MainApp().run()
main.kv
#:kivy 1.10.1
ScreenManagement:
Screen1:
Screen2:
screen1.kv
#:kivy 1.10.1
<Screen1>:
name: 's1'
BoxLayout:
orientation: 'vertical'
Label:
text: 'Screen 1'
font_size: app.font_size_one
Button:
text: 'Go To Screen 2'
on_press:
root.manager.current = 's2'
screen2.kv
#:kivy 1.10.1
<Screen2>:
name: 's2'
BoxLayout:
orientation: 'vertical'
Label:
text: 'Screen 2'
font_size: '20dp'
Button:
text: 'Go To Screen 1'
on_press:
root.manager.current = 's1'
variables.py
from kivy.properties import ObjectProperty
font_size_one = ObjectProperty('40dp')
font_size_two = ObjectProperty('60dp')
现在这样做会产生这个错误:
AttributeError: 'NoneType' 对象没有属性 'bind'
我希望能够调用一个变量,因为它是在 MainApp(App) 中导入的,所以 'app.variable 名称应该读取它。
我也试过:
font_size: app.variables.font_size_one
和:
font_size: app.modules.variables.font_size_one
然后我尝试先导入模块,结果相同。
我也试过将它放入 class 并在 .kv 中调用 class 像这样:
variables.py
from kivy.properties import ObjectProperty
class FVArs():
font_size_one = ObjectProperty('40dp')
font_size_two = ObjectProperty('60dp')
screen1.kv
#:kivy 1.10.1
<Screen2>:
name: 's2'
BoxLayout:
orientation: 'vertical'
Label:
text: 'Screen 2'
font_size: FVars().font_size_two
Button:
text: 'Go To Screen 1'
on_press:
root.manager.current = 's1'
错误:
NameError: 名称 'FVars' 未定义
感谢您的回答。
再见
编辑:由于下面的答案适用于示例代码,但不适用于我的实际项目,因此我添加了相关的项目代码:
项目结构:
Kivy文件夹
模块(文件夹)
- global_variables.py
屏幕(文件夹)
Intro.kv
(和其他屏幕作为单独的 .kv 文件
main.py
- main.kv
main.py
from kivy.app import App
from modules.global_variables import globalVariables
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.uix.label import Label
from kivy.properties import StringProperty, NumericProperty, ObjectProperty, Property
from kivy.core.window import Window
background_color = (0.1, 0.1, 0.1, 1)
Window.clearcolor = background_color
from os import listdir
from kivy.lang import Builder
kv_screens = './screens/'
for kv in listdir(kv_screens):
Builder.load_file(kv_screens+kv)
kv_elements = './elements/'
for kv in listdir(kv_elements):
Builder.load_file(kv_elements+kv)
class IntroScreen(Screen):
user_name = StringProperty("Troll")
class ScreenManagement(ScreenManager):
pass
presentation = Builder.load_file("main.kv")
class MainApp(App):
title_size = globalVariables.title_size
def build(self):
self.title = 'Kivy Omnia!'
return presentation
if __name__ == "__main__":
app = MainApp()
app.run()
global_variables.py
from kivy.properties import ObjectProperty
class globalVariables():
title_size = ObjectProperty('101sp')
main.kv
#:kivy 1.10.1
ScreenManagement:
IntroScreen:
intro.kv
#:kivy 1.10.1
<IntroScreen>:
name: "intro"
BoxLayout:
orientation: 'vertical'
Label:
text: "Hello " + root.user_name + "!"
font_size: app.title_size
错误:
kivy.lang.builder.BuilderException: Parser: File "C:\Users\Ghost\CodeProjects\phyton\kivyomnia\screens\Intro.kv", line 10: ... 8: Label: 9: text: "Hello " + root.user_name + "!"
10: font_size: app.title_size 11: font_name: "Exo-B" 12: AnchorLayout: ... BuilderException: Parser: File "C:\Users\Ghost\CodeProjects\phyton\kivyomnia\screens\Intro.kv", line 10: ... 8: Label: 9: text: "Hello " + root.user_name + "!" 10: font_size: app.title_size 11: font_name: "Exo-B" 12: AnchorLayout: ... AttributeError: 'NoneType' object has no attribute 'bind' File "C:\Python37-32\lib\site-packages\kivy\lang\builder.py", line 249, in create_handler return eval(value, idmap), bound_list File "C:\Users\Ghost\CodeProjects\phyton\kivyomnia\screens\Intro.kv", line 10, in font_size: app.title_size File "C:\Python37-32\lib\site-packages\kivy\lang\parser.py", line 75, in getattribute object.getattribute(self, '_ensure_app')() File "C:\Python37-32\lib\site-packages\kivy\lang\parser.py", line 70, in _ensure_app app.bind(on_stop=lambda instance:
文件"C:\Python37-32\lib\site-packages\kivy\lang\builder.py",行 615,在 _apply_rule rctx['ids']) 文件 "C:\Python37-32\lib\site-packages\kivy\lang\builder.py",第 254 行,在 create_handler 原因=tb)
因此,如果只是重新定位:
title_size = globalVariables.title_size
... 在 IntroScreen(Screen) 内部,然后在 Intro.kv:
内部font_size: root.title_size
...有效。但关键是让所有的全局变量在所有屏幕上都可用。
另一个问题:
if app.something 获取主应用程序中的内容 class root.something 获取该文件的根目录 class 中的内容,那么您如何从另一个 class 中调用非应用程序或根目录的内容。如果说得通。
您可以使用此行导入您的 FVars
class:
from modules.variables import FVars
然后在 MainApp
class 中,您可以使用 FVars
的 class 变量的数据创建一个 class 变量。
class MainApp(App):
f1 = FVars.font_size_one
然后您可以在您的 kv 文件上访问它:
font_size: app.f1
这里是一些基本的例子:
main.py
from kivy.app import App
from kivy.lang import Builder
from modules.variables import FVars
class Test(App):
f1 = FVars.font_size_one
def build(self):
return Builder.load_file("test.kv")
Test().run()
test.kv
BoxLayout:
Label:
text: "Hello"
font_size: app.f1
modules/variables.py
from kivy.properties import ObjectProperty
class FVars():
font_size_one = ObjectProperty('40dp')
font_size_two = ObjectProperty('60dp')
更新
为防止错误,您可以在 build
方法中加载 kv 文件。
def build(self):
self.title = 'Kivy Omnia!'
kv_screens = './screens/'
for kv in listdir(kv_screens):
Builder.load_file(kv_screens+kv)
kv_elements = './elements/'
for kv in listdir(kv_elements):
Builder.load_file(kv_elements+kv)
presentation = Builder.load_file("main.kv")
return presentation
有很多方法可以访问既不是 app
也不是 root
的 class 中的变量,您可以只设置 id
属性那个小部件。
这是一个基本示例:
main.py
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
class SecondClass(BoxLayout):
someNumber = 123 # Let's say we wanted to print the value of this variable when we press the button.
class FirstClass(BoxLayout):
pass
class TestApp(App):
def build(self):
return FirstClass()
TestApp().run()
test.kv
<SecondClass>:
<FirstClass>:
Button:
text: "Print the Numbah"
on_press: print(app.root.ids.secondclass.someNumber) # We can do something like this
SecondClass:
id: secondclass
我们也可以这样做:
<SecondClass>:
<FirstClass>:
Button:
text: "Print the Numbah"
on_press: print(root.ids.secondclass.someNumber)
SecondClass:
id: secondclass
或者这样:
<SecondClass>:
<FirstClass>:
Button:
text: "Print the Numbah"
on_press: print(secondclass.someNumber)
SecondClass:
id: secondclass
甚至这样:
<SecondClass>:
<FirstClass>:
second: secondclass
Button:
text: "Print the Numbah"
on_press: print(app.root.second.someNumber)
SecondClass:
id: secondclass
还有这个:
<SecondClass>:
<FirstClass>:
second: secondclass
Button:
text: "Print the Numbah"
on_press: print(root.second.someNumber)
SecondClass:
id: secondclass