mcpField
P
python-flet

python-flet

github.com/the-perfect-developer開発1539 回インストール26 週間前に更新
リポジトリ

python-flet について

python-fletは、Fletを使った開発のためのスキルです。FletはFlutterウィジェットをPythonコントロールとして扱うフレームワークで、Web、デスクトップ、モバイルアプリに対応し、アプリ構成やUI、ナビゲーション、非同期処理、性能改善を扱います。

主な機能

  1. 01Pythonコントロールによるアプリ構築
  2. 02レイアウトとカスタムコントロールの作成
  3. 03ルーティングとテーマの設定
  4. 04非同期タスクとライフサイクルメソッドの利用
  5. 05大規模なスクロールリストの最適化
  6. 06Webまたはデスクトップでの実行

活用シーン

  1. 01Pythonでクロスプラットフォームアプリを開発
  2. 02カスタムコントロールを使ったルーティング画面の構築
  3. 03大規模なリストの効率的な表示

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/the-perfect-developer/the-perfect-opencode --skill python-flet

インストール後、Claude Code で/python-fletを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

examples/
counter-app.py
custom-control.py
references/
controls-and-layout.md
patterns-and-best-practices.md

詳細

Python Flet 開発

Flet は、フロントエンドの経験がなくても、クロスプラットフォームのウェブ、デスクトップ、モバイルアプリを構築できる Python フレームワークです。Flutter ウィジェットをラップし、Python コントロールとして公開します。

アプリのエントリーポイント

すべての Flet アプリには、ft.Page を受け取る main 関数があり、最後に ft.run(main) を呼び出します。

import flet as ft

def main(page: ft.Page):
    page.title = "My App"
    page.add(ft.Text("Hello, Flet!"))

ft.run(main)

インストール:pip install 'flet[all]'

デスクトップで実行:flet run main.py

ウェブで実行:flet run --web main.py

ホットリロード(ディレクトリを再帰的に監視):flet run --recursive main.py

プロジェクト構成

my-app/
├── pyproject.toml
└── src/
    ├── assets/
    │   └── icon.png
    └── main.py

次のコマンドで作成します:flet create(または uv run flet create)

基本概念

Page

ft.Page はルートコンテナーです。コントロールを追加する前に設定します。

def main(page: ft.Page):
    page.title = "App Title"
    page.theme_mode = ft.ThemeMode.LIGHT
    page.theme = ft.Theme(color_scheme_seed=ft.Colors.BLUE)
    page.vertical_alignment = ft.MainAxisAlignment.CENTER
    page.horizontal_alignment = ft.CrossAxisAlignment.CENTER
    page.scroll = ft.ScrollMode.AUTO
コントロールと update()

コントロールは Python オブジェクトです。変更を反映するには page.update() または control.update() が必要です。

text = ft.Text("Initial")
page.add(text)

def change(e):
    text.value = "Changed"
    text.update()          # prefer: update only this control
    # page.update()        # fallback: updates entire page

ルール:page.update() よりも control.update() を優先してください。より小さな差分を送信できます。

レイアウトコントロール
コントロール用途
ft.Column縦方向に積み重ねます
ft.Row横方向に並べます
ft.Stack絶対位置指定
ft.Containerパディング、色、枠線、アニメーションを設定できるボックス
ft.ListView効率的な縦方向/横方向のスクロール可能リスト
ft.GridView効率的なスクロール可能グリッド
page.add(
    ft.Row(
        controls=[ft.Text("Left"), ft.Text("Right")],
        alignment=ft.MainAxisAlignment.SPACE_BETWEEN,
    )
)

Expand:expand=True を指定すると、利用可能なスペースを埋めます。

ft.ListView(expand=True, spacing=10)

カスタムコントロール

スタイル付きコントロール(単一の Flet コントロールを継承)
@ft.control
class PrimaryButton(ft.Button):
    bgcolor: ft.Colors = ft.Colors.BLUE_700
    color: ft.Colors = ft.Colors.WHITE

@ft.control または @dataclass デコレーターを使用します。フィールドの型には注釈が必要です。

複合コントロール(複数のコントロールを組み合わせる)
@ft.control
class TaskItem(ft.Row):
    text: str = ""

    def init(self):
        self.checkbox = ft.Checkbox()
        self.label = ft.Text(value=self.text)
        self.controls = [self.checkbox, self.label]

    def toggle(self, e):
        self.label.color = ft.Colors.GREY if self.checkbox.value else None
        self.update()
ライフサイクルメソッド
メソッド呼び出されるタイミング用途
init()__init__ の後サブコントロールのセットアップ
build()self.page が割り当てられたときプラットフォームに応じたロジック
did_mount()ページに追加された後タイマーの開始、データの取得
will_unmount()削除される前クリーンアップ、タスクのキャンセル
before_update()update() のたび派生状態の同期

