fairly_oddparents
fairly_oddparents

Reputation: 131

How to create a custom Kivy Label Class with formatting in python?

I'm writing a desktop app using kivy but it doesn't run as fast as I would like it to. I have many labels and buttons with lots of formatting which only differ in colour and size. I hope that if I create a custom kivy Label with the formatting already on it will improve performance. I have already all my labels with the formatting and I wish to change them all to my custom kivy Label.

The original code in kivy file. Here is how all my labels look like.

Label:  
    text: "some text"  
    color: (0, 0.2, .4, 1)  
    size_hint: 1, 0.04  
    text_size: self.size  
    halign: 'left'  
    valign: 'top'  
    bold: True  
    canvas.before:  
        Color:  
            rgba: 1, 1, 1, 1  
        Rectangle:  
            pos: self.pos  
            size: self.size  

So I tried to create a FormattedLabel class to add to it all the formatting I wanted and then just change my Label for FormattedLabel in the kivy file.

Python file

import kivy  
from kivy.app import App  

from kivy.uix.label import Label  
from kivy.properties import ListProperty  
from kivy.graphics import Color, Rectangle  
from kivy.lang import Builder  

with open("crea_kivy_file.kv", encoding='utf8') as f: 
    Builder.load_string(f.read())  

class FormattedLabel(Label):  
    background_color = ListProperty()  

    def __init__(self, *args, **kwargs):  
        Label.__init__(self, *args, **kwargs)  
        self.canvas.add(Color(self.background_color))  
        self.canvas.add(Rectangle(pos=self.pos, size=self.size))  
        self.text_size= self.size  
        self.halign= 'left'  
        self.valign= 'top'  
        self.bold= True  

Kivy file

FormattedLabel:  
    text: "some text"  
    color: (0, 0.2, .4, 1)  
    size_hint: 1, 0.04  
    background_color: 0,0,0,1  

But it didn't produce the same results as my original code: 1. The size of the rectangle is off (narrower and taller) so the letters do not longer fit in a straight line. I don't know how to bind the rectangle's size to the size_hint in the kivy file. 2. The colour of the label doesn't change. I don't know if it is because the code should not be under init or because I'm just not getting how to write it properly. Thanks in advance for your help!

Upvotes: 1

Views: 1906

Answers (1)

ikolim
ikolim

Reputation: 16011

Problems

  1. The size of the rectangle is off (narrower and taller) so the letters do not longer fit in a straight line. I don't know how to bind the rectangle's size to the size_hint in the kivy file.
  2. The colour of the label doesn't change. I don't know if it is because the code should not be under init or because I'm just not getting how to write it properly.

Root Cause

The result is not as expected because Kivy has not completed its styling. For example, the size of the rectangle is off because it is using the default size of a widget i.e (100, 100).

The load_kv() function is called from run(), therefore, any widget whose styling is defined in this kv file and is created before run() is called (e.g. in __init__), won’t have its styling applied. Note that build() is called after load_kv has been called.

Solution

  1. Implement a method, initialize_widget()
  2. Replace canvas.add with canvas.before.add because without the before keyword, the text will not be visible.
  3. Use Kivy Clock schedule_once() method to invoke the initialize_widget() function after Kivy completed styling.

Snippets

from kivy.clock import Clock

...

class FormattedLabel(Label):  
    background_color = ListProperty()  

    def __init__(self, *args, **kwargs):  
        Label.__init__(self, *args, **kwargs)  
        Clock.schedule_once(lambda dt: self.initialize_widget(), 0.002)

    def initialize_widget(self):
        self.canvas.before.add(Color(self.background_color))  
        self.canvas.before.add(Rectangle(pos=self.pos, size=self.size))  
        self.text_size = self.size  
        self.halign = 'left'  
        self.valign = 'top'  
        self.bold = True  

Upvotes: 0

Related Questions