Search code examples
kivy

Why doesn't my Kivy label text fit in the label?


I have a big knowledge gap about how Kivy sizes the various elements, and it is being resistant to my attempts to fix it.

Here is my stopwatch.kv file

#:kivy 1.11.1

<StopWatch>:
    BoxLayout:
        orientation: 'vertical'
        canvas.before:
            Color:
                rgba: .2, .2, .2, 1
            Rectangle:
                pos: self.pos
                size: self.size
        Label:
            text: "A long piece of text #1"
            size: self.texture_size
            canvas.before:
                Color:
                    rgba: .5, .1, .1, 1
                Rectangle:
                    pos: self.pos
                    size: self.size
        Label:
            text: "A long piece of text #2"
            size: self.texture_size
            text_size: root.width, None
            canvas.before:
                Color:
                    rgba: .5, .5, .1, 1
                Rectangle:
                    pos: self.pos
                    size: self.size

Here is main.py:

from kivy.app import App
from kivy.uix.widget import Widget


class StopWatch(Widget):
    pass


class StopWatchApp(App):
    def build(self):
        sw = StopWatch()
        return sw


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

I have figured out the size of the window (on my desktop) is, by default, unrelated to its contents. Okay.

I have figured out the size of the BoxLayout is, by default, unrelated to the window size. Instead, it is large enough to enclose its children widgets. Okay.

I have figured out that the size of a Label is, by default, unrelated to the size of its text contents. Instead, I think it is 100x100, but I haven't found that documented.

If you want a label to be big enough to cover the text (and hence the BoxLayout to cover the text), you have to specify:

size: self.texture_size

Okay. But I do that for the first label, and it still exceeds its label size (which I use a rectangle coloured red to visualise.)

So, I try to specify the text_size in the second label - making it the full width of the window - but its text doesn't appear at all!

Screenshot

I know I am missing something obvious, but reading the manuals hasn't helped.


Solution

  • The problem is that your StopWatch extends Widget, and Widget is not intended as a container. See the Widget Class.

    Note the part that says:

    • A Widget is not a Layout: it will not change the position or the size of its children. If you want control over positioning or sizing, use a Layout.
    • The default size of a widget is (100, 100). This is only changed if the parent is a Layout. For example, if you add a Label inside a Button, the label will not inherit the button’s size or position because the button is not a Layout: it’s just another Widget.
    • The default size_hint is (1, 1). If the parent is a Layout, then the widget size will be the parent layout’s size.

    So, your StopWatch will be size (100,100), and your Labels are wider than that. A simple solution is to change your StopWatch to extend a Layout like this:

    class StopWatch(BoxLayout):
        pass
    

    Then you can rewrite your kv as:

    #:kivy 1.11.1
    
    <StopWatch>:
        orientation: 'vertical'
        canvas.before:
            Color:
                rgba: .2, .2, .2, 1
            Rectangle:
                pos: self.pos
                size: self.size
        Label:
            text: "A long piece of text #1"
            size: self.texture_size
            canvas.before:
                Color:
                    rgba: .5, .1, .1, 1
                Rectangle:
                    pos: self.pos
                    size: self.size
        Label:
            text: "A long piece of text #2"
            size: self.texture_size
            text_size: root.width, None
            canvas.before:
                Color:
                    rgba: .5, .5, .1, 1
                Rectangle:
                    pos: self.pos
                    size: self.size
    

    Note that the BoxLayout has been removed from the kv, since StopWatch is now a BoxLayout. Also, note that your size properties of the Labels in your kv will have no effect unless you set size_hint to (None, None), since size_hint takes precedence over size.