kivyMDチュートリアル其の什伍 Components - Button篇

みなさん、GW期間中はいかがお過ごしでしょうか。
私はとくにやることありませーん！w だからと言って暇だからqiita書いているわけではなく...
うそです、すみません。暇だから書いています。。お仕事を...下さい...
\# わりとガチな要望だったりして

なので、みなさんもGW中に学んで「コピペで1千万エンジニア」を目指しましょう。
\# 駆け出しエンジニアと繋がりたいとか言ってみたりして

という冗談はさておき、KivyMDに入っていきましょう。今日はGW特別企画第2弾ということで、
前回の宣言通りButton篇になります。

## Button

いつものようにMaterialDesignのリンクは飛ばすようにします。ただし、中に書かれてある
ものは結構有益というかそれは当たり前なのですが、原則や注意点などが色々と書かれてあり
ます。ひととおり、目を通すことをおすすめします。

少しこのお題は、自身にとって結構重みが深い内容だなぁと思っています。\# 急にどうした
なので、週末に取り掛かるには少し時間が足りないなぁと思ってGW企画にしました。たかがボタン、
されどボタンというわけで、ボタンのことを触れ込んでいくと1ヶ月ほど掛かりそうな気がします。
人を移動させるエレベーターに使われたりするボタン、核実験の際にも使われたりするボタンなど
用途・場所・時代に応じて色々変化したりします。丸みを帯びたり、角ばった形をしたりと形も様々
となります。

ということで長くなりそうなので、ボタンの詳細はこの辺にしておくことにします。ボタンの構造学
みたいな本があったら、買ってみようかな。まぁ、一旦置いておいてKivyMDに続きます。
\# ただのボタンフェチだったりして

マニュアルの説明からは、ボタンの概要として以下のように書いてあります。

> Buttons allow users to take actions, and make choices, with a single tap.

疑う余地もありません。

で、続きましてKivyMD側のボタンは以下の12種類用意してあるよ、と説明があります。

* MDIconButton
* MDFloatingActionButton
* MDFlatButton
* MDRaisedButton
* MDRectangleFlatButton
* MDRectangleFlatIconButton
* MDRoundFlatButton
* MDRoundFlatIconButton
* MDFillRoundFlatButton
* MDFillRoundFlatIconButton
* MDTextButton
* MDFloatingActionButtonSpeedDial

先にあれこれマニュアルから触れ込んでもよいのですが、サンプルコードを先に貼り付けておきます。
今日のサンプルコードは、下部あたりにある[See full example]のリンク先にあったサンプルコード
からの抜粋です。少しこちらは長かったので、カスタマイズされたものをすべて除外したりMDFloating-
-ActionButtonSpeedDialを組み合わせていたりします。オリジナリティは0にほぼ近い内容となります。

```python:xv/buttons.py
from kivy.lang import Builder
from kivy.factory import Factory
from kivymd.app import MDApp

Builder.load_string(
    """
<ExampleButtons@Screen>:

    MDToolbar:
        title: app.title
        elevation: 10
        pos_hint: {'top': 1}

    BoxLayout:
        padding: dp(10)
        size_hint: None, None
        size: self.minimum_size
        spacing: dp(10)
        orientation: "vertical"
        pos_hint: {"center_x": .5}

        MDIconButton:
            icon: "sd"
            pos_hint: {"center_x": .5}

        MDFloatingActionButton:
            icon: "plus"
            opposite_colors: True
            elevation_normal: 8
            pos_hint: {"center_x": .5}

        MDFlatButton:
            text: "MDFlatButton"
            pos_hint: {"center_x": .5}

        MDRaisedButton:
            text: "MDRaisedButton"
            elevation_normal: 2
            opposite_colors: True
            pos_hint: {"center_x": .5}

        MDRectangleFlatButton:
            text: "MDRectangleFlatButton"
            pos_hint: {"center_x": .5}

        MDRectangleFlatIconButton:
            text: "MDRectangleFlatIconButton"
            icon: "language-python"
            width: dp(230)
            pos_hint: {"center_x": .5}

        MDRoundFlatButton:
            text: "MDRoundFlatButton"
            pos_hint: {"center_x": .5}

        MDRoundFlatIconButton:
            text: "MDRoundFlatIconButton"
            icon: "language-python"
            width: dp(200)
            pos_hint: {"center_x": .5}

        MDFillRoundFlatButton:
            text: "MDFillRoundFlatButton"
            pos_hint: {"center_x": .5}

        MDFillRoundFlatIconButton:
            text: "MDFillRoundFlatIconButton"
            icon: "language-python"
            pos_hint: {"center_x": .5}

        MDTextButton:
            text: "MDTextButton"
            pos_hint: {"center_x": .5}
    
    MDFloatingActionButtonSpeedDial:
        data: app.data
        root_button_anim: True
"""
)


class MainApp(MDApp):

    def __init__(self, **kwargs):
        self.title = "KivyMD Examples - Buttons"
        self.data = {
            'language-python': 'Python',
            'language-php': 'PHP',
            'language-cpp': 'C++',
        }
        super().__init__(**kwargs)

    def build(self):
        self.root = Factory.ExampleButtons()


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

コードからは以上となります。ここからはマニュアルと比べ合わせながら進んでいきます。

### kv側

いや、いきなりマニュアル入らねーのかい！みたいなツッコミがされてそうですが、ちょうど
前回のおさらいがてらkvの最初っから入っていこうではありませんか。
\# 謎の提案

#### レイアウト

```python
<ExampleButtons@Screen>:

