導入
私は業務で最も使用する言語が Python のため、簡単な社内用ツールなどの作成にFletを用いることが多かったのですが、 先日 Flet 公式ブログ が 2025 年内でのバージョン 1.0 リリースに向けてAlpha 版を公開していたので、来る破壊的変更に向けて簡単なアプリ作成をしながら挙動の予習をしてみました。 https://flet.dev/blog
本記事で紹介している内容はAlpha 版であり安定版では変更が加わる可能性があります。
Flet とは
Fletとは Flutter をラップした Python のみでマルチプラットフォームに GUI アプリケーションを開発できるフレームワークです。
Python の豊富なライブラリ資産を活かしながらモダンな UI のアプリケーションを作成でき、2025 年 8 月現在最新バージョンが0.28.3と安定版でないながらも開発が活発で将来性のあるフレームワークです。 https://flet.dev/
Flet1.0 で何が変わるのか
このセクションの内容は 公式ブログ にも書かれているので読み飛ばしていただいても構いません。 現在提供されている情報によると以下のような変更が入るようです。
- 従来の命令型スタイルに加えて、Flet アプリを構築するための宣言型アプローチ。
- 自動更新- イベント ハンドラーの完了後にページが自動的に更新されます。
- サービス- UI の再構築やナビゲーションをまたいで存続する、永続的な非 UI コンポーネントで>す。、、などの既存のコントロールは Audio サービス FilePicker として Clipboard 書き直されました。 Web アプリの完全な WASM (WebAssembly) サポート- 最新のブラウザーでのダウンロードとパフォーマンスが高速化されます。
- Web アプリのオフライン (CDN なし) モード- Flutter リソースと Pyodide がアプリにバンドルされています。
- Flet アプリを既存の Web ページに埋め込む- 任意の Web ページ上の HTML 要素に Flet アプリをレンダリングします。
- 拡張拡張 API - スプラッシュ画面や読み込み画面などの将来のカスタマイズのための余地を残しつつ、コントロールとともにサービスをエクスポートします。
色々ありますが、従来の命令的 UI からReactのような宣言的 UIになる部分が大きな破壊的変更となっています。
従来の Flet の書き方
従来の Flet は命令的 UIを採用しており、開発者は UI の状態変化を全て自身で書く必要があります。 具体的にはpage.update()メソッドを使用してページを再レンダリングする処理をあらゆる場所で記述します。
import flet as ft
def main(page: ft.Page):
txt_number = ft.TextField(value="0", text_align=ft.TextAlign.RIGHT, width=100)
def plus_click(e):
txt_number.value = str(int(txt_number.value) + 1) # UIの値を更新
page.update() # UIを再レンダリング
page.floating_action_button = ft.FloatingActionButton(
icon=ft.Icons.ADD, on_click=plus_click
)
page.add(
ft.Container(
txt_number,
alignment=ft.Alignment.CENTER,
)
)
ft.app(main)従来のやり方だと何が問題なのか
上記のサンプルコードレベルのコード量だと感じづらいですが、UI 部品は別ファイルに分けたり、複数のグローバルステートを管理する必要がある SPA だと中々辛くなってきます。
ある操作が別の複数の UI 部品に対して状態変化を起こすような関数などが増えると状態更新のためのコードも肥大化していきます。 私はpageインスタンスでグローバルステートを管理して、ローカルステートは Flet コントロールを継承した自作 UI クラスなどで管理をして整理していました。
新しい Flet の書き方
先程の従来の書き方のサンプルコードをFlet1.0で書いたものが以下になります。
状態とそれに関連する状態更新関数をデータクラスで定義して、 UI 部品はそれらをft.ControlBuilderコントロールの中で宣言するだけで、状態更新関数が実行されると自動的に UI が再レンダリングされます。
from dataclasses import dataclass
import flet as ft
## 状態とそれに関連する状態更新関数を定義したデータクラス
@dataclass
class AppState:
count: int
def increment(self):
self.count += 1
def main(page: ft.Page):
state = AppState(count=0)
page.floating_action_button = ft.FloatingActionButton(
icon=ft.Icons.ADD, on_click=state.increment
)
page.add(
ft.ControlBuilder(
state,
lambda state: ft.SafeArea(
ft.Container(
ft.Text(value=f"{state.count}", size=50),
alignment=ft.Alignment.center(),
),
expand=True,
),
expand=True,
)
)
ft.run(main)いかがでしょうか? パッと見コード量が増えたように見えますが、ステートが増えると管理のしやすさは圧倒的にこちらが有利です。
また、Flutterを触ったことがある人ならお気づきですが、従来よりも更に Flutter に寄せたコードの書き方になっています。 しかし Flutter と違ってコンストラクタ周りの記述が一切不要なのは凄い楽ちんですね。
アプリを作成して挙動を確認してみた
記事冒頭でも触れましたが、現在 Flet バージョン 1.0 に向けてAlpha版が公開されています。 公式ブログだけ読んでいてもつまらないので、この Alpha 版 Flet1.0 を使ってアプリを作成してみました。
作成したアプリ
題材選定ですが、社内でやや需要のあった PDF の圧縮・結合・抽出などが簡単な GUI 操作でできるアプリを作ってみました。 Windows64bit 限定です。 https://github.com/harumiWeb/flet1.0alpha-pdf-compressor-app
とはいってもビジネスロジックの部分は外部ソフトウェアのバイナリを埋め込んでいて私はフロントエンドの実装しかしていません。 宣言的 UI を触れるのには丁度いい題材でした。
状態管理したいところ
UI は以下の画像のような SPA 形式にしました。
-
メイン画面

