kivyMDチュートリアル其の肆什伍 Behaviors - Hover篇

ハロー、Qiita！いかがお過ごしでしょうか。

はい、というわけで間もなく1月も終わりに近づいていますが、お元気に過ごして
いますでしょうか。何よりこの季節は寒いでございますね。外に出るのが億劫に
なるくらいで。まぁ緊急事態宣言も出そうな雰囲気で、出なくともステイホーム
が余儀なくされそうです。

さて、本題に移りますが今日からはKivyMDのBehaviors章に戻っていきます。
以前どこまでやったっけなという思いに駆られていますが、確認してみると以前
はFocus篇をやっていました。ということで、今日はタイトルの通りで続きのHo-
ver篇となります。それではさっそくやっていくこととします。

あ、それでは、レッツラゴ。(わざわざ言うまでもない)

## Hover

冒頭には比較的大文字で説明が書かれています。

> Changing when the mouse is on the widget and the widget is visible.

読んで字の通りということになるでしょうか。と言っても良くみるとChangeig-
when the mouseあたりなんかは一見パッと翻訳しづらいところもあります。
こういうことでは義務・高等教育で教えてもらってはいません。(語弊の可能性あり)

ということで冒頭からにはなりますが、依頼してみることとします。
おーい、DeepLくーん！

> マウスがウィジェット上にあり、ウィジェットが表示されているときに変化します。

すると、上のように結果が返ってきました。もうwhenの手前でバッサリ切ること
になるのですね。勉強になる。

続いて、補足としてまた1文があります。これも見てみましょう。

> To apply hover behavior, you must create a new class that is 
> inherited from the widget to which you apply the behavior and 
> from the HoverBehavior class.

このあたりについては、依頼をかけなくても今までもお馴染みの表現ではない
でしょうか。単にhoverしたかったら、HoverBehaviorクラス継承してね、
ということになるでしょう。で、あとでその様子が分かるでしょう。

で、使い方としてあるのが次になります。

> In KV file:

> \<HoverItem@MDBoxLayout+ThemableBehavior+HoverBehavior>

> In python file:

> class HoverItem(MDBoxLayout, ThemableBehavior, HoverBehavior):
> 　　　'''Custom item implementing hover behavior.'''

Behivors章の特徴としてこのような継承をおこなうことが多くあるというのも
特徴の1つのようですね。さらに文は続きます。

> After creating a class, you must define two methods for it: 
> HoverBehavior.on_enter and HoverBehavior.on_leave, which 
> will be automatically called when the mouse cursor is 
> over the widget and when the mouse cursor goes beyond the widget.

ここまでくるともう手に負えません。また依頼をかけます。

> クラスを作成したら、そのクラスに対して2つのメソッドを定義する必要があります。
> HoverBehavior.on_enter と HoverBehavior.on_leave はマウスカーソルが
> ウィジェットの上に来たときと、マウスカーソルがウィジェットを越えたときに自動的に
> 呼び出されるメソッドです。

それっぽい結果が返ってきました。さすが、優秀ですね。これらのこともあとで
見てみましょう。

さらにさらに、この後では、Noteが続いています。これも見ないわけにはいかないので、
見てみましょう。

> HoverBehavior will by default check to see if the current Widget 
> is visible (i.e. not covered by a modal or popup and not a part 
> of a Relative Layout, MDTab or Carousel that is not currently 
> visible etc) and will only issue events if the widget is visible.


> To get the legacy behavior that the events are always triggered,
> you can set detect_visible on the Widget to False.

んー、これも手に負えず、、ですね。またまた依頼をかけてみます。

> HoverBehaviorは、デフォルトで現在のウィジェットが可視であるかどうかを確認し
> （モーダルやポップアップに覆われておらず、現在表示されていない相対レイアウト、
> MDTab、カルーセルなどの一部でもない）、ウィジェットが可視である場合にのみ
> イベントを発行するようになりました。

> イベントが常にトリガーされるレガシーな動作を得るには、Widgetのdetect_visible
> をFalse に設定することができます。

このあたりはカスタマイズの話もあるので、なかなか深みのある話になってきますね。
ポイントとしては、可視化されているかということになるでしょうか。現状の仕様だと
可視かどうかをチェックして可視であればイベントを出すということになるので、常に
それやりたいのであればそれ専用のプロパティを使ってやってね、ということになる
でしょうか。

では、長らくお待たせしましたが、さっそくコードに入っていきます。

