はじめに
本記事は、個人の学習目的で作成した Python デスクトップGUIアプリを題材に、
実装を通じて学んだ 設計・UI/UX・データ管理の考え方を整理したものです。
完成したアプリを紹介することが目的ではなく、
- なぜその設計を選んだのか
- どこで詰まり、どう割り切ったのか
- 次に同じものを作るなら何を意識するか
といった 判断のログを残すことを目的にまとめています。
(なお、記事作成にあたっては ChatGPT に構成整理の補助をしてもらっています)
GUIアプリに挑戦してみたい Python 学習者の方の参考になれば幸いです。
1. なぜ「いきなり高機能」にしなかったか
1.1 GUIアプリは最初の設計で8割決まる
GUIアプリを作り始めて強く感じたのは、
「最初の構成判断が、その後の難易度をほぼ決めてしまう」
という点でした。
最初はつい、
- 設定画面も欲しい
- 集計画面も欲しい
- グラフも出したい
と考えてしまいますが、これを最初からやると ほぼ確実に破綻します。
そこで今回は、最初に次の制約を置きました。
- 1画面で完結させる
- 「入力 → 保存 → 表示」の最小構成に絞る
- 拡張は「後から」前提で設計する
この制限を入れたことで、
「UIが増えすぎて何を直しているのかわからない」状態を避けられました。
※ パワーポイント等の資料作成と非常に近い感覚だと感じました。
1.2 機能を削ることで安定した点
意図的に やらなかったこと は多くあります。
- 期間集計(週・月)
- 自動推定・補正
- ネットワーク連携
- 複数ユーザー対応
代わりに優先したのは、次の点です。
- 入力が壊れないこと
- 保存・再読込が安定していること
- 画面を触っていてストレスがないこと
GUIアプリでは「機能がある」よりも
「触っていて事故らない」ことの方が圧倒的に重要だと実感しました。
機能はすぐに追加できますが、
ユーザーの信頼は簡単には積み上がらないと感じています。
2. PySide6でGUIを組むときの設計メモ
2.1 なぜ PySide6 を選んだか
Python の GUI には複数の選択肢がありますが、今回は PySide6 を選びました。
理由は以下の通りです。
- Qt の設計思想が明確
- Widget / Dialog / Model-View の分離がしやすい
- 将来 UI が増えても破綻しにくい
tkinter は軽量で扱いやすい反面、
規模が少し大きくなると「全部同じ場所に書く」構造になりがちでした。
今回は、最初から「分かれている前提」のフレームワークを選びました。
2.2 QWidget / QDialog / MainWindow の役割分担
意識したルールはとてもシンプルです。
-
MainWindow
- 画面全体の司令塔
- データの読み書きの入口
-
QWidget
- 再利用できる部品
- 表示ロジック中心
-
QDialog
- 設定・編集などの一時的な操作
「とりあえず MainWindow に全部書く」は
短期的には楽ですが、後からの修正が非常に困難になります。
「どこに書かないか」を決めることが重要だと感じました。
2.3 UIが壊れ始めるサイン
開発中に「危険だな」と感じたサインは次のようなものでした。
- signal / slot の接続が10個を超え始める
- 1つの関数が100行を超える
- UI変更のたびに別の挙動が壊れる
この状態になったら、
設計が悪いのではなく、分割が遅れている
と考えるようにしました。
「今は動いているからOK」は、GUIでは後で必ずツケが回ってきます。
3. GUIで「操作ミスを防ぐ」ためにやったこと
3.1 マウスホイール事故を防ぐ
GUIで意外と多いのが、マウスホイールによる誤操作です。
- テーブルをスクロールしたかった
- しかし ComboBox にフォーカスがあった
- 意図せず値が変わる
これを防ぐため、ComboBox のホイール操作を無効化しました。
小さな工夫ですが、「使っていて不安にならない」という点で
効果は非常に大きいと感じました。
3.2 時刻入力は必ず壊れる前提で設計する
時刻入力では、ほぼ確実に次の問題が起きます。
- フォーマット違い
- 開始 > 終了
- 入力途中の中途半端な値
そのため、
- UI側で必ずバリデーションする
- 不正な状態では保存できないようにする
- エラーは短く、具体的に表示する
という方針を取りました。
「ユーザーが間違える」のではなく、
そもそも間違いが発生しにくい設計を目指しました。
3.3 編集の連動処理でストレスを減らす
一方で、自動化しすぎると逆に使いにくくなります。
今回意識したのは、
- End を変更したら、次の行の Start を追従させる
- ただし、手入力していた場合は上書きしない
という 半自動 の考え方です。
完全自動は楽ですが、
「勝手に変わった」という不信感を生みやすい。
GUIでは 信頼感 > 自動化 だと感じました。
4. SQLiteを「軽量ローカルDB」として使う考え方
4.1 なぜファイル保存(pkl / JSON)ではなく SQLite にしたか
個人用アプリであれば、
pkl や JSON で保存する選択肢も十分に考えられました。
- 実装が簡単
- ファイル1つで完結
- 人が直接中身を確認できる
一方で、今回の用途では次の点が気になりました。
- データが増えると全件読み書きになる
- 部分更新がやりづらい
- 破損時の切り分けが難しい
そこで、「軽量だが構造を持つ保存先」として SQLite を選びました。
テーブルという「枠」があるだけで、
思考が整理される点は大きなメリットでした。
4.2 最小限のテーブル設計
最初に決めた原則は、
「データの性質が違うものは分ける」
ということです。
- 日々増える実績データ
- ほとんど変わらない設定データ
これらを同じ構造で扱うと、
後から必ず歪みが出ます。
そこで、
- 実績データ用テーブル
- カテゴリ(設定)用テーブル
を分けました。
この分離により、
- 表示順や有効/無効の管理
- 実績側ロジックの単純化
ができ、UI側の実装も読みやすくなりました。
4.3 SQLiteを使う上での注意点
今回はあえて、
その日のデータは保存時に全行置き換える
という方式を採用しました。
理由は以下の通りです。
- 編集単位が「1日」
- 差分管理を避けたい
- トランザクションを単純にしたい
この割り切りにより、
- 保存ロジックが簡潔になる
- 更新範囲を考えなくてよい
- UIとDBの責務が明確になる
というメリットがありました。
4.4 SQLite を使う上で意識した制約
SQLite は便利ですが、
サーバDBと同じ感覚で使うと事故りやすいとも感じました。
そこで、次の前提を自分に課しました。
- 同時書き込みを考えない
- 複数プロセスから触らない
- ロック競合を前提にしない
- 高頻度更新をしない
つまり、
「1人・1アプリ・短時間操作」
という前提を崩さない設計です。
5. 「継続して使われる」ことを意識したUI設計
5.1 技術的に正しいUIが、使われるとは限らない
GUIを作っていて強く感じたのは、
技術的に正しいUIと、
実際に使われ続けるUIは別物
という点です。
ウィジェットの配置や設計が正しくても、
- 毎回考えないと操作できない
- 触るたびに小さなストレスがある
- 「今日はいいか」と思われる
と、自然に使われなくなります。
「毎日開いてもらう」前提でUIを考えました。
5.2 情報は多いほど良い、はほぼ嘘
最初は、
- 合計
- 内訳
- 推移
- ランキング
などを全部出したくなります。
しかし、試してみてわかったのは、
情報が多いほど、行動が止まる
ということでした。
そこで意識的に削ったのは、
- 常時表示の数値
- 判断を要求する要素
- 「見なくても困らない」情報
代わりに残したのは、
- 今入力すべき場所
- 今日の合計
- 編集できる一覧
「見る」より「触る」を優先しました。
5.3 操作回数を減らすより、迷いを減らす
UI改善というと、
「クリック数を減らす」ことに目が行きがちです。
ただ、実際に効果が大きかったのは、
操作回数より、迷う回数を減らすこと
でした。
- ボタンの役割が一目でわかる
- 触っても壊れない安心感
- 失敗してもすぐ戻せる
この3点が揃うと、
多少操作が多くても継続されます。
5.4 自動化は「信用できる範囲」に留める
自動化は強力ですが、
やりすぎると逆効果になります。
例えば、
- 勝手に補正される
- 理由がわからない変更が起きる
- 元に戻せない
これらは 不信感の原因 になります。
そこで今回は、
- 意図が推測できる自動処理だけ入れる
- 予測できない変更はしない
- いつでも手で直せる状態を保つ
という方針を取りました。
「賢さ」より「納得感」 を優先しました。
5.5 初期状態の「空っぽ感」を大切にする
起動直後の画面は、
意外と見落とされがちです。
- 何も入っていない
- でも、何をすればいいかは分かる
この状態を目指しました。
具体的には、
- 空でも崩れないレイアウト
- 「まずここを入力する」視線誘導
- データがなくても意味がある表示
- 「何もない状態が不安にならない」
これが継続の第一歩でした。
5.6 達成感は数字ではなく行為で作る
達成感というと、
スコアやバッジを思い浮かべがちですが、
今回は入れませんでした。
理由は、
- 数値は比較を生む
- 比較は疲れを生む
- 疲れは離脱につながる
代わりに意識したのは、
- 入力が完了した感覚
- 合計が確定した安心感
- 「今日は終わった」と閉じられること
「行為の完了感」をUIの中で作ることを意識しました。
5.7 継続設計で一番大事だったこと
最終的に一番重要だと感じたのは、
UIは「使わせる道具」ではなく「邪魔をしない存在」であるべき
という考え方です。
- 覚えることが少なく、
- 考えることが少なく、
- 失敗しても怖くない。
そうしたUIは、結果的に長く使われます。
おわりに
本記事では、個人の学習目的で作成した Python デスクトップGUIアプリを題材に、
実装コードではなく「設計上の判断」を振り返ってきました。
振り返って強く感じたのは、
この取り組みの中心にあったのはフレームワークやAPIではなく、
- 何を先に決めたか
- 何をあえてやらなかったか
- どこで割り切ったか
という 意思決定の積み重ねだった、という点です。
GUIアプリ開発は、
技術力以上に 思考を整理する力 が問われます。
この記事が、
「作ったけれど続かなかった理由」を振り返るきっかけや、
これからGUIに挑戦する際の判断材料になれば幸いです。