kivyMDチュートリアル其の什捌 Components - Expansion Panel篇


どうも、おはこんばんは。いかがお過ごしでしょうか。
こう暑かったり寒かったりだと、体調を崩しやすくなりますね。そんな日頃は、
お家でkivyMDでも触っておきましょう。その内、直接DNAにも効いてきます(違う)。

そんな冗談は置いておいて、最近はkivyMDと比較するためにFlutterをちょこっと
触っていますが、これほどにも違ってくるかと日々驚くばかりです。あと機能がこんなに
豊富なんだなぁとまた驚いて。。他には、使いやすいかと言われるとそこはうーんという
回答になりそうですね。個人的にはプロパティと振る舞いなどのロジック部分は分けたい
なぁと思うばかりです。Flutterのページとかも作ろうかなぁ。

てまぁ、前置きが長くなってきたので、これくらいにして今日のお題に入っていこうと思い
ます。今日はExpansion Panelです。

Expansion Panel

通例のMaterialDesignサイトは置いておいて、概要としては以下のように述べられています。

Expansion panels contain creation flows and allow lightweight editing of an element.

これもちょっと、DeepLでの依頼結果が見ものだったので依頼してみました。

拡張パネルには、作成フローが格納されており、要素の軽量な編集が可能です。

とのことです。なぜか、自分はallowとarrowを間違えてへぇー矢印なんだと思っていた
ことは秘密です。英語やり直そうかなぁw

とまぁ、どうでもいいことは放っておいて、上記のようになっています。GoogleMapとか
でもあるやつ(営業時間の表示部分)だよなぁと思っていましたが、なんか同じではなく断定
しにくいので一旦保留です。どこでも見かけると思いきや、具体例がなかなか探しにくいものです。
でもまぁ、一言で言うと「パネルが開いたり閉じたりするやつ」ということでしょうか。これは
kivyMDの中で似たようなものでいうと、MDBannerにあたるものですね(覚えていますでしょうか)。

Usage

ここも前置きが長くなってきたので、使用例に移ります。使用例は以下だと案内があります。

self.add_widget(
    MDExpansionPanel(
        icon="logo.png",  # panel icon
        content=Content(),  # panel content
        panel_cls=MDExpansionPanelOneLine(text="Secondary text"),  # panel class
    )
)

はっはっは、簡単じゃないかジョニー!と洋画のセリフでありそうなくらいシンプルな
使用例となっていますね。これまで色々と触ってきた方はすんなり入ってくるのではない
でしょうか。あるwidgetにMDExpansionPanelインスタンスを生成してそれを放りなげて
いるだけです。MDExpansionPanelの中身はこれから見てみましょう。

なにやら説明が追加されています。

To use MDExpansionPanel you must pass one of
the following classes to the panel_cls parameter:

● MDExpansionPanelOneLine
● MDExpansionPanelTwoLine
● MDExpansionPanelThreeLine

panel_clsプロパティの指定されるウィジェットクラスとしては上記3つの内どれか1つを
選択する必要がありますということでしょうか。

These classes are inherited from the following classes:

● OneLineAvatarIconListItem
● TwoLineAvatarIconListItem
● ThreeLineAvatarIconListItem

先述した3つのクラスはそれぞれ上記の3つの派生クラスということになるみたいです。
なので、上記の3つのクラスについて、詳細は今後List篇で触れていくのでここでは
割愛ということで。ここではとりあえず、それらのプロパティとかが使用できるんだ
と留めるだけにしておきます。

実際に使われるだろうという例が載せられています。

self.root.ids.box.add_widget(
    MDExpansionPanel(
        icon="logo.png",
        content=Content(),
        panel_cls=MDExpansionPanelThreeLine(
            text="Text",
            secondary_text="Secondary text",
            tertiary_text="Tertiary text",
        )
    )
)

Example

では、お待ちかねかもなので実際にコードに触れ込んでいきましょうか。
いろいろ、改変していこうかと思いましたが時間の都合上マニュアルのままでお許しください。。

viii/expansion_panel.py
from kivy.lang import Builder

from kivymd.app import MDApp
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.expansionpanel import MDExpansionPanel, MDExpansionPanelThreeLine
from kivymd import images_path

KV = '''
<Content>
    adaptive_height: True

    TwoLineIconListItem:
        text: "(050)-123-45-67"
        secondary_text: "Mobile"

        IconLeftWidget:
            icon: 'phone'


ScrollView:

    MDGridLayout:
        id: box
        cols: 1
        adaptive_height: True
'''


class Content(MDBoxLayout):
    '''Custom content.'''


class Test(MDApp):
    def build(self):
        return Builder.load_string(KV)

    def on_start(self):
        for i in range(10):
            self.root.ids.box.add_widget(
                MDExpansionPanel(
                    icon=f"{images_path}kivymd_logo.png",
                    content=Content(),
                    panel_cls=MDExpansionPanelThreeLine(
                        text="Text",
                        secondary_text="Secondary text",
                        tertiary_text="Tertiary text",
                    )
                )
            )


Test().run()

import

今日のコードはTestクラス側でMDExpansionPanelなど使用しているので、import文は
以下のようになります。MDBoxLayoutはContentクラスがそれを継承しているので、必要
な宣言となります。

from kivy.lang import Builder

from kivymd.app import MDApp
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.expansionpanel import MDExpansionPanel, MDExpansionPanelThreeLine
from kivymd import images_path

kivy側

もう一度、kivy側で何を書いているのかおさらいしてみましょう。

