Skip to content
Home » Kivy Part 12 – Kivy Layouts Explained

Kivy Part 12 – Kivy Layouts Explained

Spread the love

You now know how to position and scale widgets inside layouts, but we’ve been using only the FloatLayout so far. Let’s have a look now at how the other layouts work.

But before we delve into the topic, here’s some info for you.

*****

Book Info

I just published my Kivy book, GUI Programming with Python and Kivy. It’s pretty long (over 800 pages) and comprehensive. And, which also counts, easy to read. The book contains lots of illustrations.

This book covers all the basics that you need to know to start programming GUI applications with Python and Kivy. Throughout the book we are building a GUI application from scratch, a fully functional game using all kinds of tools that Kivy has to offer. It’s our Slugrace project, but covered in a much more in-depth manner.

Each part of the book starts with a theoretical introduction of a topic or idea that we then implement in the project. I assume you have no prior knowledge of the Kivy library, but you should have at least some basic knowledge of the Python programming language, including the object-oriented programming paradigm as this is what we will be using a lot in this book.

Kivy book

The book covers all the basic elements of Kivy that you have to know, like widgets, layouts, Kivy ids and properties, graphics, screens, animation, sound. Finally we’ll deploy the app to Windows. It is pretty comprehensive and after you finish it, I’m sure you’ll be able to create your own awesome GUI apps of any kind, not just games.

I hope you will have at least as much fun reading the book as I had writing it.

As far as this Kivy series is concerned, the following parts will contain the most important elements covered in the book. However, some elements will be presented in a simplified way here on my blog or omitted completely.

____________

If you are interested, you can purchase the book in four versions. Here are the links:

1) ebook – pdf version on my website – in full color

Here you can see the description of the book, sample graphics from the book and the full table of contents.

2) ebook – Kindle version on Amazon – in full color

3) paperback version on Amazon – in black and white

4) paperback version on Amazon – in full color

*****

And Now Let’s Move On…

Before we dive into the other layouts, though, there’s one thing you should keep in mind. The positioning and sizing properties do not behave in the same way in all the layouts. Sometimes their behavior is not what you expect. This is why it’s easier to combine the existing layouts and embed them one into another so that we can reach our goal instead of using the properties described before. Don’t get me wrong, you can use both properties and combining layouts into larger hierarchies, but the latter is usually more intuitive tha the former, especially in less trivial projects. Anyway, in our project we’re going to use both techniques.

Now I’m going to discuss each of the layouts one by one, keeping it as simple as I can, and then, in the next part, I’ll show you a more complex example with embedded layouts.  So, with FloatLayout covered for now, let’s move on to RelativeLayout.

RelativeLayout

RelativeLayout works pretty much like FloatLayout and the difference will be clear only later when we embed it in another layout. Here’s a simple example with a RelativeLayout and just one button in it. The button should be positioned at the fixed coordinates 0, 0 and occupy about a third of the available space in both horizontal and vertical direction.

Here’s the Python code:

import kivy
from kivy.app import App

# We must import the RelativeLayout class.
from kivy.uix.relativelayout import RelativeLayout

class HelloWorldApp(App):
    def build(self):
        # We're going to use the RelativeLayout now.
        return RelativeLayout()

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

And here’s the kv file:

# File name: helloworld.kv

<RelativeLayout>:     
    Button:
        text: 'Button' 
        size_hint: .3, .3
        pos: 0, 0 

If you run this code you’ll see something you would also see using the FloatLayout:

RelativeLayout

So, what’s the difference? As mentioned before, you will see the difference soon. And now let’s move on to the next layout, the GridLayout.

GridLayout

To demonstrate how a GridLayout works we’ll need more than one widget in it. Let’s create five buttons this time. Here the Python code:

import kivy
from kivy.app import App

# We must import the GridLayout class.
from kivy.uix.gridlayout import GridLayout

class HelloWorldApp(App):
    def build(self):
        # We're going to use the GridLayout now.
        return GridLayout()

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

