Adventures in Kivy

So here is a semi-live blog as I delve into Kivy.

Mission #1: Attempt to resize the default window

Ok let’s start at the start.

We first create an object that inherits from App. Done.

Ok, and the examples all return a widget from the App’s build() method. So we don’t over-ride __init__… ok… thats… unique.

Perhaps the widget is the window if it is returned from the build() method?

Widget is not the window. Widget returned from build() is added to the window. So… where is the window created?

Window docs state the window has a constructor that lets you set the window size. Ok, cool. But we don’t create the window… so.. we can’t use the constructor… sigh.

Ok, Window has a static accessor.

kivy.core.window.Window = None

No comment on what is stored here but I assume it’s the instantiated window. It doesn’t mention when it is set… handy!

Only 1 window allowed. Ok… weird. Well… let’s try that.

import kivy.core.window.Window
AttributeError: 'module' object has no attribute 'window'

Awesome…

Let’s scour the code.

Screen capture of Kivy window module

No Window.py file……… how far does this rabbit hole go.

Ok, let’s check out the __init__.py file in the window module.

class WindowBase(EventDispatcher):
 '''WindowBase is a abstract window widget, for any window implementation.

So… window base is in there. Feel free to scream now.

So we can get this by importing kivy.core.window and just leaving the class off the end.

import kivy.core.window
...
def build(self):
    print kivy.core.window.Window.size
    return None
(800, 600)

Ok sweet, thats our window.

So let’s change its size.

def build(self):
    print kivy.core.window.Window.size
    kivy.core.window.Window.size = (1024, 768)
    print kivy.core.window.Window.size
    return None
File "/Users/adamgriffiths/Workspace/VirtualEnvs/progress_quest/lib/python2.7/site-packages/kivy/core/window/__init__.py", line 243, in _set_size
 if super(WindowBase, self)._set_size(size):
 AttributeError: 'super' object has no attribute '_set_size'

FFFFFFFUUUUUUUUUUU

Ok, so after some googling we find this post about the relationship between the App and Window classes.

His solution is to pass the size as a command line parameter……….. LAME. That kinda throws the whole configuration settings thing out the window.

Looking through the Kivy code we find this block inside their base window class’ __init__ method.

if 'fullscreen' not in kwargs:
    fullscreen = Config.get('graphics', 'fullscreen')
        if fullscreen not in ('auto', 'fake'):
        fullscreen = fullscreen.lower() in ('true', '1', 'yes', 'yup')
    kwargs['fullscreen'] = fullscreen
if 'width' not in kwargs:
    kwargs['width'] = Config.getint('graphics', 'width')
if 'height' not in kwargs:
    kwargs['height'] = Config.getint('graphics', 'height')

Ok, so we can try and set it via the global config object.

So let’s add that to our App class.

def build_config(self, config):
    config.adddefaultsection('graphics')
    config.setdefault('graphics', 'width', 1024)
    config.setdefault('graphics', 'height', 768)
    config.set('graphics', 'height', 1024)
    config.set('graphics', 'width', 768)

Run the code and……

(800, 600)

……. sigh

So let’s put some debug INSIDE kivy and see what is happening. We’ll also force it to pull the ‘graphics’ setting and ignore kwargs.

if True: #'width' not in kwargs:
    kwargs['width'] = Config.getint('graphics', 'width')
print kwargs['width']
if True: #'height' not in kwargs:
    kwargs['height'] = Config.getint('graphics', 'height')
print kwargs['height']

And the output…

800
600

…. calm blue ocean…. calm blue ocean….

Ok… google…

Hmm.. ok, this post on the kivy-users forum (because documentation is for lusers) shows a similar method.

They use the Config module directly instead of the config object passed to App….. because….. they’re not the same? Well.. let’s try it anyway.

from kivy.config import Config
Config.set('graphics', 'width', 1024)
Config.set('graphics', 'height', 768)

And our output

(800, 600)

Ok, weird because the window HAS ACTUALLY CHANGED SIZE.

Whatever. We’re all living in crazy-ville atm so let’s just pretend everything is normal.

So let’s move that inside our build_config() method.

def build_config(self, config):
    Config.set('graphics', 'height', 1024)
    Config.set('graphics', 'width', 768)

And the output

[INFO ] Kivy v1.1.1
[INFO ] [Logger ] Record log in /Users/adamgriffiths/.kivy/logs/kivy_12-03-22_40.txt
[INFO ] [Factory ] 102 symbols loaded
[INFO ] [Text ] using <pygame> as text provider
[INFO ] [Loader ] using <pygame> as thread loader
[INFO ] [Window ] using <pygame> as window provider
[WARNING] [Window ] Unable to use <pygame> as windowprovider
[CRITICAL] [Window ] Unable to find any valuable Window provider at all!
Fatal Python error: (pygame parachute) Segmentation Fault
Abort trap: 6

(╯°□°)╯︵ ┻━┻

Advertisements

6 Responses to “Adventures in Kivy”

  1. Hieu L Says:

    I *just* had this *exact same* experience haha, I can understand the flipping table emotion – that’s what I did as well.

  2. Hieu L Says:

    Here’s what did it for me, but I’m not sure whether it’d work once it’s deployed:

    class MainUI(FloatLayout):
    pass

    class MainApp(App):
    # etc
    def build(self):
    Config.set(‘graphics’, ‘width’, ‘480’)
    Config.set(‘graphics’, ‘height’, ‘960’)
    return MainUI()

    • That’s the code that finally worked for me.
      But for some reason, if I remove the window import (import kivy.core.window), it segfaults.
      Why? No idea.
      Fun eh! ………

      Cheers,
      Adam

  3. Hi,

    Ok, this is something we need to explain more. Basically, we are splitted into several’s different aspect. We are re-factoring the documentation, so we’ll include a part about Window size approach.

    – We need an OpenGL context for any GL-related operation. That include text rendering, image loading, etc. So you except to have a Window when you actually build the application. Most people tend also to create some global Image.
    – Some platform doesn’t allow Window resizing (Android / iOS). Trying to define the size have no effect.
    – Window might be resized by the OS: any switch on Android/iOS rotation will resize it.
    – If we let you resize the Window after the creation (ie, build()), the OpenGL context will be trashed and recreated (behavior of the SDL/Pygame on Windows and OSX), and then, all the GL resources you already have uploaded are re-created. That would be unnecessary.

    I totally understand the table flip. I really apologize about that part of design (It was a learning process, we didn’t get it right from the start for _all_ platforms).

    That’s said, Config.set is currently the only way to correctly set the size preferences.

    • I understand the inability on some platforms to define the window size. But the values should just be ignored on those platforms.
      There are too many code paths to do the one thing, and none of them are obvious. The obvious one (defining the window size at instantiation time) isn’t present.

      I had a lot of trouble tracing through the logic.
      I was wanting to create some custom widgets, but it was near impossible to figure out where the rendering was actually done. No ‘draw background, then a label ontop’. It was all magic code. Register components and they magically ‘render themselves’.
      It may be cool, but IMO it’s obfuscation. I didn’t have the patience to trace through the code to figure it out.
      There may be some cool techniques in there to improve render speed to avoid re-draw, but I don’t see why it can’t be just rendered normally and cached as a texture in an obvious way.
      This is what I refer to as ‘smart-ass code’. Its cool, but only serves to confuse and alienate programmers.

      I also found the KV files confusing. I don’t understand the need to invent a second scripting language, when you’re already using python. Script-ception?
      The inability to define a widget as a template in a KV file (Ie, instantiate it multiple times) due to the need to have a unique name per widget, but inability to dynamically define the name in the KV file, means that they’re pretty much useless for defining common components.
      The Github examples demonstrate this problem pretty well, most of them have empty KV files.

      I’m not trying to be narky, these are just my firs impressions as a first time user of the library. And first impressions are what we all need to work on as programmers. Lowering the barrier of entry is the best thing for any project.
      Python needs great game / UI libraries, and the iOS / Android support is totally unique in the Python world (and many others).
      But I don’t like feeling out of control. And that’s what Kivy made me feel.

      Cheers,
      Adam

  4. vjgaero Says:

    this was a good read hahaha

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: