Kivy button text alignment issue

Adam Gaskins picture Adam Gaskins · Mar 11, 2013 · Viewed 14.2k times · Source

I am trying to develop an email application in Kivy, basically just as an exercise to learn the in's and out's of the framework... I am trying to create the initial window and have reached a bit of a stumbling block! The idea is that it will simply display a list of emails in the inbox, much like any basic email app on a mobile device.

The problem I'm having is that I can't figure out how to get the text of each list item (which is a just a button) to align properly. Using "halign='left'" in my button will make the text align left, but only relative to each button; it's still centered within each button.

My actual app is a bit large to post, so this is a quick and dirty example I made from a stock Kivy example. (I realize this code isn't perfect... like I said quick and dirty for examples sake... it does work though!) So as you can see, the two rows of text on each button align with each other, but they don't all align overall. Can anyone suggest what I would do to make all the text align at, say, 10px from the left of each button? I did find one relative sounding item on StackOverflow, but it didn't really answer the question for example, it seemed to deal more with using images on buttons. I am new to Kivy, but I've read through the tutorials and documentation, as well as searched Google extensively - so any help would be greatly appreciated!

import kivy
kivy.require('1.0.8')

from kivy.app import App
from kivy.core.window import Window
from kivy.uix.button import Button
from kivy.uix.scrollview import ScrollView
from kivy.uix.gridlayout import GridLayout

import random


class ScrollViewApp(App):

    def build(self):
        # create a default grid layout with custom width/height
        layout = GridLayout(cols=1, spacing=10, size_hint=(None, None),
                            width=Window.width)

        # when we add children to the grid layout, its size doesn't change at
        # all. we need to ensure that the height will be the minimum required to
        # contain all the childs. (otherwise, we'll child outside the bounding
        # box of the childs)
        layout.bind(minimum_height=layout.setter('height'))

        # add button into that grid
        for i in range(30):
            btn = Button(text=str(i * random.random()) + '\n' + str(i * random.random()),
                         size=(300, 40),
                         size_hint=(None, None),
                         halign='left')
            layout.add_widget(btn)

        # create a scroll view, with a size < size of the grid
        root = ScrollView(size_hint=(None, None))
        root.size = (Window.width, Window.height)
        root.center = Window.center
        root.add_widget(layout)

        return root

if __name__ == '__main__':

    ScrollViewApp().run()

Answer

qua-non picture qua-non · Mar 11, 2013

The documentation of Button starts with "A Button is a Label". Even for Widgets that don't mention their lineage explicitly, you should take a note of the second line in the API doc of the Widget in question. In this case "Bases: kivy.uix.label.Label".

This establishes that the button inherits from a Label. (I am explicitly mentioning this because this part of looking at the base Class's inherited properties sometimes is not intuitive for everyone).

If you look at the Docs for label, specifically the halign property, it asks you to utilize text_size to achieve proper text alignment. What this means is the text is aligned inside a bounding box that is set by the text_size property. This property can be set to be:

a) The size of the Widget. text_size: self.size

b) Less than the size of the size of the widget (what you are looking for) text_size: self.width - dp(10), self.height - dp(10)

c) Unconstrained on one of the sides text_size: self.width, None

d) or both text_size: None, None

e) or constrained to a different Widget text_size: other_button.size

The reason for using text_size is to give more control to the user. You should also look at the textalign example