GridLayout rows

Now, with a GridLayout we must set the number of either rows or columns. The two properties that we use for that are rows and cols. Then the available space will be filled in gradually so that the predefined number of rows or columns is maintained, but let me show it on a example. First suppose we want the buttons to be in a grid consisting of two rows. Here’s the kv code:

# File name: helloworld.kv

<GridLayout>: 
    # We need two rows.
    rows: 2

    # And now come the buttons.    
    Button:
        text: 'Button 1' 
        size_hint: None, None
        size: 200, 50
    
    Button:
        text: 'Button 2' 
        size_hint: None, None
        size: 200, 50

    Button:
        text: 'Button 3' 
        size_hint: None, None
        size: 200, 50

    Button:
        text: 'Button 4' 
        size_hint: None, None
        size: 200, 50

    Button:
        text: 'Button 5' 
        size_hint: None, None
        size: 200, 50

Now, a few remarks about the code. First of all watch how I set size_hint to (None, None). This is because I wanted fixed numbers for pixels, each button being 200 x 50 pixels. You already know how it works from the previous part. The second thing you notice is that the code is very repetitive. If you now wanted to change the size of the button, you’d have to do it five times. So, let’s rewrite the code so that we avoid this repetitiveness. You already saw how to do it when we were talking about custom widgets. This time we’ll do it for the original button, because all the buttons in our example should be the same. Here’s the refactored and thus simplified code:

# File name: helloworld.kv

# Let's put all the shared stuff here.
<Button>:
    size_hint: None, None
    size: 200, 50

<GridLayout>: 
    # We need two rows.
    rows: 2

    # And here are the buttons with just the properties that are different
    # for each button.    
    Button:
        text: 'Button 1'
    
    Button:
        text: 'Button 2' 

    Button:
        text: 'Button 3' 

    Button:
        text: 'Button 4' 

    Button:
        text: 'Button 5' 

Here’s what you get when you run this code:

GridLayout

So, as you can see we indeed have two rows. The GridLayout is smart enough to know how many items to put in the first row before starting the second row. I numbered the buttons on purpose. You can now easily see what order the buttons were added in: first row 1 from left to right, then row 2 from left to right, for as long as there are any widgets left.

Your Panda3D Magazine

Make Awesome Games and Other 3D Apps

with Panda3D and Blender using Python.

Cool stuff, easy to follow articles.

Get the magazine here (PDF).

GridLayout cols

And now I’m going to achieve the same effect using the cols property. Let’s rewrite the kv code so that we set the number of columns to 3. Here’s the kv code:

# File name: helloworld.kv

<Button>:
    size_hint: None, None
    size: 200, 50

<GridLayout>: 
    # We need three columns now.
    cols: 3
       
    Button:
        text: 'Button 1'
    
    Button:
        text: 'Button 2' 

    Button:
        text: 'Button 3' 

    Button:
        text: 'Button 4' 

    Button:
        text: 'Button 5' 

And here’s what we get when we run the program:

GridLayout again

See any difference? Well, in this particular case there isn’t any. This is just how it works. The widgets are added from left to right, row after row. So, what if you set the number of columns to two? Let’s find out:

# File name: helloworld.kv

<Button>:
    size_hint: None, None
    size: 200, 50

<GridLayout>: 
    # We need two columns now.
    cols: 2
       
    Button:
        text: 'Button 1'
    
    Button:
        text: 'Button 2' 

    Button:
        text: 'Button 3' 

    Button:
        text: 'Button 4' 

    Button:
        text: 'Button 5' 

This time let’s arrange the buttons in a different way, in two columns:

GridLayout with two columns

But still, you can see that the order of adding them is again row by row, from left to right. OK, there is much more to the GridLayout, but we’ll be talking about some other Grid-related stuff when we need it later in our project. For now, let’s move on to the next layout.

Python Jumpstart Course

Learn the basics of Python, including OOP.

with lots of exercises, easy to follow

