Widgetとは何か
Widgetは、独立して動く小さなUIの部品のことだ。ボタン、入力欄、リスト、カード、時計、グラフ——一つ一つが自分の状態と見た目を持ち、他から切り離しても動く。
大きなアプリは、Widgetを組み合わせて作る。階層的に重ねて、全体を構成する。ReactのComponent、Flutterの Widget、VueのComponent、FletのControl——呼び方は違っても、考え方は共通だ。
この章では、小さな時計アプリを題材に、Widgetアーキテクチャを体得する。コードそのものはClaudeが書く。あなたが身につけるのは、設計の考え方とClaudeへの指示の仕方だ。
第一節 題材:シンプルなダッシュボード
作るのは次のようなアプリだ。
+-------------------------------+
| 時計(13:42:30) |
+-------------------------------+
| 今日の予定(3件) |
| - 10:00 ミーティング |
| - 14:00 資料提出 |
| - 18:00 夕食 |
+-------------------------------+
| 天気(晴れ、18°C) |
+-------------------------------+
三つのWidgetが積み重なる構造。各Widgetは独立して動き、それぞれ別のデータ源を持つ。
使う言語とフレームワーク
本書の推奨は Python + Flet(Flutter ベース、Python から扱える)。 Dart / Flutter の準備が要らず、最短で動く。
Python のパッケージ管理は uv を使う(第 16 章で詳述)。pip + venv
の組み合わせよりも 10〜100 倍速く、プロジェクトの再現性が高い。
requirements.txt の代わりに pyproject.toml + uv.lock を使う。
# uv を入れる(初回のみ)
curl -LsSf https://astral.sh/uv/install.sh | sh
# プロジェクト作成 + Flet 追加
mkdir ~/Projects/my-dashboard && cd ~/Projects/my-dashboard
uv init
uv add flet
これで pyproject.toml、uv.lock、.venv/ が自動で作られる。
別の PC に持っていく時は git clone && uv sync の 2 行で完全再現 できる。
第二節 Widgetに分割する
設計の第一歩
書き始める前に、どのWidgetに分けるかを決める。
- ClockWidget:現在時刻を1秒ごとに更新
- ScheduleWidget:今日の予定を表示
- WeatherWidget:現在の天気を表示
- DashboardApp:上の三つを並べる親
分けるときの原則:
- 一つのWidgetは、一つの関心事しか持たない(時計は時計、天気は天気)
- Widget間で直接データをやり取りしない(親経由でのみ渡す)
- Widgetは外から使うAPIを最小限にする(初期化と更新だけ)
Claudeに聞いてみよう①:Widget分割の相談
Fletで、時計・予定・天気を並べたダッシュボードアプリを作ります。 次の三つのWidgetに分けようと思います:
- ClockWidget:時刻を1秒ごとに更新
- ScheduleWidget:その日の予定リスト
- WeatherWidget:現在の天気
この分割は妥当か、改善案があるか、教えてください。 各Widgetの責務(何を知り、何を表示し、外とどう通信するか)を表にしてください。
Claudeとの往復で、設計を固める。この段階ではコードは書かない。設計だけで30分〜1時間使う価値がある。
第三節 一つ目のWidget:時計
Claudeに書かせる指示
最初のWidgetをClaudeに書かせる。
Flet で ClockWidget を書いてください。
要件:
- 現在時刻を
HH:MM:SS形式で表示- 1秒ごとに更新
- 文字は大きく、中央揃え
- 独立したクラスとして実装(main関数とは分離)
コード全体を一ファイルで。実行するとClockWidget 単独で動くサンプルも添えてください。 Python 3.11以上、Flet 最新版で動くことを前提に。
Claudeが返したコードを読む。全部理解できなくてよい。次の三点だけ確認する。
- クラスの名前が
ClockWidgetになっているか - 時刻を更新するロジックがクラスの中にあるか
- main関数でそのクラスを使うサンプルが動きそうか
実行してみる
cd ~/Projects/my-dashboard
# Claudeのコードを clock_widget.py として保存
python3 clock_widget.py
ウィンドウが開いて、時計が動けば成功。動かなければ、エラーをそのままClaudeに貼って聞く。
Claudeに聞いてみよう②:エラー対応
次のコードを実行したところ、エラーが出ました:
〔コード〕〔エラーメッセージ全文〕原因と修正方法を教えてください。修正後のコード全文を示してください。
第四節 Widget同士の組み合わせ
親 Widget を作る
三つのWidgetを並べる親を作る。
ClockWidget、ScheduleWidget、WeatherWidget の三つを縦に並べて表示する DashboardApp を書いてください。 各Widgetは既に別ファイル(clock_widget.py, schedule_widget.py, weather_widget.py)にあるとします。
要件:
- 各Widgetは独立したクラス
- DashboardAppはそれらを import して配置するだけ
- 画面サイズはウィンドウ幅に追従
- 縦スクロール可能
これがWidgetアーキテクチャの核:親は子を配置するだけ。子の中身には口を出さない。
ScheduleWidgetとWeatherWidget
同じ流れで、残り二つもClaudeに書かせる。Scheduleは一旦ハードコードした予定を表示、Weatherはダミーデータで始める。
大事なのは:最初は動く最小版を作って、その後で本物のデータに繋ぐ。いきなり外部APIに繋ぐと、デバッグが大変になる。
第五節 状態管理の入り口
Widget 内部の状態
ClockWidgetは「現在時刻」という状態を持つ。Flet では次のように扱う。
# Claudeに書かせた例(概念)
class ClockWidget(ft.UserControl):
def build(self):
self.time_text = ft.Text(size=48)
return self.time_text
def did_mount(self):
# 1秒ごとに更新するタイマーを開始
...
親から子にデータを渡す
WeatherWidget に「地名」を親から渡したいとき。
class WeatherWidget(ft.UserControl):
def __init__(self, city: str):
super().__init__()
self.city = city
親が WeatherWidget(city="Tokyo") のように初期化する。
Claudeに聞いてみよう③:状態管理の質問
Fletでの状態管理について教えてください: (1) Widget内部で持つべき状態(時計の現在時刻、天気の最新データ) (2) 親から子に渡すべきもの(表示地名、テーマ色) (3) 親子を跨ぐ状態の扱い(複数Widgetが共有する設定)
初心者向けの単純な方針を、ダッシュボードアプリの例で示してください。 過度に複雑な状態管理ライブラリは避けてください。
第六節 見た目を整える
色、フォント、余白
一旦動いたら、見た目を整える。Claudeに指示する。
現在のDashboardAppの見た目を、次の原則で整えてください:
- ダークテーマ(背景 #1a1a1a、前景 #e0e0e0)
- 各Widget間の余白 16px
- 角丸のカード風 (border_radius=12)
- 時計は大きめ(72pt)、他は中くらい
- 日本語対応フォント(Noto Sans JP)
コード全体を書き換えるのではなく、スタイルをまとめた定数セクションを追加してください。
見た目を整える過程で、コードの読みやすさも上がる。色や大きさを定数にまとめる設計は、後の変更を楽にする。
第七節 Widget の再利用
応用:タイマーWidget
ClockWidgetができたので、同じ構造で「カウントダウンタイマー」も作れる。
ClockWidgetと同じ構造で、指定した分数をカウントダウンするTimerWidgetを作ってください。 共通できる部分があれば、基底クラス BaseTimeWidget を作って両方を派生させてください。
ここでコードの共通化が起きる。同じ構造のWidgetが複数あるとき、共通部分をまとめる——これがソフトウェアの成長の仕方だ。
重要な禁じ手
共通化をやりすぎない。最初から抽象化すると、後の変更が難しくなる。
- 2回同じコードが出たら:まだコピペ
- 3回目に出たら:共通化を検討
- 4回以上出る予感:共通化する
この感覚は、Claudeに相談しながら身につける。
Claudeに聞いてみよう④:過剰設計の回避
私は Widget を作っています。今、ClockWidget と TimerWidget で似たコードが出てきました。 次のどれが今の段階で適切ですか: (1) そのまま二つの独立したWidgetで置いておく (2) 共通部分を関数に抽出する (3) 基底クラス BaseTimeWidget を作って派生させる (4) イベントドリブンなアーキテクチャに作り変える
現状のコード〔貼る〕と、今後の見通し〔Claude対話UIも作るかも〕を踏まえて判断してください。
第八節 この章で学んだ「考え方」
コード以上に、次の考え方が残れば成功だ。
- 書き始める前に分割を決める。 Widgetに分ける境界が、そのまま設計の品質になる
- まず動く最小版を。 機能を足すのは後。最初は空のカードでもいい
- 親は子を配置するだけ。 子の中身に口を出さない
- 状態は持つWidgetの中に閉じる。 親子を跨いで状態を引き回さない
- 共通化は3回目から。 早すぎる抽象化はバグの温床
これは Web、モバイル、GUI、全てに共通する。Python/Fletから入ったが、考え方は React や Flutter にも直接転用できる。
まとめ
この章でやったこと:
- 小さなダッシュボードアプリを題材に選んだ
- Widget分割の設計をClaudeと議論した
- 一つずつWidgetを Claude に書かせ、動かした
- 親に組み上げて、全体像を作った
- 状態管理の最小構成を身につけた
- 見た目を整え、再利用(共通化)の感覚を掴んだ
手元に残ったもの:
- 動作するダッシュボードアプリ(Python/Flet)
- Widget分割の設計メモ
- 「小さく作って組み合わせる」という考え方
次の第15章では、Claude Code を使って、このアプリをもっと実用的な形に育てる実践に入る。実データへの接続、エラー処理、テスト、ビルドと配布——本格的なアプリ開発の最初の一周を体験する。
シリーズ全体はClaudeと一緒に学ぶDebian 一覧から辿れる。コメント・議論は Facebook グループへ:AISeed — 生物多様性・食料・AIと暮らし