kivyMD開発其の壱 初期公開説明篇

正月気分がようやく薄れ、またいつもの毎日が戻ってまいりました。(強制)

今年もよろしくお願いしまーす！(いろんな方が見てると思うので簡素に)

はい、ということで新年もKivyMDのお時間がやってきました！お正月気分は
まだ抜けてない人が多いでしょうかね。投稿者も全然抜けてはいません:joy::joy::joy:

というわけで、寒い中なんかお仕事も始まっていますが、(あと体重が増えたりも...)
なんかやる気でなーとなった方はこちらの記事でも読んでお正月気分を抜いてもら
えれば、この上なく幸いでございます。(おそらく抜けない)

強引に今日のお題に入っていきますが、まずは去年の年末にどんなことをやって
いたかと言うと、ギリギリ滑りこみセーフで1stAppのリリースを告知していま
した。なんそれ?そんなの知らないよという方は以下の記事を見てもらえればと
思います。

https://qiita.com/virty/items/3d03e5e2c8ec35a9117d

まぁ、全然大したことないTODOアプリでしかも完成はしていないんですけどね。。

今回はこちらのアプリの続編で、前回解説をしていなかったのでその解説をして
みたいと思います。1回分で説明できればと思いますが、体力がなかった場合は
その限りではないので、そこあたりはご了承頂ければと思います。

というわけで、ここを長くしてもしょうがないのでさっそく説明に入っていきます。

## 動き

コードだけ見ても、動きを見ておかないとなんだか分からんとなると思うので、
前回を一部だけ振り返っておきます。

![todoapp.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82826/3554bdbf-dfda-faa6-7c41-f18a4e27dc1a.gif)

どんなアプリなのよ、と思われる方は上のキャプチャを見てもらえればなんとなく
雰囲気は伝わるかと思われます。

## 説明

ここからは、コードの方を説明していきます。コードについてはこれも前回告知済
ですが、知らない方も多くいられると思うので再掲しておきます。以下のリポジトリ
にプッシュ済みで前回あげたときから改変はしておりません。

https://github.com/Quiet396/TodoApp

### KV

普段はマニュアルから構成をガラリと変えていないので、KV言語を分けることは全然
ないのですが、今回に至ってはKVファイルとpyファイルとを分けることにしています。

:::note
分けるに至っては、KVファイルとクラス名(pyファイル名しかり)を同一にすることが
必要なので、今回は名前をmainという風に統一しています。ちゃんと公開するときは
この形式が良さそうな気がしています。
※この辺りはKivyのことなのでちゃんと知りたい方は公式マニュアルもしくは以下の
  黄本(と呼ぶのか?)を参照ください
:::

https://honto.jp/netstore/pd-book_29090994.html

※当然ではあるがアフィリエイトではない

ということで、寄り道が過ぎていますがこれからはKV側の説明に入っていきます。
まずはこちらでもコードの方を掲載しておきます。

```python
MDBoxLayout:
    orientation: "vertical"

    MDToolbar:
        title: "TODO APPLICATION"
        #right_action_items: [["file-document", lambda x: app.setting_task_info_form()]]

    MDTabs:
        on_tab_switch: app.on_tab_switch(*args)
        
        Tab:
            text: "Create"
            orientation: "vertical"
            padding: "10dp"

            MDLabel:
                text: "TaskName"
                pos_hint: {"center_x": .5}
                                
            MDTextField:
                id: taskname
                text: ''
                required: True
                pos_hint: {"center_x": .5}
                helper_text_mode: "on_error"
                halign: "center"
                    
            MDLabel:
                text: "Description"
                pos_hint: {"center_x": .5}

            MDTextField:
                id: description
                text: ''
                pos_hint: {"center_x": .5}
                halign: "center"
            
            MDRaisedButton:
                id: button
                text: "SEND"
                pos_hint: {"center_x": .5}
                halign: "center"
                on_release: app.send()
            
        Tab:
            text: "Todo"
            ScrollView:

                MDList:
                    id: todo
                    text: "todo"

        Tab:
            text: "Doing"
            ScrollView:

                MDList:
                    id: doing
                    text: "doing"

        Tab:
            text: "Done"
            ScrollView:

                MDList:
                    id: done
                    text: "done"
                    
<Task>

    text: root.text
    secondary_text: root.secondary_text
    tertiary_text: root.tertiary_text
    
    IconLeftWidget:
        icon: "file-document-outline"
        on_release: app.change_task_status(root)

    IconRightWidget:
        icon: "delete"
        on_release: app.remove_widget(root)

<DoneTask>

    text: root.text
    secondary_text: root.secondary_text
    tertiary_text: root.tertiary_text

    IconRightWidget:
        icon: "delete"
        on_release: app.remove_widget(root)
```

長くつらつらと書いていますが、構成は大まかに分けてこのようになっています。

```yaml:KVの構成
MDBoxLayout(Root):
  - MDToolbar
  - MDTabs:
    - Tab × 4

<Task>:
  - IconLeftWidget
  - IconRightWidget

<DoneTask>:
  - IconRightWidget
```

なんでyaml形式なのかということはするどい視点だと思います。(いきなり何)
理由は単純で、KVの構成を描きやすいことと、単に私が好きなだけですw

これにもとづいて説明していくと、まずルートウィジェットにMDBoxLayoutを
指定しています。んで、その中には毎度おなじみMDToolbar、さらにはMDTabs
を入れ込んでいます。MDTabsにはTabが4つ配置しています。

そしてカスタムウィジェットにTask、DoneTaskウィジェットがあります。これは
Icon(Left|Right)Widgetから察せられるとお目が高いです。MDListをまるまる
使っていますね。

おおまかに言うとこんな感じです。