The course is available on Udemy.

BoxLayout

The BoxLayout is a very common layout and we’ll be making use of it a lot in our project. You can imagine it as a GridLayout with just one row or one column. If you want all the elements to be positioned in one row, you should set the orientation property to ‘horizontal’, or just leave it out altogether as this is the default value. If you want the elements to be in a column, you should set orientation to ‘vertical’. Let’s see how it works. Here’s the Python file:

import kivy
from kivy.app import App

# We must import the BoxLayout class.
from kivy.uix.boxlayout import BoxLayout

class HelloWorldApp(App):
    def build(self):
        # We're going to use the BoxLayout now.
        return BoxLayout()

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

Now, we want the five buttons that we have to be all in one row. Here’s the kv code:

# File name: helloworld.kv

<Button>:
    size_hint: None, None

    # Let's make the buttons slightly shorter so that they all
    # fit in one row.
    size: 100, 50

<BoxLayout>: 
    # The buttons should be in a row.
    orientation: 'horizontal'  # this is the optional default value
       
    Button:
        text: 'Button 1'
    
    Button:
        text: 'Button 2' 

    Button:
        text: 'Button 3' 

    Button:
        text: 'Button 4' 

    Button:
        text: 'Button 5' 

Here the app window:

horizontal BoxLayout

And now let’s put the buttons in a column:

# File name: helloworld.kv

<Button>:
    size_hint: None, None

    # Let's make the buttons slightly shorter so that they all
    # fit in one row.
    size: 100, 50

<BoxLayout>: 
    # The buttons should be in a column.
    orientation: 'vertical'  
       
    Button:
        text: 'Button 1'
    
    Button:
        text: 'Button 2' 

    Button:
        text: 'Button 3' 

    Button:
        text: 'Button 4' 

    Button:
        text: 'Button 5' 

And here’s what we’ll get:

vertical BoxLayout

Fine, let’s move on.

StackLayout

The next layout we’re going to talk about is the StackLayout. Let’s start with the Python code as usual:

import kivy
from kivy.app import App

# We must import the StackLayout class.
from kivy.uix.stacklayout import StackLayout

class HelloWorldApp(App):
    def build(self):
        # We're going to use the StackLayout now.
        return StackLayout()

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

Just like the BoxLayout, the StackLayout also has the orientation property, but it works in a different way. This layout arranges the widgets in a specific order and automatically moves on to the next row or column when it run out of space in the current row or column. The orientation property takes one of the following values:

rl-tb   :   right to left, top to bottom

lr-tb   :   left to right, top to bottom

rl-bt   :   right to left, bottom to top

lr-bt   :   left to right, bottom to top

Let’s try the out. Here’s the kv code:

# File name: helloworld.kv

<Button>:
    size_hint: None, None

    # Let's make the buttons slightly bigger.
    size: 300, 200

<StackLayout>: 
    # The buttons should be arranged from right to left, top to bottom.
    orientation: 'rl-tb'  
       
    Button:
        text: 'Button 1'
    
    Button:
        text: 'Button 2' 

    Button:
        text: 'Button 3' 

    Button:
        text: 'Button 4' 

    Button:
        text: 'Button 5' 

Here’s the app window. Watch what order the buttons appear in: first right to left and then top to bottom.

StackLayout rl-tb

Now let’s test the other combinations. There are only changes in the kv file. So, how about the order from left to right, top to bottom? Here’s the code:

# File name: helloworld.kv

<Button>:
    size_hint: None, None
    size: 300, 200

<StackLayout>: 
    # The buttons should be arranged from left to right, top to bottom.
    orientation: 'lr-tb'  
       
    Button:
        text: 'Button 1'
    
    Button:
        text: 'Button 2' 

    Button:
        text: 'Button 3' 

    Button:
        text: 'Button 4' 

    Button:
        text: 'Button 5' 

Watch the result now:

StackLayout lr-tb

And now right to left, bottom to top:

# File name: helloworld.kv

