如何在 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)时,它不起作用。

项目结构:

代码:

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' 未定义

感谢您的回答。

再见

编辑:由于下面的答案适用于示例代码,但不适用于我的实际项目,因此我添加了相关的项目代码:

项目结构:

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