Pythonで作るGUIアプリ with kivy 基礎編

# はじめに
本記事は、PythonのGUI作成ライブラリであるkivyの使い方について解説する記事です。

よろしければ、以前の記事もご参照ください。

[Pythonで作るGUIアプリ with kivy 導入編](https://qiita.com/phorizon20/items/ff352ef1ad15b62ff266)
[Pythonで作るGUIアプリ with kivy 環境構築編](https://qiita.com/phorizon20/items/3fe094186d44d620b661)


# kivyアプリの基本構成
これからkivyを使いこなして最高にCOOLなGUIアプリを作っていく訳ですが、まず初めに、kivyアプリの基本的な構成要素を説明します。

前回の[はじめてのkivyアプリ](https://qiita.com/phorizon20/items/3fe094186d44d620b661#%E3%81%AF%E3%81%98%E3%82%81%E3%81%A6%E3%81%AEkivy%E3%82%A2%E3%83%97%E3%83%AA)では、下記のようなコードを用いました。

```py
# coding:utf-8

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

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

        btn = Button(text="hello")
        self.add_widget(btn)

class MainApp(App):
    def build(self):
        MS = MainScreen()
        return MS

if __name__=="__main__":
    MainApp().run()
```

こちらを起動してみると、このような画面が表示されます。

![001_first_app.png](https://qiita-image-store.s3.amazonaws.com/0/216607/f875eac1-c52e-b742-4c38-2d347bc4024f.png)



ある意味、これがkivyアプリにおける基本にして奥義と言いますか、原点にして頂点と言いますか、全てのkivyアプリの原型となるものです。

ということで、この原型を少し詳しく見てみましょう。

このコードには、現在２つのクラスが存在します。下から順に、

```py
class MainApp(App):
    def build(self):
        MS = MainScreen()
        return MS
```

と、

```py
class MainScreen(BoxLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        btn = Button(text="hello")
        self.add_widget(btn)
```

です。

これらは、それぞれ、

1. MainApp = アプリを構成するクラス
2. MainScreen = 画面上の見た目や機能を構成するクラス

となります。

## アプリを構成するクラス
`アプリを構成するクラス`とは、アプリが立ち上がり、終了するまでの間、そのプロセスを管理するクラスです。

例として、「アプリが立ち上がったらコンソール上に"App Start!!"と表示したい」、「アプリが終了する際にコンソール上に"App End!!"と表示したい」といった要望が出てきたときは、その挙動はこのAppクラスに記述します。

```py
class MainApp(App):
    def on_start(self):
        print("App Start!!")

    def build(self):
        MS = MainScreen()
        return MS

    def on_stop(self):
        print("App End!!")
```

といった具合です。

アプリの起動や終了以外、つまり、ユーザーがアプリを使っている間にどんな画面を表示し、どんな操作や入力を受け付け、どんな結果を画面に返すか、といった処理は、次の`MainScreen`の役割となります。Appクラスの役割としては、`def build(self):`にて、`MainScreen`をインスタンス化し、それを主画面として保持し始めた時点で、その役目の殆どを終えます。

## 画面上の見た目や機能を構成するクラス
つまり、これから作っていく最高にCOOLなアプリがどうCOOLなのかを決めるのは、この`MainScreen`およびそこに付随する画面にどんな機能を持たせるかによって決まります。なので、もう少し詳しく説明していきます。

kivyで作るGUI画面を構成する要素は、基本的に、下記のような構成になっています。

### Widget
- レイアウト 系
  - BoxLayout
  - GridLayout
  - FloatLayout
- 部品 系
  - ラベル
  - ボタン
  - テキストインプット（入力欄）

### Event
- マウスイベント（もしくはタッチイベント）
  - クリックされたとき
  - ダブルクリックされたとき
  - ドラッグされたとき
- プロパティイベント
  - <何か>のサイズが変更されたとき
  - <何か>の位置が変更されたとき
  - <何か>の値が変更されたとき

もしWEBの開発になじみのある方であれば、WEBページを構成する要素としての静的な画面を構成するHTML/CSSと、画面に動きを与えるJavaScriptが、それぞれWidgetとEventだと考えると、少し解り易いかもしれません。

kivyアプリの基本構成をさらっと確認したうえで、次のセクションにて、画面の**組み立て方**について（widgetの使い方・配置の仕方について）詳しく見て行きます。


# はじめてのkivyアプリに毛を生やす
WEB開発において、いきなりJavaScriptから書き始める人は殆ど居ないでしょう。同じように、画面に動きを与えるEvent関連の処理は一旦おいておき、まず始めに、Widgetを駆使して最初の画面を構築していきたいと思います。

前述した通り、Widgetには`レイアウトを管理するためのWidget`と`単体の部品として使うWidget`と、大きく分けて２種類あります。そして、それらWidgetを入れ子にして、画面を構築していきます。ここもWEBの構造とある意味似ていますね。

まずレイアウト系についてですが、kivyでは始めから様々なレイアウト系Widgetが用意されています。

[Layout](https://pyky.github.io/kivy-doc-ja/api-kivy.uix.layout.html#kivy.uix.layout.Layout)

- AnchorLayout
- BoxLayout
- FloatLayout
- GridLayout
- PageLayout
- RelativeLayout
- ScatterLayout
- StackLayout

kivy==1.0.0の時点では上記の８種類が用意されていますが、**ぶっちゃけ`BoxLayout`と`FloatLayout`の２つだけ、いや、まずは`BoxLayout`の１つだけ覚えて、その他すべてを忘れて貰ってもひとまず大丈夫です！**　もう一度言います。**`BoxLayout`だけでも、とてもCOOLなアプリが作れます！**

後程、その様子を確認していきます。

一方、部品系Widgetについては、残念ながら、欲しい部品を逐次調べていく必要があります。ありますが、まぁとりあえず始めは、ボタンとラベルだけで、なんかそれっぽい！かっちょよくなりそう！みたいなモノを目指して、とりあえず動くのモノを作ってみましょう。


## BoxLayoutを知るために、部品を追加してみる
たったひとつだけ覚えけば良い`BoxLayout`について、実際の挙動を確認しながら見てみます。

まず、奥義にして頂点である`はじめてのkivyアプリ`の、`MainScreen`の部分を見返してみると、

```py
class MainScreen(BoxLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        btn = Button(text="hello")
        self.add_widget(btn)
```

この１行目の部分で、この`MainScreen`は`BoxLayout`を継承しています。これにより、`MainScreen`は、`BoxLayout`の性質を受け継いだ新しいkivyのWidgetとして定義されました。

次に、５行目と6行目にて

```py
        btn = Button(text="hello")
        self.add_widget(btn)
```

`Button`というkivyの部品がインスタンス化され、`self`、すなわち`MainScreen`、すなわち`BoxLayout`の性質を受け継いだkivyのWidgetに、`add_widget`、つまり追加された、ということになります。

ここに、さらにもう一つ`Button`を追加することで、`BoxLayout`の性質というものを確認してみましょう。

```py
class MainScreen(BoxLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        btn = Button(text="hello")
        self.add_widget(btn)

        btn2 = Button(text="everyone")
        self.add_widget(btn2)
```

8,9行目を付け加えたうえで、アプリを起動してみると、

![002_2btn.png](https://qiita-image-store.s3.amazonaws.com/0/216607/23b5e67d-178f-81c6-b5d9-3ecffa1f9aef.png)

このように、ボタンが２つ、横方向に並んで配置（レイアウト）されました。

さて、さらに調子に乗って、もう４つ追加してみると、

```py
class MainScreen(BoxLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        btn = Button(text="hello")
        self.add_widget(btn)

        btn2 = Button(text="everyone")
        self.add_widget(btn2)

        btn3 = Button(text="how")
        self.add_widget(btn3)

        btn4 = Button(text="are")
        self.add_widget(btn4)

        btn5 = Button(text="you")
        self.add_widget(btn5)

        btn6 = Button(text="today?")
        self.add_widget(btn6)
```

![003_6btn.png](https://qiita-image-store.s3.amazonaws.com/0/216607/eac9523f-f90c-4e21-8fa9-5ef497d82bc9.png)

このようになりました。

勘のいい方はもうお解りかと思いますが、`BoxLayout`の性質とは、`BoxLayout`に追加されたすべてのWidgetを、横方向に並べて配置する、というものです。加えて、アプリの画面サイズを変更すると、ボタンのサイズも同時に、常に6等分になるように、変更されることが確認できるかと思います。これが、いわゆる`BoxLayout`の性質です。

当然、部品をただ横方向に並べるだけでCOOLなアプリは作るのは大変難しいですが、勘のいい方はもうお解りの通り、縦方向にする事ももちろん可能です。試してみましょう。


## レイアウトをいじってみる
この`BoxLayout`に、横方向ではなく縦方向に並べてほしい場合、方法はすごく簡単で、`BoxLayout`の`orientation`のプロパティ設定を変更してあげる事で、それが可能になります。

```py
class MainScreen(BoxLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        self.orientation = "vertical"

        btn = Button(text="hello")
        self.add_widget(btn)

        btn2 = Button(text="everyone")
        self.add_widget(btn2)

        btn3 = Button(text="how")
        self.add_widget(btn3)

        btn4 = Button(text="are")
        self.add_widget(btn4)

        btn5 = Button(text="you")
        self.add_widget(btn5)

        btn6 = Button(text="today?")
        self.add_widget(btn6)
```

![004_vertical.png](https://qiita-image-store.s3.amazonaws.com/0/216607/11279389-4152-5d24-27ce-de19df2fcb50.png)

５行目にて`MainScreen`のプロパティを上書き（デフォルトでは"horizontal"）した結果、無事ボタンが縦方向に並びましたね。



このように、`orientation`以外にも、kivyのWidgetには様々なメソッドやプロパティが存在します。これらは公式ドキュメントで確認する事が出来ます。

[BoxLayout](https://kivy.org/doc/stable/api-kivy.uix.boxlayout.html)

もちろんkivyに限った話ではありませんが、kivyは特に、日本人のユーザーがあまり多くない様で、技術ブログもそこまで多くありませんので、早い段階で公式ドキュメントを読み解くのに慣れておくと、後々の開発にとてもプラスに働くこと間違いないので、大変おススメです。

さて、次はもう一歩踏み込んで、`はじめてのkivyアプリ`にもう2,3本の毛をはやしてあげましょう。

## レイアウトを入れ子にしてみる
世の中にあるCOOLなアプリのほとんどは、単一の横方向もしくは縦方向に並んだボタンやラベルやテキストインプットだけで構成されている事はなく、それらが複雑な形で入れ子になっています。そして当然、最高にCOOLなライブラリであるkivyでも、それらを簡単に構築する事が可能です。

少し例を見てみます。といっても、勘のいい方はもうお解りかと思いますが、Widgetの代わりに、BoxLayoutを追加してあげるという、ただそれだけです。

```py
class MainScreen(BoxLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        btn = Button(text="hello")
        self.add_widget(btn)

        btn2 = Button(text="everyone")
        self.add_widget(btn2)

        # MainScreenに追加する、BoxLayoutというWidgetを用意
        bl = BoxLayout()
        bl.orientation = "vertical"

        # blに追加する３つのボタンを用意
        btn3 = Button(text="how")
        btn4 = Button(text="are")
        btn5 = Button(text="you")

        # blにボタンを追加
        bl.add_widget(btn3)
        bl.add_widget(btn4)
        bl.add_widget(btn5)

        # MainScreenにblを追加
        self.add_widget(bl)

        btn6 = Button(text="today?")
        self.add_widget(btn6)
```

![005_bl_in_bl.png](https://qiita-image-store.s3.amazonaws.com/0/216607/144d3311-3a5b-a223-d6f8-36944c93cf69.png)

このようにして、`BoxLayout`の中に`BoxLayout`を入れ子にして追加し、その子`BoxLayout`にボタンを３つ追加した、というわけです。とても簡単ですね。

このときも、`how`と`are`と`you`の３つのボタンは、縦方向に３等分したサイズになっている事もポイントです。




以上が、kivyを使ってアプリを開発していく、基礎的な部分です。

以後はこららを魔改造して最高にCOOLなアプリを作っていくために、kivyに備わっている**kivy語**という機構について解説し、その次に、アプリを作っていく上での手順というか考え方というかを、説明していきたいと思います。

<br>

今回はひとまずここまでです。
ありがとうございました。