(略)

    BoxLayout:
        padding: dp(10)
        size_hint: None, None
        size: self.minimum_size
        spacing: dp(10)
        orientation: "vertical"
        pos_hint: {"center_x": .5}
```

レイアウトになります。とりあえず、まだMDToolbarは触れ込んでいないので対象外として
省略しています。あれ、リンク先ではExampleButtonsってBoxLayoutを継承してなかった
っけって言う方はするどいです。というかリサーチ力がえぐいです。

これも別に継承させなくてもいいや、えいって継承をなくそうとしたのですが、Factoryでの
インスタンス化の制限に引っかかってしまいました。。どうやらFactoryでのインスタンス化
をする上では、ルートウィジェットをいづれのウィジェットから継承させる必要があるそうです。
というか私がkivyの仕様知らなすぎるのと、kivyをこれまでガッツリ触ってきた方は当たり前
のことだったりして。。

ということでひとまず、BoxLayoutを継承させるには少々MDToolbarを使いにくいことと、
レイアウトをそんなに考えなくて済むようにするためにScreenウィジェットを継承させました。

んで、あとは前回のおさらいですが、定義してあるBoxLayoutですね。これが終わればやっと
ボタンに進めます。padding・spacing・orientationは以下リンクで触れていますので、
適宜参照してもらえれば。
[kivyMDチュートリアル其の伍 Themes - Icon Definitions篇](https://qiita.com/virty/items/97499128a205113431d5)
続きますが、size_hint、size...これはどこかで見かけましたね！なんだこれと言う方は
前回のLayout篇を参照ください。
[kivyMDチュートリアル其の什肆 Components - Layout篇](https://qiita.com/virty/items/d5fa0a529912e6b0beb0)
あとは、pos_hintですがこれは今まで出たことあったっけ？と自分でもあやふやになっている
ので一応触れますが、単に横方向に中央揃えしますよということになります。この形は縦配置
するときによく使われそうです。良く分からなければ、この形を暗記しましょう。

#### button

ようやく今日のメインディッシュです。

##### MDIconButton

マニュアルから入っていきます。
一旦、マニュアルのサンプルコードは置いておいて説明から進みます。

説明については以下のように述べられています。

> The icon parameter must have the name of the icon 
> from kivymd/icon_definitions.py file.

> You can also use custom icons:
> MDIconButton:
> 　　icon: "data/logo/kivy-icon-256.png"

アイコンはicon_definitions.pyに定義されているものを使ってよということですね。
ただしカスタムアイコンも使うことは出来るようです。

> By default, MDIconButton button has a size (dp(48), dp (48)). 
> Use user_font_size attribute to resize the button:

user_font_sizeって名前微妙じゃねえぇー?という生意気なことを言いたくなりますが
アイコンサイズも変更できるようです。デフォルトは(dp(48), dp (48))とのことです。
これは後で結果の方を見てみましょう。

> By default, the color of MDIconButton (depending on the style 
> of the application) is black or white. You can change the color 
> of MDIconButton as the text color of MDLabel:
> MDIconButton:
> 　icon: "android"
> 　theme_text_color: "Custom"
> 　text_color: app.theme_cls.primary_color

これは後々わかることですが、アイコンはデフォルトで白黒となるようです。
これもメインのテーマカラーなどに引き継ぐことが出来て、後でこの様子を見てみましょう。

##### MDFloatingActionButton

こちらは浮き上がって見えるようなアイコンボタンになります。まぁ、訳している
だけですけどねぇ。。

> The above parameters for MDIconButton apply to MDFloatingActionButton.

> To change MDFloatingActionButton background, use the md_bg_color parameter:

> 　MDFloatingActionButton:
> 　　icon: "android"
> 　　md_bg_color: app.theme_cls.primary_color


MDIconButtonでも使われていたパラメータはこちらでも使えるよ(適用される)ということ
でしょうか。あとは、背景変えたければ専用のパラメータを使ってねということもあるので
これも後で見てみましょう。

> The length of the shadow is controlled by the elevation_normal parameter:

> 　MDFloatingActionButton:
> 　　icon: "android"
> 　　elevation_normal: 12

影を付けたければ、こんなのもあるよーということも。後回しにします。

##### MDFlatButton

こちらは後述するテキストボタンと似ているものですが、枠線がないボタンになります。

> To change the text color of: class:~MDFlatButton use the text_color parameter:

> 　MDFlatButton:
> 　　text: "MDFLATBUTTON"
> 　　theme_text_color: "Custom"
> 　　text_color: 0, 0, 1, 1

文字カラーを変えたければ、これを使ってねーということも。同様、後回しにします。

> Or use markup:

> 　MDFlatButton:
> 　　text: "[color=#00ffcc]MDFLATBUTTON[/color]"

マークアップが使えたり(はえぇーほんとすっごい)

> To specify the font size and font name, use the parameters as in the usual Kivy buttons:

> 　MDFlatButton:
> 　　text: "MDFLATBUTTON"
> 　　font_size: "18sp"
> 　　font_name: "path/to/font"

フォントが使えたりもします。これは試すことはしません(なんという自分勝手なのでしょう)。

##### MDRaisedButton

MDFlatButtonとも似ていますが、こちらは枠の中に色付けをすることもできます。

> This button is similar to the MDFlatButton button except 
> that you can set the background color for MDRaisedButton:

> 　MDRaisedButton:
> 　　text: "MDRAISEDBUTTON"
> 　　md_bg_color: 1, 0, 1, 1

こちらは後で試してみましょうかね。

##### MDRectangleFlatButton

こちらは枠線が付いている中身が色付けされていないボタンになります。
枠線とテキストのカラーが選択できます。こちらは後述するMDRectangleFlatIcon-
-Buttonで試すので、そのままで。

> MDRectangleFlatButton:
> 　text: "MDRECTANGLEFLATBUTTON"
> 　theme_text_color: "Custom"
> 　text_color: 1, 0, 0, 1
> 　line_color: 0, 0, 1, 1

##### MDRectangleFlatIconButton

こちらはMDRectangleFlatButtonにアイコンがくっ付いたものになりますね。
こちらでは色が付けられるかどうか見てみます。

> MDRectangleFlatIconButton:
> 　icon: "android"
> 　text: "MDRECTANGLEFLATICONBUTTON"
> 　theme_text_color: "Custom"
> 　text_color: 0, 0, 1, 1
> 　line_color: 1, 0, 1, 1
> 　icon_color: 1, 0, 0, 1

line_colorをすべて0に設定すると、枠線なしにすることも可能らしいです。
意味があるのかどうか分からないですが。。

##### MDRoundFlatButton

枠線の角が丸っこいボタンになります。

> MDRoundFlatButton:
> 　text: "MDROUNDFLATBUTTON"
> 　text_color: 0, 1, 0, 1

##### MDRoundFlatIconButton

MDRoundFlatButtonにアイコンがくっ付いたものになりますね。

> Button parameters MDRoundFlatIconButton are the same as button MDRoundFlatButton:

> 　MDRoundFlatIconButton:
> 　　icon: "android"
> 　　text: "MDROUNDFLATICONBUTTON"

パラメータについてもアイコン以外はMDRoundFlatButtonと同じらしいです。

##### MDFillRoundFlatButton

こちらはMDRoundFlatButtonから枠線の中を全て色付けしているボタンになりますかね。

> Button parameters MDFillRoundFlatButton are the same as button MDRaisedButton.

こちらはMDRaisedButtonとパラメータは同様になるみたいです。

##### MDFillRoundFlatIconButton

省略したいところですが、こちらはMDFillRoundFlatButtonにアイコンをくっ付けたボタン。

パラメータについてもMDFillRoundFlatButtonと同様。

##### MDTextButton

こちらはシンプルなボタンになりますね。テキストだけがあるボタンと言えますか。

> MDTextButton:
> 　text: "MDTEXTBUTTON"
> 　custom_color: 0, 1, 0, 1

MDFlatButtonと違い、背景の色付けをするプロパティがないようです。これもどうなるか
確認が必要そうですね。

##### MDFloatingActionButtonSpeedDial

最後になりました。ボタンを押すとさらにボタンが現れるボタンです(ややこしい)。
使用方法はサンプルコードでもありますが、ここではkv側だけをマニュアルから抜粋。
※ サンプルコードでも同じものを使用しています

> 　MDFloatingActionButtonSpeedDial:
> 　　data: app.data
> 　　root_button_anim: True

使用方法は特に変わったものはなさそうです。が、dataについては意味不明な供述を
しています。でも、ご安心を。この後で出てきますので。
\# というかすでにマニュアルでは見えてますけどね

### class側

ここでは、MDFloatingActionButtonSpeedDialであった伏線を回収するためだけに
記載をします。まぁ、直に見てもらったほうが早そうですね。

```python
class MainApp(MDApp):

    def __init__(self, **kwargs):
        self.title = "KivyMD Examples - Buttons"
        self.data = {
            'language-python': 'Python',
            'language-php': 'PHP',
            'language-cpp': 'C++',
        }
        super().__init__(**kwargs)

    def build(self):
        self.root = Factory.ExampleButtons()
