Table of Contents
Brief
Following the principle of separation of concerns kvlang enables separation of the GUI (Graphical User Inerface) definition, "the dashboard", from the general code, "the engine". However, when the GUI is user configurable, kvlang alone is inadequate for its fixed graphical description. Rather than create a *.kv / *.py mix the following method that uses the pyexpander preprocessor module let us do "everything" within the .kv file.
For comments contact: ixew
Software versions
The following example is current with kivy 1.10.0 (405) and pyexpander 1.8.3 (1).
project.py example
Thanks to kivy.context we can modify the kivy.lang Builder instance. Note that the ExpanderBuilder instance operates on the same objects which the Builder earlier created when processing the default style.kv.
from kivy.context import get_current_context
from kivy.lang.builder import Builder, BuilderBase
from copy import copy
from pyexpander.lib import expandToStr
# ...
class ExpanderBuilder(BuilderBase):
def __init__(self, app, builder):
super(BuilderBase, self).__init__()
self.app = app
self.files = builder.files
self.dynamic_classes = builder.dynamic_classes
self.templates = builder.templates
self.rules = builder.rules
self.rulectx = builder.rulectx
def load_string(self, string, **kwargs):
defs = {'config': self.app.config}
xstring = expandToStr(string, external_definitions=defs)[0]
return super(ExpanderBuilder, self).load_string(xstring, **kwargs)
class ProjectApp(App):
def __init__(self):
super(ProjectApp, self).__init__()
context = copy(get_current_context())
context['Builder'] = ExpanderBuilder(self, Builder)
context.push()
def build(self):
context = get_current_context()
context.pop()
return super(ProjectApp, self).build()
project.kv example
$py(many = config.getint('general', 'devices'))
ScreenManager:
$for(x in range(many))
Device:
prev: g$(((x-1) % many) + 1).name
name: g$(x + 1).name
next: g$(((x+1) % many) + 1).name
$endfor\
Having two devices the builder load_string() would get the following expanded input:
ScreenManager:
# ...
Device:
prev: g2.name
name: g1.name
next: g2.name
Device:
prev: g1.name
name: g2.name
next: g1.name