How to send parameters to the __init__ function of widgets in the kv language ?

3,587 views
Skip to first unread message

sjinny

unread,
Dec 2, 2011, 10:15:58 PM12/2/11
to Kivy users support
I'm writing a tetris game as exercise. There's a class Tetris
implemented the game logic and a class UITetris derived from Tetris &
FloatLayout implemented the UI and render. I need to pass parameters
like game size or block size to the __init__ function of UITetris
because them should be determined at the first of the game created. Is
it possible ?
thanks :)

Shardul

unread,
Dec 7, 2011, 12:31:14 AM12/7/11
to Kivy users support
I think it is definitely possible. You can specify an optional kwargs
parameter with the init call which I believe is a python dictionary so
you can pass any name/value pairs to the init function.

Mathieu Virbel

unread,
Dec 7, 2011, 6:17:51 AM12/7/11
to kivy-...@googlegroups.com
Hi,

You can declare your classes using Kivy Properties:

    class UITetris(Widget):
        blocksize = ListProperty([1, 1])
        gamesize = ListProperty([1, 1])

Then, you can instanciate the widget with:

    >>> ui = UITetris(blocksize=(5, 2), gamesize=(1024, 768))
    >>> print ui.block size
    (5, 2)
    >>> ui.block_size = (3, 3)
    >>> print ui.block_size
    (3, 3)

Regards,

Mathieu

sjinny

unread,
Dec 7, 2011, 10:24:35 AM12/7/11
to Kivy users support
thanks but i can't receive properties in __init__ if I create widget
in kv language ...

Mathieu Virbel

unread,
Dec 7, 2011, 10:32:58 AM12/7/11
to kivy-...@googlegroups.com
Yes, if you're using kv language, the creation is delayed.

I can suggest you to use or bind your "update method" when a property
change, or defer loading.

When you need to do something on blocksize update:

class UITetris(Widget):
...
def on_blocksize(self, instance, value):
# put your things here

When you need to do something after multiple changes (clock trigger is a
good way)

class UITetris(Widget):
def __init__(self, **kwargs):
super(UITetris, self).__init__(**kwargs)
self._trigger_update =
Clock.create_trigger(self.my_update_func, 0)
self.bind(blocksize=self._trigger_update,
gamesize=self._trigger_update)

def my_update_func(self, *largs):
# put your things here, one or both blocksize/gamesize have
been updated


Or delayed initialization:

class UITetris(Widget):
def __init__(self, **kwargs):
super(UITetris, self).__init__(**kwargs)
Clock.schedule_once(self.late_init, 0)
def late_init(self, *largs):
# put your things here, it will be call one once before the
next frame.


The 3 methods have pro/cons, and can support different case. The second
one is the most robust i think.

Mathieu

Le 07/12/2011 16:24, sjinny a �crit :

sjinny

unread,
Dec 7, 2011, 10:50:38 AM12/7/11
to Kivy users support
Yes that's a way, thanks. So I think there's no way to pass parameters
to __init__ in kv language for now ?

> Le 07/12/2011 16:24, sjinny a �crit :

Mathieu Virbel

unread,
Dec 7, 2011, 11:47:08 AM12/7/11
to kivy-...@googlegroups.com
No way. Because some properties value can be an expression that depend
on other. To be able to execute it, you need the object. So it's already
__init__().

Le 07/12/2011 16:50, sjinny a �crit :

>> Le 07/12/2011 16:24, sjinny a �crit :

knappador

unread,
May 26, 2014, 12:26:33 AM5/26/14
to kivy-...@googlegroups.com
I've come into a situation where we need exactly what isn't currently possible in kv.  My object needs a property defined in kv file to instantiate a model that the other child widgets want to bind to.  I have to write incredibly verbose binds.

Mathieu is saying about expressions is true, but we don't need expressions for kwargs.  Would it hurt anything to support kwargs in the kv syntax?  If kwargs is specified, we update the kwargs being sent by the Factory with the literal dict in kwargs in kv.  This 100% solves the problem I have today and prevents a great many painful occasions where you need to customize a widget with a string, but you can't get that string to the widget's logic in time.

knappador

unread,
May 26, 2014, 1:05:17 AM5/26/14
to kivy-...@googlegroups.com
Passing arguments to constructors is a very natural way to customize Class instances.  It's so natural that not having it is really becoming irritating, so I'm putting it on my list for Kivy-Android-Nativer.

Current situation:
def on_foo()
root.foo.bar if Enter code here...
root.foo else ''
def on_parent()
   parent.bind(foo=self.watch_foo)

etc etc etc to deal with chicken and egg problems since I can't pass custom values to init and have to instead daisy-chain a bunch of binds.

Desired situation:
# in kv
MyClass:
    kwargs: {'foo', 'bar'}

# in python space
__init__(**kwargs):
    print kwargs     # shows Factory kwargs + {'foo': 'bar'}
    # use 'foo' to customize my object before children exist, avoiding NoneType object has no attribute 'foo' errors.
Reply all
Reply to author
Forward
0 new messages