```

マニュアルでもありましたが、少し形が変わっています。app(MainApp)側でdataとありますが、
MDFloatingActionButtonSpeedDialのdataプロパティの値はこの辞書型のdataと重なります。
マニュアルと変わっているところはまだあります。辞書型の定義がおかしいじゃねーか！何バグを
生み出してんだ！と強く叱責されそうな感じがありますが、これで正しいのです。なんとマニュアル
の方がミスを犯していまして、何度も見直しましたがちゃんと動かないことには正しいことを証明
できません。それでも怪しいなと言う方がいらっしゃいましたら、サンプルコードを動かしてみて
下さい。

ふーん、そうなんだと言う方はアイコン名:表示文字列という組み合わせを覚えてもらえれば嬉しいです。

## 結果

ということで、今日も長かった！
んなことはどうでもいいので、さっそく結果をお見せします。

![66.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82826/ca1ad73a-e6ea-23a7-d1ff-3f9c573b527e.png)

おぉー、というか当たり前ですが出力はこんな感じになります。
で、右下にあるMDFloatingActionButtonSpeedDialボタンを押してみるとこんな感じになります。

![67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82826/f5b12bad-4d55-cbe8-b1f3-afd9edb8ef8e.png)

うん、問題なさそうだ！
MDFloatingActionButtonSpeedDialの方で動かないと述べましたが、少し強調していて動かない
わけではないのですが、アイコンの検索ができなく枠がくり抜かれた様子が拝見できます。気になる
方はマニュアルの指定そのままにして実行してみて下さい。

んで、あとは後で見てみますねというものを回収しておきます。対象は以下で再掲しておきます。

* MDIconButton
* MDFloatingActionButton
* MDFlatButton
* MDRaisedButton
* MDRectangleFlatIconButton
* MDTextButton

角が丸まっているボタンとMDFloatingActionButtonSpeedDialボタン以外になりますね。
ではどうなっているか見てみましょう。変更の仕方は上記で先述した通りでマニュアル記載の
ものを変更なく使っています。

![68.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82826/74304fd1-ce91-d6a7-40a4-0ae0c3656d75.png)

うーん、見事に反映されていますね。SDカードのアイコンに関してはツールバーに当たって
しまってますね。これはいけない。アンチパターンのひとつですね。あとは影が大きすぎると
なんか不恰好に見えてしまいますね。こちらのコードについてはGitHubの方でもアップして
いるので、適宜そちらもみてもらえれば。

それにしても僕もKivyMD力が上がったものだ。。なんせ、マニュアルの指摘ができるように
なったのだから。

## まとめ

とまぁ、だれも興味がないであろう独り言をしたところで締めくくろうかと思います。

さて、いかがだったでしょうか。何か使いたい、推しのボタンがありましたでしょうか。
用途によって様々だと思いますが、私はシンプルなMDRaisedButtonですかね。推しが
ありましたら、どんどんコメントください。

ということで、GW企画第2弾としてのButton篇でした！スマホだけでなくアプリとしては
協力なアイテムの1つかと思われますので、どんどん使っていきたいものです。

次回は週末予定のGW第3弾のCard篇を予定しています。お楽しみに！

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

## 参照

>  Components » Button
> https://kivymd.readthedocs.io/en/latest/components/button/

> GitHub -  kivymd / KivyMD - Components Button
> https://github.com/kivymd/KivyMD/wiki/Components-Button