#### MDBoxLayout(Root)

ここからは、パッと見て何してんだこれ?というところや補足として過去投稿記事の
リンクを載せていくために、ウィジェットごとに説明を繰り広げていきます。

まずは最初のあたりから。コードを再掲しておきます。

```python
MDBoxLayout:
    orientation: "vertical"

    MDToolbar:
        title: "TODO APPLICATION"
        #right_action_items: [["file-document", lambda x: app.setting_task_info_form()]]
```

最初のところあたりは特に言うことでもないかもですが、コメントアウトしたところ
は何をやっているか分からん状態になると思うので、少し補足をしておきます。これ
はというと、最初は異なるウィジェットを考えていました。入力項目はタブにしないで
ダイアログへと。初期構想は以下のようでした。

![hope.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82826/6b535ad8-209d-1618-b94c-87f7db6b44f1.png)

ですが、カスタムウィジェットが持っているタスク名や説明欄の内容がルートウィジェ
ットに保持されなく、タブがうまく作れないという現象に陥っていました。いや、それ
すら分からんわという方はニュアンスで受け取ってもらえればと思います。

ということがあったので、仕方なく入力項目をタブで作るということをしなければなら
なかったということもありました。。

このへんに関しては以下リンクもしくは該当公式マニュアルを見てもらえればと思います。

https://qiita.com/virty/items/d5fa0a529912e6b0beb0

https://qiita.com/virty/items/3c726e2a7faa694fb54d

さらに続きます。続きからのコードを再掲しておきます。

```python
    MDTabs:
        on_tab_switch: app.on_tab_switch(*args)
        
        Tab:
            text: "Create"
            orientation: "vertical"
            padding: "10dp"

            MDLabel:
                text: "TaskName"
                pos_hint: {"center_x": .5}

(略)

        Tab:
            text: "Done"
            ScrollView:

                MDList:
                    id: done
                    text: "done"
```

だいぶ端折ってる気はしますが、お気に留めなく。

まずは、on_tab_switchプロパティですが、これはタブをスイッチするときは
必要になるみたいです。マニュアルそんなこと書いてたっけな...となりましたが、
このバージョン(v0.104.2)ではこの仕様となっています。

そして次からは実際のタブが配置していますが、左から順にCreate -> Todo -> 
Doing -> Doneとなっています。Createで作ったあとはTodoでタスクが作られ、
ステータスを変更するときはDoing -> Doneと1方向になっています。これもどう
なのかというご指摘はその通りかと思います。。時間オーバーでした。。

Createタブ自体はそれほど複雑ではなく、ラベルとテキストフィールド、ボタンが
あるだけになります。ここも以下のリンクもしくは該当マニュアルを見てもらえれば
それほど難しくはないかと思われます。

https://qiita.com/virty/items/8475f11f314b76af21e1

https://qiita.com/virty/items/338d3c97c7fdd5fb1dda

https://qiita.com/virty/items/29d792d5ecf4ad0f86be

Createタブではorientationプロパティを指定していますが、これがないと面白い
レイアウトになるので興味のある方は試してもらうとですね。再度試したところ、pad-
dingプロパティはそれほどというか全然変わらんくて意味のないプロパティとなって
います。。\# なんで置いておいた

後のタブは共通していて、単にMDListらを配置していることになります。いつぞやの
投稿でMDListパターン!と馬鹿みたいにはしゃいでたのがまさにこれですね。

この辺りについては以下のリンクもしくは該当マニュアルをご覧ください。

https://qiita.com/virty/items/3871b85bc67179d67b30

ここまで見ると、最初の表示画面があぁなるほどねとなってくれるのを祈るばかりに
なります。

![init.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82826/a66943dd-c412-aea5-9d0c-48454122e29d.png)

#### Task&DoneTask

これらは実はほとんど同じようなレイアウト&振る舞いをしています。というかもともと
同じものであったのですが、かくかくしかじか(投稿って便利)な理由で分けました。理由
については、pyファイルの方で説明するかもしれませんし、しないかもしれません。

ほとんど同じようなものなので、Taskウィジェットに絞ってコードを再掲しておきます。
見比べてもらうとわかり良いですが、DoneTaskウィジェットはIconLeftWidgetがない
だけになります。

```python
<Task>

    text: root.text
    secondary_text: root.secondary_text
    tertiary_text: root.tertiary_text
    
    IconLeftWidget:
        icon: "file-document-outline"
        on_release: app.change_task_status(root)

    IconRightWidget:
        icon: "delete"
        on_release: app.remove_widget(root)
```

で、Taskウィジェットについてですが、こちらは伝えた通りほぼほぼというかまんま
リストウィジェットになります。プロパティとしては3つの*textを持ち、それぞれ
必要な入力項目を入れるためにあります。そうでもないものもあるけど。

そしてリストの左に配置するアイコンとして、タスクのステータスを変更するもの。右に配置
するものとして、リストそのものを消去するためにあるアイコンがあります。コールバックメソ
ッド自体がなんなのかは来週お伝えしようと思います。(急なネタバレ)

ちゃんと作れると以下のようにリストが出来上がるようになります。

## まとめ

はい、ということで新年早々の投稿はいかがだったでしょうか。
個人的にはスムーズな出だしになったかと思われます(自意識過剰)。

すみません、力尽きました。。なので、実際に処理をおこなうところに関しては来週説明して
いきたいと思います。ではまたお会いしましょう〜。

それでは、ごきげんよう。

## 参照

> KivyMD
> https://kivymd.readthedocs.io/en/latest/

> 時候の挨拶　1月（睦月：むつき）
> https://www.midori-japan.co.jp/letter/letter-manners/jikouaisatsu/4306