-
出力するページを設定できる画面

ざっくり状態管理する項目を挙げると
- サイドバーの設定項目
- 選択されたファイルの情報
- 処理後のファイルの情報
などかと思います。
宣言的 UI で実装してみる
状態側の処理
今回はstate.pyというファイルにアプリ内で使うステートを宣言してみました。
Flet1.0 のステートクラスはただのdataclassなので、ステートクラスの中にステートクラスをネストすることで複雑なデータ型も問題なく扱えます。
AppGlobalStateデータクラスで宣言している内容がアプリのグローバルステートにあたります。 https://github.com/harumiWeb/flet1.0alpha-pdf-compressor-app/blob/main/state.py
雑なところはありますが、こうやって書いてみると、状態と状態更新関数が一つのクラスでまとめられるので非常にコードの管理がしやすいです。
UI 側の処理
UI 側のコードは以下のように実装してみました。 エントリーポイントなのであまり UI の記述はないですが、AppView関数上部のほうで選択済みファイルタブと処理済みファイルタブを宣言して値と更新関数にグローバルステートを使用しているのが見て取れるかと思います。 https://github.com/harumiWeb/flet1.0alpha-pdf-compressor-app/blob/main/main.py#L20-L87
その他従来の Flet と実装が大きく変わったところ
- on_clickなどで発火する関数が非同期になった
これ、かなり大きな変更なんですが、インタラクティブな UI 部品に設定できるon_~系の処理が非同期関数として実行されるようになりました。
つまり、通常の関数ではなくasync defのように宣言する必要があります。 そして注意しないといけないのが、非同期関数内でpageインスタンス組み込みの UI に変化をもたらす関数は処理が後回しにされるということです。
このあたりは Alpha 版のため、実際の 1.0 では仕様が変わる可能性がありますが、Alpha 版段階では上記仕様だったため、少し工夫が必要でした。 https://github.com/harumiWeb/flet1.0alpha-pdf-compressor-app/blob/main/components/sidebar.py#L201-L219
Flet 組み込みのダイアログを表示、非表示する関数としてpage.show_dialog()やpage.pop_dialog()を使っているのですが、これらは非同期関数ではないためawaitすることができず、 従来のやり方で実装すると、処理中のダイアログの表示を待たずに処理ロジックが走って順番を制御できませんでした。
なので、await asyncio.sleep()を使って擬似的に await を入れて順序を制御してみました。
この辺の挙動は従来の Flet に慣れている人だとハマるかもしれないので、もう少し楽な実装ができるようになることを期待したいです。
細かい実装方法の違いなど
アプリのローカルストレージに値を格納しておくメソッドとして従来は以下のようなpage.client_storageを使っていましたが、
page.client_storage.set("key", "value")
value = page.client_storage.get("key")こちらはpage.shared_preferencesに置き換わり、値の取得処理は非同期になりました。
theme = await page.shared_preferences.get_async("theme")Flutter でストレージ管理モジュールとしてshared_preferencesがよく使われていて、Flet のストレージ管理も内部的にshared_preferencesを使っているので、こちらも Flutter により近くなったということでしょう。
他にも多くの場所に破壊的変更が入っているのですが、現在進行系で再設計されているのでソースコードを解読してみると色々発見があって楽しいので見てみてください 👀
Flet1.0Alpha を触った感想
ざっくり感想
- 状態管理めっちゃ楽になった!
- 非同期処理とレンダリングの連携むずい
- プロバイダーが無いので油断するとステートのバケツリレーになる
慣れなさから来る不便さはありましたが、慣れれば従来の Flet よりも圧倒的に少ないコードでインタラクティブなアプリケーションを開発できるので安定版のリリースがとても楽しみになりました。
現在は0.70.0のAlpha版として公開されているだけなので、本記事で紹介している挙動からまた大きな変更が加わる可能性はありますが、大本命の宣言的 UI の部分はかなり出来てきているので、何か簡単なアプリを作って遊んでみるとすごく楽しいと思います!
ちょっとした GUI ツールに Flet、いかがでしょうか?

