🐍

【Flet】GridViewの内容を中央揃えで表示したい【Python】

2024/11/30に公開

やりたいこと

Fletには複数のコントロールをいい感じに一覧表示してくれるGridViewコントロールが存在します。
https://flet.dev/docs/controls/gridview/
このGridViewがどのような働きをするのかは、公式のアイコンブラウザーを見ればだいたい分かると思います。
https://gallery.flet.dev/icons-browser/

このGridView、表示するコントロールの数が少ないときには左上にすべてが寄るかたちになって少し寂しい見た目になってしまいます。(GridViewの使用場面を考えれば当然ですが)

これを以下のように中央に寄せて表示したい場面があったのですが、一筋縄ではいかなかったのでその方法を記しておきます。

結論

GridViewをContainerの中に入れ、Containerの内容を中央揃えにするようにします。
そして、GridViewの幅(widthプロパティ)をそのmax_extentプロパティとcontrolsプロパティ(これはリスト型)の長さを掛けた値に設定すれば解決です。

ソースコード

import flet as ft

def main(page: ft.page):
    gv = ft.GridView(
        spacing=30,
        run_spacing=30,
        max_extent=200,
    )

    ct = ft.Container(
        content=gv,     # GridViewを内包
        alignment=ft.alignment.center,  # Containerの内部を中央寄せ
        expand=1,       # expandを1に設定することでGridViewがスクロールできるようになる
    )

    for i in range(3):
        gv.controls.append(
            ft.Container(
                bgcolor=ft.colors.BLUE,
                border_radius=20,
            )
        )
    
    # GridViewの幅をmax_extent × controlsの長さに設定
    gv.width = gv.max_extent * len(gv.controls)

    page.add(ct)

ft.app(main)

実行結果

原理

なんで上記のようなコードにする必要があるのか、自分で気づくのに紆余曲折あったのでそれを記していこうと思います。
まず、これから解説する内容の元となるコードを紹介しておきます。

import flet as ft

def main(page: ft.page):
    gv = ft.GridView(
        spacing=30,
        run_spacing=30,
        max_extent=200,
    )

    for i in range(3):
        gv.controls.append(
            ft.Container(
                bgcolor=ft.colors.BLUE,
                border_radius=20,
            )
        )

    page.add(gv)

ft.app(main)

GridViewに青色のContainerを3つだけ入れた単純なコードです。
max_extentを設定しておくことで、ウィンドウサイズを変更してもいい感じにGridViewが内包するコントロールの大きさを調整してくれるようになります。(今回はこのmax_exntenありきで書いていきます)

GridViewに中央寄せをするプロパティはない

公式ドキュメントを読んだり、ChatGPTやGeminiに聞いてみたりしたのですが、FletのGridViewコントロールにはalignmentのような整列方法を設定するプロパティは存在しないようです。
そのため、今回のようにGridViewで中央寄せを実現したい場合は別のアプローチを考えなければいけません。

Containerに入れてalignmentを設定

GridView単体では中央寄せをできないのであれば、親要素で中央に寄せてやろう!ということで以下のようなコードを書いてみました。

import flet as ft

def main(page: ft.page):
    gv = ft.GridView(
        spacing=30,
        run_spacing=30,
        max_extent=200,
    )

    ct = ft.Container(
        content=gv,     # GridViewを内包
        alignment=ft.alignment.center,  # Containerの内部を中央寄せ
    )

    for i in range(3):
        gv.controls.append(
            ft.Container(
                bgcolor=ft.colors.BLUE,
                border_radius=20,
            )
        )

    page.add(ct)

ft.app(main)

魂胆は単純で、GridViewをContainerに入れて、Container内部のレイアウトを中央寄せに設定しただけです。
これで解決!と思ったのですが実行してみるとあらびっくり

Containerに内包しないときと何も変わっていません。

なんで??

GridViewは横に延びる

どうやら、GridViewは親要素の領域の許す限り無制限に横方向にスペースを占拠する仕様のようです。(上下方向には不必要に延びない)
たとえば、内包する要素が3つだけの以下のようなGridViewでも、GridViewの占めるスペースは以下のようになっています。

そのため、親要素のContainerで中央寄せに設定しても場所が動かない、という状況に陥っていました。

GridViewの幅を設定する

これを解決するには、GridViewの領域を以下のように表示するコントロールにフィットさせる必要があります。

GridViewコントロールにはwidthプロパティが用意されているので、これを適切な値に設定することができれば、問題を解決できそうです。
今回使用しているコードでは、最大幅200(max_extent=200)のContainerが3つ並ぶというGridViewになっています。そのため、600をGridViewの幅として設定してあげればちょうど良さそうです。
ここで、冒頭の結論で述べた

gv.width = gv.max_extent * len(gv.controls)

という計算式が出てきます。
GridViewのcontrolsにコントロールを追加し終わったタイミングでこの計算式を実行するとGridViewの幅が希望通りに調整され、狙ったようにGridViewを中央揃えにできます!

完成形コード

import flet as ft

def main(page: ft.page):
    gv = ft.GridView(
        spacing=30,
        run_spacing=30,
        max_extent=200,
    )

    ct = ft.Container(
        content=gv,     # GridViewを内包
        alignment=ft.alignment.center,  # Containerの内部を中央寄せ
        expand=1,       # expandを1に設定することでGridViewがスクロールできるようになる
    )

    for i in range(3):
        gv.controls.append(
            ft.Container(
                bgcolor=ft.colors.BLUE,
                border_radius=20,
            )
        )
    
    # GridViewの幅をmax_extent × controlsの長さに設定
    gv.width = gv.max_extent * len(gv.controls)

    page.add(ct)

ft.app(main)

おまけ

結論でさらっとコメントアウトしてましたが、GridViewの親要素となるContainerのexpandプロパティを1(またはTrue)に設定しておくと、GridViewがウィンドウをはみ出るほど下方向に延びてもスクロールができるようになります。

#~~~省略~~~#

ct = ft.Container(
    content=gv,
    alignment=ft.alignment.center,
    expand=1,       # expandを1に設定することでGridViewがスクロールできるようになる
)

#~~~省略~~~#

Fletはまだベータ版のライブラリということもあり情報も少ないので、すこし難しいことをしようとすると自力で工夫しなければいけいないことが多いですよね(それがFletの楽しいところでもありますが)。
この記事が少しでもあなたの役に立てば幸いです。

Discussion