Как использовать переменные в kivy, которые определены в другом модуле .py (не main.py)? - PullRequest
0 голосов
/ 05 февраля 2019

Я хочу, чтобы все переменные для приложения были определены в модуле .py отдельно от файла main.py.Затем я хочу использовать эти переменные внутри файла kivy.

Я пробовал приведенный ниже код с несколькими вариантами, и всегда есть ошибки.Модуль отлично работает, например, для определения различных шрифтов, но когда дело доходит до свойств (ObjectProperty), он не работает.

Структура проекта:

  • KivyFolder

    • модули (папка)

      • 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 name должно прочитать его.

Я также пробовал:

font_size: app.variables.font_size_one

и:

font_size: app.modules.variables.font_size_one

Затем я попытался импортировать модуль перед всем остальным с тем же результатом.

Я также попытался поместить его в класс и вызвать этот класс в .kv следующим образом:

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' не определено

Спасибо за ваши ответы.

Пока

РЕДАКТИРОВАТЬ: Поскольку ответ нижеработает над примером кода, но не в моем реальном проекте. Я добавляю соответствующий код проекта:

Структура проекта:

  • KivyFolder

    • модули (папка)

      • 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: файл "C: \ Users \ Ghost \ CodeProjects \ phyton \ kivyomnia \ Screen \ Intro.kv", строка 10: ... 8: Метка: 9: text: "Hello" + root.user_name + "!"

10: font_size: app.title_size 11: font_name: "Exo-B" 12: AnchorLayout: ... BuilderException: Parser: файл "C: \ Users \ Ghost \ CodeProjects \ phyton \ kivyomnia \screen \ Intro.kv", строка 10: ... 8: Метка: 9: текст: "Hello" + root.user_name + "! "10: font_size: app.title_size 11: font_name:" Exo-B "12: AnchorLayout: ... AttributeError: У объекта 'NoneType' нет атрибута 'bind' File 'C: \ Python37-32 \ lib \ site-packages \ kivy \ lang \ builder.py ", строка 249, в create_handler возвращают eval (значение, idmap), файл bound_list, файл" C: \ Users \ Ghost \ CodeProjects \ phyton \ kivyomnia \ Screen \ Intro.kv ", строка 10,в файле font_size: app.title_size "C: \ Python37-32 \ lib \ site-packages \ kivy \ lang \ parser.py ", строка 75, в getattribute объект. getattribute (self, _ensure_app ') () Файл" C: \ Python37-32 \ lib \ site-packages\ kivy \ lang \ parser.py ", строка 70, в _ensure_app app.bind (on_stop = лямбда-экземпляр:

Файл" C: \ Python37-32 \ lib \ site-packages "\ kivy \ lang \ builder.py ", строка 615, в _apply_rulerctx ['ids']) Файл "C: \ Python37-32 \ lib \ site-packages \ kivy \ lang \ builder.py", строка 254, в create_handler reason = tb)

Итакесли просто изменить положение:

title_size = globalVariables.title_size

... внутри IntroScreen (Экран), а затем внутри Intro.kv:

font_size: root.title_size

... это работает.Но дело в том, чтобы все глобальные переменные были доступны на всех экранах.

Другой вопрос:

если app.something получает то, что находится внутри основного класса приложения, а root.something получает то, что находится в корневом классе этого файла, тогда как вы вызываете что-то из другого классаэто не приложение или root.Если это имеет смысл.

1 Ответ

0 голосов
/ 05 февраля 2019

Вы можете импортировать ваш класс FVars с помощью этой строки:

from modules.variables import FVars

Затем внутри вашего класса MainApp вы можете создать переменную класса с данными переменной класса FVars.

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')

ОБНОВЛЕНИЕ

Чтобы предотвратить ошибку, вы можете загрузитьkv-файлы внутри метода build.

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, вы можете просто установить 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
...