kivyを使ってGUIプログラミング ~その6 レイアウトいろいろ~

#はじめに
[その4](https://qiita.com/kurodae/items/1bfeaf982d82943c1401)でボタンの説明をしましたが、レイアウトに関しても複数存在するためいろいろ紹介してみたいと思います。
前回と同様に簡単な説明と、例を示して行きます、詳しい説明は[リファレンス](https://pyky.github.io/kivy-doc-ja/gettingstarted/layouts.html)を見ていただけたらと思います。

#レイアウト
[リファレンス](https://pyky.github.io/kivy-doc-ja/gettingstarted/layouts.html)のレイアウト一覧にある順番で紹介していきます。


###[AnchorLayout](https://pyky.github.io/kivy-doc-ja/api-kivy.uix.anchorlayout.html#module-kivy.uix.anchorlayout)

kivy.uix.anchorlayout

配置するオブジェクトを画面の上、真ん中等簡単に配置が行えるレイアウトです。
配置場所の指定は、`anchor_x`、`anchor_y`という変数に対して
`anchor_x`なら`left`, `center`, `right`
`anchor_y`なら`top`, `center`, `bottom`の組み合わせ計9箇所から指定できます。
また、１つのAnchorLayoutに対して1つしかwidgetを追加できないので注意する必要があります。複数配置したい場合は、AnchorLayoutに別のレイアウトを追加すれば良いと思います。

``` python
import random

from kivy.app import App
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.button import Button


class Test(AnchorLayout):
    def __init__(self, **kwargs):
        super(Test, self).__init__(**kwargs)

        self.x_positon = ["left", "center", "right"]
        self.y_positon = ["top", "center", "bottom"]
        self.anchor_x = "center"
        self.anchor_y = "center"

        btn = Button(text='Hello World', size_hint=(0.5,0.5), on_press=self.click)
        self.add_widget(btn)

    def click(self,btn):
        x = random.choice(self.x_positon)
        y = random.choice(self.y_positon)
        self.anchor_x = x
        self.anchor_y = y
        btn.text = "x : {}\ny : {}".format(x, y)


class Sample(App):
    def build(self):
        return Test()


if __name__ == '__main__':
    Sample().run()
```

![sample1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/421817/05d7ec47-13c0-3836-41de-564ac55ad6e9.gif)

###[BoxLayout](https://pyky.github.io/kivy-doc-ja/api-kivy.uix.boxlayout.html#module-kivy.uix.boxlayout)

kivy.uix.boxlayout

ウィジェットを水平方向か垂直方向に並べるように配置するレイアウトです。
デフォルトでは、水平方向にウィジェットが追加されていきます。方向を変更するには、```orientation ```という変数に垂直方向にしたいなら```vertical```、水平方向に配置したいなら```horizontal ```を代入することで向きを変えることができます。途中でウィジェットの追加向きを変えるということはできないと思うので、新しいBoxLayoutをadd_wigetして配置を変える感じになるかと思います。


``` python
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button


class Test(BoxLayout):
    def __init__(self, **kwargs):
        super(Test, self).__init__(**kwargs)

        self.count = 0
        #デフォルトは"horizontal"水平方向に配置されます。
        self.orientation = "horizontal"
        #self.orientation = "vertical"

        btn = Button(text='Hello World', on_press=self.click)
        self.add_widget(btn)

    def click(self,btn):
        self.count += 1
        self.add_widget(Button(text="{}".format(self.count),on_press=self.dismiss))

    def dismiss(self, a):
        self.remove_widget(a)


class Sample(App):
    def build(self):
        return Test()


if __name__ == '__main__':
    Sample().run()
```

![sample2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/421817/d14589c1-dd31-1366-0582-79a9cae2ed45.gif)

###[FloatLayout](https://pyky.github.io/kivy-doc-ja/api-kivy.uix.floatlayout.html#module-kivy.uix.floatlayout)

kivy.uix.floatlayout

FloatLayoutは上で紹介したようなレイアウトとは異なり、絶対位置を指定して配置することができます。
絶対位置であるため、widget配置後にウィンドウの大きさを変えたりしてもオブジェクトはウィンドウに合わせて位置が変化することはないため注意する必要があります。

```python
import random

from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button

class Test(FloatLayout):
    def __init__(self, **kwargs):
        super(Test, self).__init__(**kwargs)

        btn = Button(text='Hello World', size_hint=(0.1,0.1), on_press=self.click)
        self.add_widget(btn)

    def click(self,btn):
        x = int(random.uniform(0,self.width))
        y = int(random.uniform(0,self.height))
        self.add_widget(Button(text="x : {}\ny : {}".format(x, y), pos=(x,y), size_hint=(0.1,0.1)))


class Sample(App):
    def build(self):
        return Test()

if __name__ == '__main__':
    Sample().run()
```

![sample3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/421817/6b7d573d-db20-dad4-4bc3-fb45a36eda00.gif)


###[RelativeLayout](https://pyky.github.io/kivy-doc-ja/api-kivy.uix.relativelayout.html#module-kivy.uix.relativelayout)

kivy.uix.relativelayout

使い方がイマイチわかりませんでした。
わかり次第記事を更新したいと思います。


###[GridLayout](https://pyky.github.io/kivy-doc-ja/api-kivy.uix.gridlayout.html#module-kivy.uix.gridlayout)

kivy.uix.gridlayout

GridLayoutはグリッドとあるように表計算みたいな形でウィジェットを追加していく配置になります。
配置は```cols```と```rows```から指定することができます。```cols```に数値を代入すると、その数値分だけ横に配置が終わるとその下に新しい段を作りさらに追加していきます。```rows```は縦方向の最大値を指定して、横方向にウィジェットを追加していきますが、イマイチ挙動がよくわかりませんでした。同時に```cols```と```rows```を用いると、cols×rowsのグリッドを作成することができます。

```python
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button


class Test(GridLayout):
    def __init__(self, **kwargs):
        super(Test, self).__init__(**kwargs)
        self.count = 0
        btn = Button(text='Hello World', on_press=self.click)
        self.cols = 5
        #self.rows = 5

        self.add_widget(btn)

    def click(self,btn):
        self.count += 1
        self.add_widget(Button(text="{}".format(self.count)))


class Sample(App):
    def build(self):
        return Test()


if __name__ == '__main__':
    Sample().run()
```

![sample4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/421817/1fce8efa-6133-621b-8328-ed1c1c76dde2.gif)

###[PageLayout](https://pyky.github.io/kivy-doc-ja/api-kivy.uix.pagelayout.html#module-kivy.uix.pagelayout)

kivy.uix.pagelayout

PageLayoutは、画面に別の画面を配置できるようなレイアウトになっており、簡単な画面遷移のようなことができると思います。画面端の線(見辛いですが,,)をクリックしながら横にドラッグすると別の画面が出てきます(ちょっと操作しづらいですw)。例ではボタンをそのまま貼り付けていますが、本来はPageLayoutに別のレイアウトをadd_widgetをするような使い方になると思います。

```python
from kivy.app import App
from kivy.uix.pagelayout import PageLayout
from kivy.uix.button import Button


class Test(PageLayout):
    def __init__(self, **kwargs):
        super(Test, self).__init__(**kwargs)
        btn1 = Button(text='Hello World1', size_hint=(0.5, 0.5))
        self.add_widget(btn1)

        btn2 = Button(text='Hello World2', size_hint=(0.5, 0.5))
        self.add_widget(btn2)

        btn3 = Button(text='Hello World3', size_hint=(0.5, 0.5))
        self.add_widget(btn3)


class Sample(App):
    def build(self):
        return Test()


if __name__ == '__main__':
    Sample().run()
```

![sample5.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/421817/914d3784-76dc-6a84-631d-d80ed9c0f083.gif)


###[ScatterLayout](https://pyky.github.io/kivy-doc-ja/api-kivy.uix.scatterlayout.html#module-kivy.uix.scatterlayout)

kivy.uix.scatterlayout

ScatterLayoutは、マウスで位置を変えたり、大きさを変えることができたりするレイアウトです。例では、ラベルを2つ貼ったBoxLayoutをScatterLayout上で動かしてみています(ラベルだけだと見辛かったので破線を追加しています)。本来なら画像アプリなどで画面を拡大したりとかそういった使い方をすると思います。パソコンよりスマホアプリような気がします。

```python
from kivy.app import App
from kivy.uix.scatterlayout import ScatterLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.config import Config
#破線を表示する
Config.set('modules', 'ShowBorder', '')


class Test(ScatterLayout):
    def __init__(self, **kwargs):
        super(Test, self).__init__(**kwargs)

        layout = BoxLayout()

        label = Label(text="Hello World!")
        layout.add_widget(label)

        label2 = Label(text="Hello World!")
        layout.add_widget(label2)

        self.add_widget(layout)


class Sample(App):
    def build(self):
        return Test()


if __name__ == '__main__':
    Sample().run()
```

![sample6.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/421817/54f2a37a-56bc-b3fa-998e-8c71872f13d4.gif)


###[StackLayout](https://pyky.github.io/kivy-doc-ja/api-kivy.uix.stacklayout.html#module-kivy.uix.stacklayout)

kivy.uix.stacklayout

StackLayoutは、BoxLayoutと同じように配置する方向を指定するようなレイアウトになっています。
BoxLayoutと違いは、並べる向きを8つのパラメータから指定できることと、画面外に出そうになると、
次の段や横などに配置を変更する点です。並べる方向ですが、```orientation```という変数から指定することができ、```lr```や```tb```というパラメータを組み合わせたもので向きを指定します。例で書いてある```lr-tb```ですが```lr```は左(left)から右(right)、```tb```は上(Top)から下(Bottom)であり、左から右方向に配置し、画面端にいったら上から下にウィジェットを追加するとなります。

```python
from kivy.app import App
from kivy.uix.stacklayout import StackLayout
from kivy.uix.button import Button


class Test(StackLayout):
    def __init__(self, **kwargs):
        super(Test, self).__init__(**kwargs)

        ori = ["lr-tb","tb-lr","rl-tb","tb-rl","lr-bt","bt-lr","rl-bt","bt-rl"]

        # デフォルトでは右方向、上から下方向に進みます。
        self.orientation="lr-tb"

        for i in range(100):
            btn = Button(text=str(i), width=40 + i * 5, size_hint=(None, 0.15))
            self.add_widget(btn)


class Sample(App):
    def build(self):
        return Test()


if __name__ == '__main__':
    Sample().run()
```

　```lr-tb```を指定すると左の画像、```bt-rl```を指定すると右の画像のようになります。
![画像.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/421817/081f520a-f8e6-f8af-89eb-16a789c03117.png)

#まとめ
普段はboxlayoutを使うことが多いため、その他のレイアウトについてほぼ知識がない状態でしたので良い機会となりました。結局調べたもののrelativelayoutについてはイマイチ使い方がわからなかったのでもう一度調べてみたいと思いました。

#参考サイト

https://pyky.github.io/kivy-doc-ja/gettingstarted/layouts.html