<Button>:
    size_hint: None, None
    size: 300, 200

<StackLayout>: 
    # The buttons should be arranged from right to left, bottom to top.
    orientation: 'rl-bt'  
       
    Button:
        text: 'Button 1'
    
    Button:
        text: 'Button 2' 

    Button:
        text: 'Button 3' 

    Button:
        text: 'Button 4' 

    Button:
        text: 'Button 5' 

And the app now looks like this:

StackLayout rl-bt

Finally, left to right, bottom to top:

# File name: helloworld.kv

<Button>:
    size_hint: None, None
    size: 300, 200

<StackLayout>: 
    # The buttons should be arranged from left to right, bottom to top.
    orientation: 'lr-bt'  
       
    Button:
        text: 'Button 1'
    
    Button:
        text: 'Button 2' 

    Button:
        text: 'Button 3' 

    Button:
        text: 'Button 4' 

    Button:
        text: 'Button 5' 

And here’s the app window:

StackLayout lr-bt

Blender Jumpstart Course

Learn the basics of 3D modeling in Blender.

step-by-step, easy to follow, visually rich

The course is available on Udemy and on Skillshare.

AnchorLayout

We use this layout to anchor widgets in particular positions, like at the top or bottom, or on one of the sides. It lends itself well to create menus. The two properties used with this layout are anchor_x and anchor_y. Let’s first rewrite the Python file to make use of the AnchorLayout:

import kivy
from kivy.app import App

# We must import the AnchorLayout class.
from kivy.uix.anchorlayout import AnchorLayout

class HelloWorldApp(App):
    def build(self):
        # We're going to use the AnchorLayout now.
        return AnchorLayout()

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

And now the kv file:

# File name: helloworld.kv

<Button>:
    size_hint: None, None

    # Let's make the button smaller again.
    size: 100, 50

<AnchorLayout>: 
    # Let's position the button in the upper right corner.
    anchor_x: 'right'
    anchor_y: 'top'  
       
    Button:
        text: 'Button'

Here’s what the app looks like:

AnchorLayout

Well, I added just one button here because otherwise the buttons would be on top of one another and only the last one would be visible unless we changed the sizes of some of them. This layout is more practical if you want to position a custom widget, or even more if you want to position another embedded layout. For example you can imagine making a menu consisting of 5 labels positioned in a row inside a BoxLayout and then positioning the whole menu inside the AnchorLayout. We’re going to see some embedding examples in the next part. And now some more examples with the AnchorLayout. Only the kv file is going to change. Here’s the first example. We want to position the button in the center (horizontally) and at the top:

# File name: helloworld.kv

<Button>:
    size_hint: None, None

    # Let's make the button smaller again.
    size: 100, 50

<AnchorLayout>: 
    # Let's position the button in top central position.
    anchor_x: 'center'
    anchor_y: 'top'  
       
    Button:
        text: 'Button'

Here’s our app:

AnchorLayout with top-centered button

And now let’s place the button in the lower left corner:

# File name: helloworld.kv

<Button>:
    size_hint: None, None

    # Let's make the button smaller again.
    size: 100, 50

<AnchorLayout>: 
    # Let's position the button in lower left corner.
    anchor_x: 'left'
    anchor_y: 'bottom'  
       
    Button:
        text: 'Button'

The result is:

AnchorLayout with a button in the lower left corner

OK, just one more example. Let’s say the button should be in the very middle. Here’s the code:

# File name: helloworld.kv

<Button>:
    size_hint: None, None

    # Let's make the button smaller again.
    size: 100, 50

<AnchorLayout>: 
    # Let's position the button in lower left corner.
    anchor_x: 'center'
    anchor_y: 'center'  
       
    Button:
        text: 'Button'

Now you will get this:

AnchorLayout with centered widget

So, now you more or less know how to use the layouts independently. In the next part I’ll show you how to embed layouts in other layouts. We’ll be embedding layouts a lot in the project.


Spread the love

Leave a Reply