<Content>
    adaptive_height: True

    TwoLineIconListItem:
        text: "(050)-123-45-67"
        secondary_text: "Mobile"

        IconLeftWidget:
            icon: 'phone'


ScrollView:

    MDGridLayout:
        id: box
        cols: 1
        adaptive_height: True

ContentカスタムクラスとルートウィジェットにScrollViewがありますね。Content側は
MDBoxLayoutを継承しているので、adaptive_heightが使えるようになります。具体的な
中身はList篇の触れ込みになってしまうので、ここでは割愛します。textなどがあるんだ!
と目を焼き付けておきましょう。あとで目に見えて分かります。

ScrollViewは中にMDGridLayoutを持っていて、1列表示のidをboxとしてadaptive_height
を有効化しています。idはTestクラス側でも出てくるので要チェック!!

Contentクラス側

ここでは、クラス側で定義するだけで何もしていることはありません。
ただし、MDBoxLayoutを継承していることは目に見えて分かります。

ここで表示テキストを可変にしたいなーと思ったときには、textプロパティを生成しておきます。

class Content(MDBoxLayout):
    '''Custom content.'''

Testクラス側

ここでも、何書いているか忘れがちなので再掲しておきます。

class Test(MDApp):
    def build(self):
        return Builder.load_string(KV)

    def on_start(self):
        for i in range(10):
            self.root.ids.box.add_widget(
                MDExpansionPanel(
                    icon=f"{images_path}kivymd_logo.png",
                    content=Content(),
                    panel_cls=MDExpansionPanelThreeLine(
                        text="Text",
                        secondary_text="Secondary text",
                        tertiary_text="Tertiary text",
                    )
                )
            )

今日のメインディッシュというか冷めた料理になっているのか分からないですが、
チェックするべきポイントはon_startメソッドとなります。もう見飽きたなーと
思ってしまうほどのイテレータでクラスを生成しているところですが、これもUsage
のところで触れましたね。予定調和感がすごいですが、実際の使われ方はこうなります。

触れてなかったポイントはcontentプロパティにContentクラスを指定しているところに
なります。実際、下部にピローって出てくる部分ですね。で、あとは適当なiconを定義して
完成ー!っと。

Two events are available for MDExpansionPanel

スルーしようかと思いましたが、一応念のため触れておきます。

パネルをオープン・クローズしたときにイベントを定義出来るらしいです。

● on_open
● on_close

MDExpansionPanel:
    on_open: app.on_panel_open(args)
    on_close: app.on_panel_close(args)

on_panel_openの引数にはパネル(選択した1つのなのかな?)のインスタンスを渡す
みたいです。

The user function takes one argument - the object of the panel:

def on_panel_open(self, instance_panel):
print(instance_panel)

API

で、結果に入る前に使用されたAPIの触れ込みになります。
実際に荒々しく引用していきます。

class kivymd.uix.expansionpanel.MDExpansionPanel(**kwargs)

content

Content of panel. Must be Kivy widget.
content is an ObjectProperty and defaults to None.

kivyならなんでもよいということでしょうか。なかなか見たことない案内です。

icon

Icon of panel.
Icon Should be either be a path to an image or a logo name in md_icons
icon is an StringProperty and defaults to ‘’.

どうやら、指定する必要はないようですね。まぁよほどのことない限り指定するとは思いますが。

panel_cls

Panel object. The object must be one of the classes MDExpansionPanelOneLine,
MDExpansionPanelTwoLine or MDExpansionPanelThreeLine.

panel_cls is a ObjectProperty and defaults to None.

これも必ずしも指定する必要はなし。まぁよほどのこと...モガモガ。

結果

お待たせしております。お世話になっております。

意味不明な文言がありましたが、放っておいて実行結果にはいります。
疲れているだけで、変わったことはありません。

これも、マニュアル通りですね。うーん、つまらない。
だけれども、ちゃんと動いていることは分かります。

適当な場所を押すと、コンテンツが出てきました。だけれども、工夫点はいまひとつという
ところになります。

これだけだと、丸写しだけで面白みがありませんので他のサンプルも動かしてみました。
具体的なものでいうと、マニュアルの真ん中下部あたりにある以下リンクになります。

# ちょっと中身見えにくいですが...

一言で言えばMDCardにパネルを使うこともできるぜ!ということになりますね。
これも触れ込みの量が多く、もったいぶることも出来ないので結果を以下に載せて
おきます。画像は先週にも登場した猫ちゃんになります。

かわいい。実際に開いてみます。

可愛すぎて、電話してしまいそうです。押してもなにも出来ません(当たり前)。

こちらもGitHubにコードを置いていますので、好きな画像があれば試してみてもよいのではないでしょうか。

まとめ

さぁ、いかがだったでしょうか。
若干、手抜き感が出てしまってて申し訳ありませんということになりますが、
使うことが出来るということは分かられたと思います(ポジティブシンキング)。

設定画面とかでも重宝しそうなウィジェットになりそうですね。こう使えるのでは!
ということがありましたら、コメントいただけると嬉しいです。

次回は順番通りにいくと、FileManagerなのですが、あまりPCの中身は...という
ことと実際にスマホで見たほうがいいんじゃね?ということで飛ばします。なのでLayout
篇は終わっているので、飛ばして飛ばしてImage List篇となります。お楽しみに〜。

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

補足

先週、GitHubのコードをプッシュし忘れていました。お詫び申し上げます。

参照

Components » Expansion Panel
https://kivymd.readthedocs.io/en/latest/components/expansion-panel/

Components Expansion Panel and MDCard
https://github.com/kivymd/KivyMD/wiki/Components-Expansion-Panel-and-MDCard