分離ルール:独自のメソッド内で self.update() を呼び出すカスタムコントロールでは、is_isolated = True を設定する必要があります(または is_isolated プロパティをオーバーライドして True を返します)。

ナビゲーションとルーティング

単一の信頼できる情報源として、page.on_route_change と page.views を使用します。

def main(page: ft.Page):
    def route_change():
        page.views.clear()
        page.views.append(ft.View("/", controls=[...]))
        if page.route == "/settings":
            page.views.append(ft.View("/settings", controls=[...]))
        page.update()

    async def view_pop(e):
        page.views.remove(e.view)
        await page.push_route(page.views[-1].route)

    page.on_route_change = route_change
    page.on_view_pop = view_pop
    route_change()

ft.run(main)

ナビゲート:await page.push_route("/settings")

パラメーター付きルート:

troute = ft.TemplateRoute(page.route)
if troute.match("/items/:id"):
    print(troute.id)

ルーティングのルール:

  • page.views 内にルート / のビューを常に保持します
  • すべてのルートロジックを page.on_route_change に集約します
  • 状態を同期させるため、常に page.on_view_pop を処理します

テーマ設定

# App-wide theme
page.theme = ft.Theme(color_scheme_seed=ft.Colors.GREEN)
page.dark_theme = ft.Theme(color_scheme_seed=ft.Colors.BLUE)
page.theme_mode = ft.ThemeMode.SYSTEM  # LIGHT | DARK | SYSTEM

# Nested theme (scoped to a container)
ft.Container(
    theme=ft.Theme(color_scheme=ft.ColorScheme(primary=ft.Colors.PINK)),
    content=ft.Button("Pink button"),
)

非同期アプリ

asyncio をサポートするには、main を async にします。time.sleep() ではなく asyncio.sleep() を使用します。

import asyncio
import flet as ft

async def main(page: ft.Page):
    async def on_click(e):
        await asyncio.sleep(1)
        page.add(ft.Text("Done!"))

    page.add(ft.Button("Click me", on_click=on_click))

ft.run(main)

did_mount() からバックグラウンドのコルーチンを実行するには、page.run_task(coro) を使用します。

パフォーマンス:大規模なリスト

数百件のアイテムを扱う場合は、Column/Row ではなく ListView または GridView を使用します。

# Efficient: renders only visible items
lv = ft.ListView(expand=True, spacing=10, item_extent=50)
for i in range(5000):
    lv.controls.append(ft.Text(f"Line {i}"))
page.add(lv)

# Batch updates to avoid large WebSocket messages
for i in range(5000):
    lv.controls.append(ft.Text(f"Line {i}"))
    if i % 500 == 0:
        page.update()
page.update()

暗黙的なアニメーション

コントロールの animate_* プロパティを設定して有効にします。

# Opacity fade
container = ft.Container(
    width=150, height=150,
    bgcolor=ft.Colors.BLUE,
    animate_opacity=300,  # ms
)

# Scale with bounce curve
ft.Container(
    animate_scale=ft.Animation(
        duration=600,
        curve=ft.AnimationCurve.BOUNCE_OUT,
    )
)

# Position animation (inside Stack or page.overlay)
ft.Container(animate_position=1000)

# Animated content switcher
ft.AnimatedSwitcher(
    content,
    transition=ft.AnimatedSwitcherTransition.SCALE,
    duration=500,
)

ウィンドウ制御(デスクトップ)

page.title = "My App"
page.window.width = 800
page.window.height = 600
page.window.resizable = True
page.window.always_on_top = False
page.window.center()

クイックリファレンス:よく使うコントロール

ft.Text("Hello", size=20, weight=ft.FontWeight.BOLD)
ft.Button("Click", on_click=handler)
ft.IconButton(ft.Icons.ADD, on_click=handler)
ft.TextField(label="Name", on_change=handler)
ft.Checkbox(label="Check me", on_change=handler)
ft.Dropdown(options=[ft.dropdown.Option("A"), ft.dropdown.Option("B")])
ft.Image(src="photo.jpg")                   # from assets/
ft.Image(src="https://example.com/img.png") # remote
ft.AppBar(title=ft.Text("Title"))
ft.NavigationDrawer(controls=[...])
ft.AlertDialog(title=ft.Text("Alert"), content=ft.Text("Body"))

追加リソース

リファレンスファイル
  • references/controls-and-layout.md - レイアウトパターン、Container のスタイル設定、Stack の位置指定、コントロールのプロパティを網羅しています
  • references/patterns-and-best-practices.md - 状態管理、セッション/クライアントストレージ、PubSub、キーボードショートカット、エラー処理
サンプルファイル
  • examples/counter-app.py - ページのセットアップとイベントハンドラーを示す、最小構成の動作するカウンター
  • examples/custom-control.py - ライフサイクルメソッドと分離を備えた複合カスタムコントロール

コメント