adn05
adn05

Reputation: 308

How to customize style.kv in Kivy

According to Kivy Doc, I can customize a kivy app look, by creating a local style.kv file that will be use instead of standard. So I edited the original file, by modifying, the behavior of the Button widget like this :

<-Button,-ToggleButton>:
    canvas:
        Color:
            rgba: [1, 0, 0, 1] if self.state == 'normal' else [0, 0, 1, 1]
        Rectangle:
            pos: self.pos
            size: self.size
        Color:
            rgba: 1, 1, 1, 1
        Rectangle:
            texture: self.texture
            size: self.texture_size
            pos: int(self.center_x - self.texture_size[0] / 2.), int(self.center_y - self.texture_size[1] / 2.)

I was hoping that buttons background's become red and change to blue when clicked. But nothings happen, and the default behavior was applied.

This is the content of my main file

from os.path import abspath, dirname, join

from kivy.app import App
from kivy.resources import resource_add_path, resource_find
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button


class MainLayout(BoxLayout):
    def __init__(self, **kwargs):
        super(MainLayout, self).__init__(**kwargs)
        self.add_widget(Button(text="Button1"))
        self.add_widget(Button(text="Button2"))

class MainApp(App):
    def build(self):
        return MainLayout()


if __name__ == '__main__':
    res_path = join(dirname(abspath(__file__)), "custom")
    resource_add_path(res_path)
    print("find ", resource_find("data/style.kv"))
    MainApp().run()

At runtime, the local path of the style.kv is well printed.

All help is greatly appreciated!

Upvotes: 2

Views: 3148

Answers (2)

Caleb Sword
Caleb Sword

Reputation: 31

When loading style.kv, Kivy looks for wherever the "Kivy data directory" is on the local machine's environment. It does so with an absolute filepath, not a relative filepath, so Kivy won't ever automatically load a style.kv file from any directory added with resource_add_path.

This means if you create a custom data directory, then you must modify the environment variable KIVY_DATA_DIR.

However, Kivy loads style.kv the moment that the Kivy package is imported. So, if you want to set this environment variable in Python, you will have to do something like

import os
# this must be written BEFORE you import anything from Kivy
os.environ['KIVY_DATA_DIR'] = 'path/to/your/custom/data/directory'

from kivy.app import App 
# etc

Note that if you create a custom Kivy data directory with only a style.kv file, a lot of things will break. Hence I recommend you copy everything which exists in the default Kivy directory (which on Windows you can probably find at C:\Users\<your_username>\AppData\Local\Programs\Python\<your_python_version>\Lib\site-packages\kivy\data; or you can just download it from the Kivy source code) and place it in your custom data directory. Then you incrementally modify the copied style.kv in your custom data directory.

If you don't want to go through all this trouble just to modify style.kv, then a simpler approach is to just do the following:

import kivy
from kivy.lang import Builder

Builder.unload_file(os.path.join(kivy.__file__, '../data/style.kv'))
Builder.load_file('path/to/your/custom/data/directory/style.kv')

# the rest of your application goes here

Upvotes: 1

John Anderson
John Anderson

Reputation: 39002

Even though the documentation says that you can customize kivy exactly the way you have attempted, it does not look like it works. However, you can get it to work by just loading your modified style.kv using kivy.lang.Builder. For example:

from kivy.lang import Builder

Builder.load_string('''
<-Button,-ToggleButton>:
    canvas:
        Color:
            rgba: [1, 0, 0, 1] if self.state == 'normal' else [0, 0, 1, 1]
        Rectangle:
            pos: self.pos
            size: self.size
        Color:
            rgba: 1, 1, 1, 1
        Rectangle:
            texture: self.texture
            size: self.texture_size
            pos: int(self.center_x - self.texture_size[0] / 2.), int(self.center_y - self.texture_size[1] / 2.)
''')

from os.path import abspath, dirname, join

from kivy.app import App
from kivy.resources import resource_add_path, resource_find
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button


class MainLayout(BoxLayout):
    def __init__(self, **kwargs):
        super(MainLayout, self).__init__(**kwargs)
        self.add_widget(Button(text="Button1"))
        self.add_widget(Button(text="Button2"))

class MainApp(App):
    def build(self):
        return MainLayout()

if __name__ == '__main__':
    MainApp().run()

Upvotes: 2

Related Questions