```python:xlv/hover.py
from kivy.lang import Builder

from kivymd.app import MDApp
from kivymd.uix.behaviors import HoverBehavior
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.theming import ThemableBehavior

KV = '''
Screen

    MDBoxLayout:
        id: box
        pos_hint: {'center_x': .5, 'center_y': .5}
        size_hint: .8, .8
        md_bg_color: app.theme_cls.bg_darkest
'''


class HoverItem(MDBoxLayout, ThemableBehavior, HoverBehavior):
    '''Custom item implementing hover behavior.'''

    def on_enter(self, *args):
        '''The method will be called when the mouse cursor
        is within the borders of the current widget.'''

        self.md_bg_color = (1, 1, 1, 1)

    def on_leave(self, *args):
        '''The method will be called when the mouse cursor goes beyond
        the borders of the current widget.'''

        self.md_bg_color = self.theme_cls.bg_darkest


class Test(MDApp):
    def build(self):
        self.screen = Builder.load_string(KV)
        for i in range(5):
            self.screen.ids.box.add_widget(HoverItem())
        return self.screen


Test().run()
```

最初から最後まで、シンプルな構成となることは見て分かるのではないでしょうか。
もし分からねー、となった方はComponents章のどこか4~5篇くらい見ると景色が
変わってくるのが分かると思います。(なげやり)

もしそんな時間ねーよ!という方のために以下リンクがあります。これでもわか
んねーとなった方は該当マニュアルをご覧ください。

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

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

KV側ではMDBoxLayoutが1つあるだけになります。で、どうやってウィジェット
生成してんのよ、という問いにはメイン(Test)クラスを見てねという返答になり
そうです。メインクラスでrangeを回してHoverItemインスタンスを生成して
います。

あとはHoverItemって何なのよということですが、今日のメインディッシュとなる
ところになります。部分的にコードの方を再掲しておきます。

```python
class HoverItem(MDBoxLayout, ThemableBehavior, HoverBehavior):
    '''Custom item implementing hover behavior.'''

    def on_enter(self, *args):
        '''The method will be called when the mouse cursor
        is within the borders of the current widget.'''

        self.md_bg_color = (1, 1, 1, 1)

    def on_leave(self, *args):
        '''The method will be called when the mouse cursor goes beyond
        the borders of the current widget.'''

        self.md_bg_color = self.theme_cls.bg_darkest
```

最初から眺めると、まず冒頭で言及していたHoverBehaviorクラスですが、
ここで継承していることが分かりますね。

お次はというと、on_enter/on_leaveクラスがあることが分かるかと思います。
これは定義する必要があるということでしたが、定義する必要があります。ネタバレ
要素ですが、試しにこの2つをコメントアウトするとHoverItemは表示されますが、
Hoverが効かないことが確認出来ました。これを定義することで、イベントが発行
される仕組みになっているのですね。

中身はというと、md_bg_colorプロパティを対象に、白色・ダークな色をそれぞれ
のメソッドで設定しているだけになります。

### 結果

触れ込みが全て終わったところで、実行結果の方を見てみます。論より証拠を。
今の時代にピッタリなことですね。

![204.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82826/4e52385e-6dc6-b93d-4d14-80a3ec91569d.gif)

まぁ偉そうなこと言っていますが、マニュアルとそれほど変わり映えのない
ものとなっています。ですが、ちゃんと動いていて有効化されているという
ことが分かっているだけでも、何かしら意味のあることではないかと。
\# ポジティブシンキング

### API - kivymd.uix.behaviors.hover_behavior

まとめに入る前にAPIのことについて触れておきます。

#### class kivymd.uix.behaviors.hover_behavior.HoverBehavior(**kwargs)

`Events:`

`on_enter`

> Called when mouse enters the bbox of the widget AND the widget is visible

`on_leave`

> Called when the mouse exits the widget AND the widget is visible

今回における主人公のサブの立場なメソッドです。(意味不明)
Hoverをしたい場合にはこれらを定義する必要があります。

`detect_visible`

> Should this widget perform the visibility check?

> detect_visible is a BooleanProperty and defaults to True.

今回はHoverに関するプロパティを使うことはありませんでしたが、少し
面白いと思ったので記載してみました。まさかの疑問形で終わっていると
いう。。コミュニティメンバーに問いかけているのでしょうか。

プロパティについては冒頭らへんでもあったvisibleかどうかを検知する
ものでした。デフォルトはTrueとなってます。

## まとめ

さて、いかがだったでしょうか。

似ている機能としては、以前やったFocusがありました。この違いは何なん
でしょうね。

振り返りも合わせてそれと照らし合わせてみましたが、Focusは発行する
イベントが必要ありませんでした。

なので違いはというと、発行するイベントの記載が強制されるかどうか
ということになりますでしょうか。他にも細かな違いなどはありそう
ですが、これについては追調査が必要です。

ということで、今日はこの辺にしたいと思います。来週はさらに続きで
Magic篇となります。お楽しみに〜。

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

## 参照

> Behaviors » Hover
> https://kivymd.readthedocs.io/en/latest/behaviors/hover/

> DeepL 翻訳ツール
> https://www.deepl.com/ja/translator