Search code examples
pythonkivy

Positioning widgets in a grid cell?


I am trying to position labels dynamically added to a grid. I'd like the label widgets in the 2nd column to all align to the right side of the column rather than the left. I've tried all kinds of alignment to no avail. So I've pared it back to this demo code At this stage I'm wondering if I can bind the label width to the column width and then use alignment. Or can I override on_size for the label and adjust it to the parent grid column?

grid alignment demo

Code

import kivy
kivy.require('2.1.0')

from kivy.app            import App
from kivy.uix.label      import Label
from kivy.uix.gridlayout import GridLayout
from kivy.factory        import Factory

class AlignTestGridLayout(GridLayout):

    def __init__(self, **kwargs):
        super(AlignTestGridLayout, self).__init__(**kwargs)

    def update( self, *args):
        for j in range(0,4):
            for i in range(0,4):
                newCell = Factory.GridEntry()
                newCell.text = 'text' + ( str(j) * (j + 1))
                self.ids.gridCalendar.add_widget( newCell )

class AlignTestApp(App):

    def build(self):
        AlignTest = AlignTestGridLayout()
        AlignTest.update()
        return AlignTest

if __name__ == '__main__':

    AlignTestApp().run()

KV

#:kivy 2.1.0

<Widget>:
    # draw outlines for debugging only
    canvas.after:
        Line:
            rectangle: self.x+1,self.y+1,self.width-1,self.height-1
            dash_offset: 5
            dash_length: 3

<GridEntry@Label>:
    padding_x: 5
    font_size: 25
    size_hint: (None, None)
    size: self.texture_size

<AlignTestGridLayout>:
    GridLayout:
        id: gridCalendar
        cols: 4
        rows: 4
        size: self.minimum_size

Solution

  • You can use the halign property of Label to position its text but that has no effect when its size is bound to its texture_size. So in order to use that property you can bind only its height to its texture height and modify its text_size.

    Also in that case you can restrict its parent layout, here GridLayout, in height by using minimum_height (also to restrict the width you can specify that explicitly or use col_default_width etc.).

    With all this your modified code in kvlang would now look like,

    #:kivy 2.1.0
    
    <Widget>:
        # draw outlines for debugging only
        canvas.after:
            Line:
                rectangle: self.x+1,self.y+1,self.width-1,self.height-1
                dash_offset: 5
                dash_length: 3
    
    <GridEntry@Label>:
        padding_x: 5
        font_size: 25
        size_hint_y: None
        height: self.texture_size[1]
        text_size: self.width, None
    
    <AlignTestGridLayout>:
        cols: 1  # You must provide a value to at least one of `cols` and `rows`.
        GridLayout:
            id: gridCalendar
            cols: 4
            rows: 4
            size_hint_y: None
            height: self.minimum_height
    

    Now to alter labels' position in particular column you can modify the logic as,

        def update( self, *args):
            for j in range(0,4):
                for i in range(0,4):
                    newCell = Factory.GridEntry()
                    newCell.halign = "right" if i == 1 else "left"
                    newCell.text = 'text' + ( str(j) * (j + 1))
                    self.ids.gridCalendar.add_widget( newCell )