SteeveL
SteeveL

Reputation: 11

Kivy - How to Size Embedded Anchor Layouts?

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

design

It is made of 3 parts :

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!

Upvotes: 0

Views: 2367

Answers (2)

ikolim
ikolim

Reputation: 16031

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

Upvotes: 2

John Anderson
John Anderson

Reputation: 39012

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"

Upvotes: 0

Related Questions