【Flet】pageメソッドでDialogやBannerの表示/非表示を行う

## 背景

複数のダイアログやバナーの表示/非表示を行う時、FletのDocsに記載されている書き方だと同じコードが増えてしまうことがよくありました。

[**AlertDialogのサンプル**](https://flet.dev/docs/controls/alertdialog/#basic-and-modal-dialogs)

```flet_sample_dialog.py
import flet as ft

def main(page: ft.Page):
    page.title = "AlertDialog examples"

    dlg = ft.AlertDialog(
        title=ft.Text("Hello, you!"), on_dismiss=lambda e: print("Dialog dismissed!")
    )

    def close_dlg(e):
        dlg_modal.open = False
        page.update()

    dlg_modal = ft.AlertDialog(
        modal=True,
        title=ft.Text("Please confirm"),
        content=ft.Text("Do you really want to delete all those files?"),
        actions=[
            ft.TextButton("Yes", on_click=close_dlg),
            ft.TextButton("No", on_click=close_dlg),
        ],
        actions_alignment=ft.MainAxisAlignment.END,
        on_dismiss=lambda e: print("Modal dialog dismissed!"),
    )

    def open_dlg(e):
        page.dialog = dlg
        dlg.open = True
        page.update()

    # open_dlgメソッドとほとんど同じ
    def open_dlg_modal(e):
        page.dialog = dlg_modal
        dlg_modal.open = True
        page.update()

    page.add(
        ft.ElevatedButton("Open dialog", on_click=open_dlg),
        ft.ElevatedButton("Open modal dialog", on_click=open_dlg_modal),
    )

ft.app(target=main)
```

[**Bannerのサンプル**](https://flet.dev/docs/controls/banner#banner-with-leading-icon-and-actions)

```flet_sample_banner.py
import flet as ft

def main(page):
    def close_banner(e):
        page.banner.open = False
        page.update()

    page.banner = ft.Banner(
        bgcolor=ft.colors.AMBER_100,
        leading=ft.Icon(ft.icons.WARNING_AMBER_ROUNDED, color=ft.colors.AMBER, size=40),
        content=ft.Text(
            "Oops, there were some errors while trying to delete the file. What would you like me to do?"
        ),
        actions=[
            ft.TextButton("Retry", on_click=close_banner),
            ft.TextButton("Ignore", on_click=close_banner),
            ft.TextButton("Cancel", on_click=close_banner),
        ],
    )

    def show_banner_click(e):
        page.banner.open = True
        page.update()

    page.add(ft.ElevatedButton("Show Banner", on_click=show_banner_click))

ft.app(target=main)
```

## pageメソッドを使って、ダイアログやバナーの表示/非表示を行う

pageのメソッドにあらかじめ定義されています。[^1]

- ダイアログの[表示](https://flet.dev/docs/controls/page#show_dialogdialog-alertdialog)
  - show_dialog(dialog: AlertDialog)
- ダイアログの[非表示](https://flet.dev/docs/controls/page#close_dialog)
  - close_dialog()
- バナーの[表示](https://flet.dev/docs/controls/page#show_bannerbanner-banner)
  - show_banner(banner: Banner)
- バナーの[非表示](https://flet.dev/docs/controls/page#close_banner)
  - close_banner()

このメソッドを使用することで、ダイアログ/バナーごとの表示/非表示メソッドが不要になります。[^2]

## サンプルコード

比較しやすいように、FletのDocsのサンプルコードで試してみます。[^3]

[^3]: Python(3.10)、Flet(0.20.2)で実装

**AlertDialogの場合**

```close_dialog_by_page_method.py.py
import flet as ft


def main(page: ft.Page):
    page.title = "AlertDialog examples"

    dlg = ft.AlertDialog(title=ft.Text("Hello, you!"))

    dlg_modal = ft.AlertDialog(
        modal=True,
        title=ft.Text("Please confirm"),
        content=ft.Text("Do you really want to delete all those files?"),
        actions=[
            ft.TextButton("Yes", on_click=lambda _: page.close_dialog()),
            ft.TextButton("No", on_click=lambda _: page.close_dialog()),
        ],
        actions_alignment=ft.MainAxisAlignment.END,
    )

    page.add(
        ft.ElevatedButton("Open dialog", on_click=lambda _: page.show_dialog(dlg)),
        ft.ElevatedButton("Open modal dialog", on_click=lambda _: page.show_dialog(dlg_modal)),
    )


ft.app(target=main)

```

**Bannerの場合**

```close_banner_by_page_method.py
import flet as ft


def main(page: ft.Page):
    banner = ft.Banner(
        bgcolor=ft.colors.AMBER_100,
        leading=ft.Icon(ft.icons.WARNING_AMBER_ROUNDED, color=ft.colors.AMBER, size=40),
        content=ft.Text("Oops, there were some errors while trying to delete the file. What would you like me to do?"),
        actions=[
            ft.TextButton("Retry", on_click=lambda _: page.close_banner()),
            ft.TextButton("Ignore", on_click=lambda _: page.close_banner()),
            ft.TextButton("Cancel", on_click=lambda _: page.close_banner()),
        ],
    )

    page.add(ft.ElevatedButton("Show Banner", on_click=lambda _: page.show_banner(banner)))


ft.app(target=main)
```

Dialog、Bannerともにメソッドを作成せず表示/非表示を実現できました。

## 使ってみた感想

単純な表示/非表示だけなら、Pageメソッドを使うとコード数を減らすことができるなと感じました。
DialogやBanner以外にもpageメソッドで補えるものがあるので、どんどん活用していきたいと思います。

## 参考ページ

https://flet.dev/

https://flet.dev/docs/controls/page/

[^1]: [Ver0.8.0](https://github.com/flet-dev/flet/blob/main/CHANGELOG.md#080)で導入されている
[^2]: 複雑な処理（ex.ダイアログを表示させてから、別の動作も行う等）の場合は、個別に設定する