0

I would like to build the following simple design in a .kv file.

design

It is made of 3 parts :

  • One top-left Anchor Layout which is made up of a Grid Layout of 3 columns. I want its width to be equal to 20% of the window's with and its height to be equal to 75% of the window's height.
  • One top-right Anchor Layout which is made up of a vertically-oriented Box Layout. I want its width to be equal to 80% of the window's with and its height to be equal to 75% of the window's height.
  • One bottom-left Anchor Layout which is empty for the moment. I want its height to be 25% of the window's height.

These three parts are themselves included in an AnchorLayout.

I tried to translate this design into a .kv file as follows.

#:kivy 1.11.1

<Example>:
    anchor_x: "center"
    anchor_y: "center"

    AnchorLayout:
        anchor_x: "left"
        anchor_y: "top"
        size_hint: (0.2, 0.75)

        GridLayout:
            cols: 3
            Button:
                text: "X"
            Button:
                text: "X"
            Button:
                text: "X"
            Button:
                text: "X"
            Button:
                text: "X"
            Button:
                text: "X"

    AnchorLayout:
        anchor_x: "right"
        anchor_y: "top"
        size_hint: (0.8, 0.75)

        BoxLayout:
            orientation: "vertical"
            Label:
                text: "HELLO..."
            Label:
                text: "WORLD..."

    AnchorLayout:
        anchor_x: "left"
        anchor_y: "bottom"
        size_hint: (1, 0.25)

        Label:
            text: "FOOTER"

In case it matters, here is the code of my .py file as well.

# Importing Kivy
import kivy
kivy.require("1.11.1")

# Importing kivy libraries
from kivy.app import App
from kivy.uix.anchorlayout import AnchorLayout
from kivy.lang import Builder


# Importing external libraries


# Import kv files
Builder.load_file("example.kv")


# Root widget of the application
class Example(AnchorLayout):
    pass


# Application class
class TestApp(App):
    def build(self, **kwargs):
        return Example()

# Launch the application
if __name__=="__main__":
    app = TestApp()
    app.run()

The output does not look as I expected as shown on the picture below :

screenshot2

I don't get it. Because the AnchorLayout is a subclass of the Widget class and is itself included within a Layout, its size_hint property should enable me to define its size.

What am I missing here ? Thanks in advance!

SteeveL
  • 11
  • 2
  • The `anchor_x` and `anchor_y` properties of the `AnchorLayout` affect the children of the `AnchorLayout`, so your `Example` layout is trying to put all its children close to the center. – John Anderson Jun 27 '19 at 16:45
  • Thanks a lot, it is perfectly logical! – SteeveL Jun 27 '19 at 17:27

2 Answers2

2

Problem - design centered

The design is placed in the center.

Root Cause

The root is an AnchorLayout with value 'center' for both anchor_x and anchor_y. Therefore, all its children (the AnchorLayouts) are placed in respect to the root.

Below is a view of your design in different colours for visualization.

Design - canvas painted

AnchorLayout

The AnchorLayout aligns its children to a border (top, bottom, left, right) or center.

Solution

There are three possible solutions to your design. The preference is method 1.

Method 1 - No AnchorLayouts

This method replace all AnchorLayouts with BoxLayouts. It use one less AnchorLayout widget which makes the app more resource efficient i.e. use less memory and the app is smaller.

Snippets - Method 1

<Example>:
    orientation: 'vertical'

    BoxLayout:
        ...
        GridLayout:    # left box
            ...
        BoxLayout:    # right box
            ...
    BoxLayout:    # footer
        ...

Method 2 - BoxLayout as root

This method replace the root widget with BoxLayout and realign the left box.

Snippets - Method 2

<Example>:
    orientation: 'vertical'

    AnchorLayout:
        ...
        GridLayout:    # left box
            ...
        AnchorLayout:    # right box
            ...
    AnchorLayout:    # footer
        ...

Method 3

This method add a BoxLayout as a child of the root, and the rest of the AnchorLayout as children of the BoxLayout.

Snippets - Method 3

<Example>:
    anchor_x: "center"
    anchor_y: "center"

    BoxLayout:
        orientation: 'vertical'

        AnchorLayout:
            ...
            GridLayout:    # left box
                ...
            AnchorLayout:    # right box
                ...
        AnchorLayout:    # footer
            ...

Example

Method 1 - No AnchorLayouts

