Gostaria de importar elementos opcionais da GUI definidos em arquivos Mod1.py
/ Mod2.py
/etc separados e adicioná-los/remover dinamicamente da GUI principal. Os arquivos separados que definem esses elementos opcionais da GUI contêm kv
strings. No meu caso de uso, esses elementos da GUI podem ser descarregados/recarregados várias vezes. Descobri que se eu tiver classes com nomes idênticos nos Modx.py
arquivos, isso cria uma conversa cruzada entre os módulos porque Builder.load_string
funciona cumulativamente. O pano de fundo para essa descoberta está aqui - Importando vários módulos contendo classes com nomes idênticos em python
A documentação do Kivy Builder sugere que uma determinada kv
string pode ser seletivamente descarregada mais tarde se um pseudo nome de arquivo for fornecido, por exemplo
Builder.load_string("""<kv string>""", filename="myrule.kv")
, e mais tarde para descarregar -
Builder.unload_file("myrule.kv")
No entanto, quando tento isso, parece funcionar apenas na primeira vez que um módulo é descarregado e outro é carregado. Depois disso, os elementos opcionais da GUI não aparecem mais quando recarregados. O exemplo a seguir demonstra isso.
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button
from kivy.lang import Builder
import importlib
Builder.load_string('''
<MainWidget>:
orientation: 'vertical'
BoxLayout:
Button:
text: "Load Mod 1"
on_press:
root.load_module(self.text)
Button:
text: "Load Mod 2"
on_press:
root.load_module(self.text)
Button:
text: "Unload all"
on_press:
dock.clear_widgets()
FloatLayout:
id: dock
''')
class MainWidget(BoxLayout):
def load_module(self, hint):
self.ids.dock.clear_widgets()
Builder.unload_file("foo.kv")
if "1" in hint:
self.module = importlib.import_module("Mod1").Module()
if "2" in hint:
self.module = importlib.import_module("Mod2").Module()
self.ids.dock.add_widget(self.module)
class MyApp(App):
def build(self):
return MainWidget()
if __name__ == '__main__':
MyApp().run()
Mod1.py
from kivy.uix.floatlayout import FloatLayout
from kivy.lang import Builder
Builder.load_string('''
<Module>:
size_hint: None, None
size: self.parent.size if self.parent else self.size
pos: self.parent.pos if self.parent else self.pos
Button:
size_hint: None, None
width: self.parent.width / 3
height: self.parent.height
pos: self.parent.pos
text: "Mod 1"
on_press: print(root); print([x for x in dir(root) if 'method' in str(x)])
''', filename="foo.kv")
class Module(FloatLayout):
def __init__(self, **kwargs):
super(FloatLayout, self).__init__(**kwargs)
def dummymethod1(self):
pass
Mod2.py
from kivy.uix.floatlayout import FloatLayout
from kivy.lang import Builder
Builder.load_string('''
<Module>:
size_hint: None, None
size: self.parent.size if self.parent else self.size
pos: self.parent.pos if self.parent else self.pos
Button:
size_hint: None, None
width: self.parent.width / 3
height: self.parent.height
pos: (self.parent.x + self.parent.width / 2) , self.parent.y
text: "Mod 2"
on_press: print(root); print([x for x in dir(root) if 'method' in str(x)])
''', filename="foo.kv")
class Module(FloatLayout):
def __init__(self, **kwargs):
super(FloatLayout, self).__init__(**kwargs)
def dummymethod2(self):
pass
Gostaria de saber se há uma maneira de fazer isso funcionar corretamente. Talvez eu esteja esquecendo de algo sobre a maneira como o Kivy builder funciona?