main.py

from kivy.base import runTouchApp
from kivy.lang import Builder

runTouchApp(Builder.load_string("""

BoxLayout:
    orientation: 'vertical'

    BoxLayout:
        size_hint: 1, 0.75

        GridLayout:
            size_hint: 0.2, 1

            canvas.before:
                Color:
                    rgba: 1, 0, 0, 1
                Rectangle:
                    size: self.size
                    pos: self.pos

            cols: 3
            row_force_default: True
            row_default_height: 40

            Button:
                text: "X"
            Button:
                text: "X"
            Button:
                text: "X"
            Button:
                text: "X"
            Button:
                text: "X"
            Button:
                text: "X"            

        BoxLayout:
            orientation: 'vertical'

            canvas.before:
                Color:
                    rgba: 0, 1, 0, 1
                Rectangle:
                    size: self.size
                    pos: self.pos

            Label:
                text: "HELLO..."
            Label:
                text: "WORLD..."


    BoxLayout:
        size_hint: 1, 0.25

        canvas.before:
            Color:
                rgba: 0, 0, 1, 1
            Rectangle:
                size: self.size
                pos: self.pos

        Label:
            text: "FOOTER"

"""))

Output: Method 1 - No AnchorLayouts

Output: Method 1 - No <code>AnchorLayout</code>s

Method 2 - BoxLayout as root

main.py

from kivy.base import runTouchApp
from kivy.lang import Builder

runTouchApp(Builder.load_string("""

BoxLayout:
    orientation: 'vertical'

    AnchorLayout:
        size_hint: 1, 0.75
        anchor_x: 'left'
        anchor_y: 'top'

        GridLayout:
            size_hint: 0.2, 1

            canvas.before:
                Color:
                    rgba: 1, 0, 0, 1
                Rectangle:
                    size: self.size
                    pos: self.pos

            cols: 3
            row_force_default: True
            row_default_height: 40

            Button:
                text: "X"
            Button:
                text: "X"
            Button:
                text: "X"
            Button:
                text: "X"
            Button:
                text: "X"
            Button:
                text: "X"            

        AnchorLayout:
            anchor_x: 'right'
            anchor_y: 'top'

            BoxLayout:
                orientation: 'vertical'
                size_hint: 0.8, 1

                canvas.before:
                    Color:
                        rgba: 0, 1, 0, 1
                    Rectangle:
                        size: self.size
                        pos: self.pos

                Label:
                    text: "HELLO..."
                Label:
                    text: "WORLD..."


    AnchorLayout:
        size_hint: 1, 0.25
        anchor_x: 'left'
        anchor_y: 'bottom'

        canvas.before:
            Color:
                rgba: 0, 0, 1, 1
            Rectangle:
                size: self.size
                pos: self.pos

        Label:
            text: "FOOTER"

"""))

Output: Method 2 - BoxLayout as root

Output: Method 2 - <code>BoxLayout</code> as root

ikolim
  • 15,721
  • 2
  • 19
  • 29
  • Thanks a lot for this really exhaustive answer which helps a lot to understand how layouts work in Kivy. You're right, Anchor Layouts are in fact not needed to yield the targeted design. – SteeveL Jun 27 '19 at 18:16
0

Changing the Example class to extend FloatLayout instead of AnchorLayout allows more control of its children. With that change to Example, here is a kv that looks more like what you want:

<Example>:
    AnchorLayout:
        anchor_x: "center"
        anchor_y: "top"
        size_hint: (0.2, 0.75)
        pos_hint: {'x':0, 'top':1}

        GridLayout:
            cols: 3
            Button:
                text: "X"
            Button:
                text: "X"
            Button:
                text: "X"
            Button:
                text: "X"
            Button:
                text: "X"
            Button:
                text: "X"

    AnchorLayout:
        anchor_x: "center"
        anchor_y: "top"
        size_hint: (0.8, 0.75)
        pos_hint: {'right':1, 'top':1}

        BoxLayout:
            orientation: "vertical"
            Label:
                text: "HELLO..."
            Label:
                text: "WORLD..."

    AnchorLayout:
        anchor_x: "center"
        anchor_y: "bottom"
        size_hint: (1, 0.25)
        pos_hint: {'x':0, 'y':0}

        Label:
            text: "FOOTER"
John Anderson
  • 35,991
  • 4
  • 13
  • 36