はじめに
こんにちは!今回は、Pythonを使ってポモドーロタイマーを作成する過程を、要件定義から実装まで詳しく解説します。このプロジェクトを通じて、以下のスキルを身につけることができます:
- ソフトウェア開発のプロセス(要件定義、仕様策定、設計、実装)
- Pythonの基本的な構文とオブジェクト指向プログラミング
- Tkinterを使ったGUIアプリケーションの作成
- 時間管理の基本概念とその実装方法
それでは、プロジェクトの各段階を見ていきましょう。
1. 要件定義
まず、ポモドーロタイマーの基本的な要件を定義します。
1.1 機能要件
- 25分の作業時間を計測するタイマー機能
- 5分の短い休憩時間を計測するタイマー機能
- 15分の長い休憩時間を計測するタイマー機能(4回の作業セッション後)
- タイマーの開始、一時停止、再開、リセット機能
- 現在のフェーズ(作業、短い休憩、長い休憩)の表示
- 完了したポモドーロ(作業セッション)数の表示
- 現在のセッション数の表示(1/4, 2/4, 3/4, 4/4)
1.2 非機能要件
- ユーザーフレンドリーなインターフェース
- 視覚的にわかりやすいデザイン
- 操作が直感的で簡単であること
- プログラムの安定性と信頼性
2. 仕様策定
要件に基づいて、具体的な仕様を決定します。
2.1 タイマー仕様
- 作業時間: 25分
- 短い休憩時間: 5分
- 長い休憩時間: 15分
- タイマーは1秒ごとにカウントダウン
- 4回の作業セッション後に長い休憩
2.2 UI仕様
- ウィンドウサイズ: 適切なサイズ(例:400x300ピクセル)
- 表示要素:
- タイトル
- 現在の時間(分:秒)
- 現在のフェーズ表示
- セッション進捗表示
- 完了したポモドーロ数
- 操作ボタン:
- スタート
- 一時停止
- 再開
- リセット
- スキップ(現在のフェーズをスキップ)
2.3 デザイン仕様
- カラーパレット:
- 背景色: 暖かみのある色(例:#FFF8E1)
- メインカラー: ビビッドな色(例:オレンジ #FF5722)
- アクセントカラー: 補完的な色(例:ブルー #2196F3)
- フォント: 読みやすいサンセリフフォント(例:Helvetica)
3. 設計
仕様に基づいて、システムの設計を行います。
3.1 クラス設計
3.2 状態遷移設計
- アイドル状態
- 開始 → 実行中状態
- リセット → アイドル状態(初期化)
- 実行中状態
- 一時停止 → 一時停止状態
- 完了 → 次のフェーズのアイドル状態
- スキップ → 次のフェーズのアイドル状態
- 一時停止状態
- 再開 → 実行中状態
- リセット → アイドル状態
3.3 シーケンス図
4. 実装
設計に基づいて、Pythonコードを実装します。以下は主要な部分の実装例です。
import tkinter as tk
from enum import Enum
import math
class Phase(Enum):
WORK = 1
SHORT_BREAK = 2
LONG_BREAK = 3
class State(Enum):
IDLE = 1
RUNNING = 2
PAUSED = 3
class PomodoroTimer:
def __init__(self):
self.window = tk.Tk()
self.window.title("ポモドーロタイマー")
self.window.config(padx=20, pady=20, bg="#FFF8E1") # 背景色を暖かい色に設定
# 初期状態の設定
self.current_phase = Phase.WORK
self.state = State.IDLE
self.time_left = 0
self.pomodoros_completed = 0
self.current_session = 1
self.timer = None
self.setup_ui()
self.reset_timer()
def setup_ui(self):
# フォントとカラーの設定
TITLE_FONT = ("Helvetica", 28, "bold")
TIMER_FONT = ("Helvetica", 64, "bold")
LABEL_FONT = ("Helvetica", 18)
BUTTON_FONT = ("Helvetica", 14, "bold")
MAIN_COLOR = "#FF5722" # オレンジ
SECONDARY_COLOR = "#4CAF50" # グリーン
ACCENT_COLOR = "#2196F3" # ブルー
# タイトル
self.title_label = tk.Label(text="ポモドーロタイマー", fg=MAIN_COLOR, bg="#FFF8E1", font=TITLE_FONT)
self.title_label.grid(column=0, row=0, columnspan=4, pady=(0, 20))
# タイマー表示
self.timer_frame = tk.Frame(self.window, bg="#FFE0B2", bd=2, relief="raised")
self.timer_frame.grid(column=0, row=1, columnspan=4, pady=20, padx=20, sticky="nsew")
self.timer_label = tk.Label(self.timer_frame, text="25:00", fg=MAIN_COLOR, bg="#FFE0B2", font=TIMER_FONT)
self.timer_label.pack(pady=20)
# フェーズと進捗表示
self.info_frame = tk.Frame(self.window, bg="#FFF8E1")
self.info_frame.grid(column=0, row=2, columnspan=4, pady=10)
self.phase_label = tk.Label(self.info_frame, text="作業", fg=SECONDARY_COLOR, bg="#FFF8E1", font=LABEL_FONT)
self.phase_label.pack(side="left", padx=10)
self.session_label = tk.Label(self.info_frame, text="セッション: 1/4", fg=ACCENT_COLOR, bg="#FFF8E1", font=LABEL_FONT)
self.session_label.pack(side="left", padx=10)
# ボタン
self.button_frame = tk.Frame(self.window, bg="#FFF8E1")
self.button_frame.grid(column=0, row=3, columnspan=4, pady=20)
button_width = 10
button_height = 2
self.start_button = tk.Button(self.button_frame, text="開始", command=self.start_timer,
bg=SECONDARY_COLOR, fg="white", font=BUTTON_FONT,
width=button_width, height=button_height)
self.start_button.pack(side="left", padx=5)
self.pause_button = tk.Button(self.button_frame, text="一時停止", command=self.pause_timer,
bg=MAIN_COLOR, fg="white", font=BUTTON_FONT,
width=button_width, height=button_height, state=tk.DISABLED)
self.pause_button.pack(side="left", padx=5)
self.resume_button = tk.Button(self.button_frame, text="再開", command=self.resume_timer,
bg=ACCENT_COLOR, fg="white", font=BUTTON_FONT,
width=button_width, height=button_height, state=tk.DISABLED)
self.resume_button.pack(side="left", padx=5)
self.reset_button = tk.Button(self.button_frame, text="リセット", command=self.reset_timer,
bg="#607D8B", fg="white", font=BUTTON_FONT,
width=button_width, height=button_height)
self.reset_button.pack(side="left", padx=5)
# スキップボタン
self.skip_button = tk.Button(self.window, text="スキップ", command=self.skip_phase,
bg="#9C27B0", fg="white", font=BUTTON_FONT,
width=button_width, height=1, state=tk.DISABLED)
self.skip_button.grid(column=0, row=4, columnspan=4, pady=10)
# 完了したポモドーロ数
self.pomodoro_label = tk.Label(text="完了したポモドーロ: 0", fg=MAIN_COLOR, bg="#FFF8E1", font=LABEL_FONT)
self.pomodoro_label.grid(column=0, row=5, columnspan=4, pady=10)
def start_timer(self):
if self.state == State.IDLE:
self.state = State.RUNNING
self.start_button.config(state=tk.DISABLED)
self.pause_button.config(state=tk.NORMAL)
self.resume_button.config(state=tk.DISABLED)
self.skip_button.config(state=tk.NORMAL)
self.countdown()
def pause_timer(self):
if self.state == State.RUNNING:
self.state = State.PAUSED
self.pause_button.config(state=tk.DISABLED)
self.resume_button.config(state=tk.NORMAL)
if self.timer is not None:
self.window.after_cancel(self.timer)
self.timer = None
def resume_timer(self):
if self.state == State.PAUSED:
self.state = State.RUNNING
self.pause_button.config(state=tk.NORMAL)
self.resume_button.config(state=tk.DISABLED)
self.countdown()
def reset_timer(self):
if self.timer is not None:
self.window.after_cancel(self.timer)
self.timer = None
self.state = State.IDLE
self.current_phase = Phase.WORK
self.time_left = 25 * 60 # 25分
self.current_session = 1
self.update_timer_display()
self.update_phase_display()
self.start_button.config(state=tk.NORMAL)
self.pause_button.config(state=tk.DISABLED)
self.resume_button.config(state=tk.DISABLED)
self.skip_button.config(state=tk.DISABLED)
def skip_phase(self):
if self.timer is not None:
self.window.after_cancel(self.timer)
self.timer = None
self.next_phase()
def countdown(self):
if self.state == State.RUNNING:
if self.time_left > 0:
self.time_left -= 1
self.update_timer_display()
self.timer = self.window.after(1000, self.countdown)
else:
self.next_phase()
def next_phase(self):
if self.current_phase == Phase.WORK:
self.pomodoros_completed += 1
self.update_pomodoro_count()
if self.current_session % 4 == 0:
self.current_phase = Phase.LONG_BREAK
self.time_left = 15 * 60 # 15分
else:
self.current_phase = Phase.SHORT_BREAK
self.time_left = 5 * 60 # 5分
else:
self.current_phase = Phase.WORK
self.time_left = 25 * 60 # 25分
self.current_session += 1
self.update_phase_display()
self.update_timer_display()
self.state = State.IDLE
self.start_button.config(state=tk.NORMAL)
self.pause_button.config(state=tk.DISABLED)
self.resume_button.config(state=tk.DISABLED)
self.skip_button.config(state=tk.DISABLED)
def update_timer_display(self):
minutes, seconds = divmod(self.time_left, 60)
self.timer_label.config(text=f"{minutes:02d}:{seconds:02d}")
def update_phase_display(self):
if self.current_phase == Phase.WORK:
self.phase_label.config(text="作業", fg="#4CAF50")
elif self.current_phase == Phase.SHORT_BREAK:
self.phase_label.config(text="短い休憩", fg="#2196F3")
else:
self.phase_label.config(text="長い休憩", fg="#F44336")
self.session_label.config(text=f"セッション: {self.current_session}/4")
def update_pomodoro_count(self):
self.pomodoro_label.config(text=f"完了したポモドーロ: {self.pomodoros_completed}")
def run(self):
self.window.mainloop()
if __name__ == "__main__":
timer = PomodoroTimer()
timer.run()
5. 実装のポイント
ポモドーロタイマーの実装において、以下のポイントに特に注意を払いました:
-
クラスベースの設計
-
PomodoroTimer
クラスを中心に、アプリケーションの全機能をカプセル化しました。 - これにより、コードの再利用性と保守性が向上します。
-
-
状態管理の明確化
-
Phase
とState
の列挙型を使用して、タイマーのフェーズと状態を明確に定義しました。 - これにより、複雑な状態遷移を管理しやすくなります。
-
-
イベントドリブンプログラミング
- Tkinterのイベントシステムを活用し、ユーザーのアクションに応じて適切なメソッドを呼び出します。
- ボタンクリックなどのイベントと、それに対応するメソッドを明確に関連付けています。
-
非同期タイマーの実装
-
after
メソッドを使用して、非ブロッキングなタイマー機能を実現しています。 - これにより、UIの応答性を保ちながら、正確なタイミング管理が可能になります。
-
-
ユーザーインターフェースの動的更新
- タイマーの状態やフェーズの変更に応じて、UIを動的に更新します。
- ラベルやボタンの状態を適切に管理し、現在の状況を明確にユーザーに伝えます。
-
エラー処理とエッジケースの考慮
- タイマーの一時停止や再開、リセット時の処理を適切に実装し、予期せぬ動作を防止しています。
- 各メソッドで現在の状態をチェックし、不適切な操作を防いでいます。
-
モジュール化と関数の分離
- 各機能(開始、一時停止、再開、リセットなど)を別々のメソッドとして実装し、コードの可読性を向上させています。
- UI更新、タイマー制御、状態管理などの機能を明確に分離しています。
-
定数の活用
- 作業時間、休憩時間、色などの設定を定数として定義し、容易にカスタマイズできるようにしています。
-
Pythonの言語機能の活用
- f文字列を使用して、文字列フォーマットを簡潔に記述しています。
-
divmod
関数を使用して、秒を分と秒に効率的に変換しています。
-
UIデザインの考慮
- 色やフォントを適切に選択し、視覚的に魅力的なインターフェースを作成しています。
- ボタンのサイズや配置を工夫し、使いやすさを向上させています。
これらのポイントに注意を払うことで、機能的で保守性の高いポモドーロタイマーアプリケーションを実現しています。また、これらの実装技術は、他の類似のプロジェクトにも応用可能です。
まとめ
このポモドーロタイマープロジェクトを通じて、私たちは単なるタイマーアプリケーションの作成を超えて、ソフトウェア開発の包括的なプロセスを体験しました。以下に、このプロジェクトから得られる主要な学びと insights をまとめます:
-
統合的なソフトウェア開発プロセス
- 要件定義から実装まで、ソフトウェア開発の全段階を実践的に学びました。
- 各段階の重要性と相互関連性を理解することができました。
-
Pythonとオブジェクト指向プログラミングの実践
- Pythonの強力な機能(列挙型、f文字列、divmod関数など)を実際のプロジェクトで活用しました。
- クラスベースの設計を通じて、オブジェクト指向プログラミングの原則を適用しました。
-
GUIプログラミングの基礎
- Tkinterを使用して、実用的でユーザーフレンドリーなインターフェースを設計・実装しました。
- イベントドリブンプログラミングの概念を理解し、応用しました。
-
状態管理と非同期プログラミング
- 複雑な状態遷移を管理する技術を学びました。
- 非同期タイマーの実装を通じて、応答性の高いアプリケーション開発のテクニックを習得しました。
-
ソフトウェアアーキテクチャの重要性
- モジュール化、関数の分離、適切な定数の使用など、保守性の高いコード構造の重要性を理解しました。
-
実践的な問題解決スキル
- エラー処理やエッジケースの考慮など、実世界のアプリケーション開発で直面する課題に取り組みました。
このプロジェクトは、単にポモドーロタイマーを作るだけでなく、実践的なソフトウェア開発スキルを総合的に向上させる機会となりました。ここで学んだ技術と概念は、より複雑なアプリケーションの開発にも応用可能です。
今後の発展として、以下のような拡張が考えられます:
- タスク管理機能の追加
- ユーザー設定のカスタマイズ(作業時間、休憩時間の調整など)
- データの永続化(SQLiteなどのデータベースの使用)
- 統計情報の表示(生産性分析など)
- クロスプラットフォーム対応(Webアプリケーションやモバイルアプリへの展開)
このプロジェクトを基盤として、さらに機能を追加したり、異なるテクノロジーを探求したりすることで、ソフトウェア開発スキルを継続的に向上させることができるでしょう。
ポモドーロテクニックの実践と合わせて、このアプリケーションを日々の作業に活用し、生産性の向上を図ってください。そして、ここで得た知識と経験を、今後のプログラミング学習やプロジェクト開発に活かしていくことをお勧めします。
参考リソース
Happy coding!
コメント対応 : 実装
指摘事項、改善の内容はコメント欄を参照ください。
import tkinter as tk
from tkinter import ttk, messagebox
from enum import Enum
class Time:
SECONDS = 1
MINUTES = 60 * SECONDS
class Phase(Enum):
WORK = 1
SHORT_BREAK = 2
LONG_BREAK = 3
class State(Enum):
IDLE = 1
RUNNING = 2
PAUSED = 3
class PomodoroTimer:
def __init__(self):
self.window = tk.Tk()
self.window.title("ポモドーロタイマー")
self.window.config(padx=20, pady=20, bg="#FFF8E1")
self.settings = {
"work_time": 25,
"short_break_time": 5,
"long_break_time": 15,
"phases_in_session": 4
}
self.current_phase = Phase.WORK
self.state = State.IDLE
self.time_left = 0
self.pomodoros_completed = 0
self.current_session = 1
self.timer = None
self.setup_ui()
self.reset_timer()
def setup_ui(self):
# フォントとカラーの設定
TITLE_FONT = ("Helvetica", 28, "bold")
TIMER_FONT = ("Helvetica", 64, "bold")
LABEL_FONT = ("Helvetica", 18)
BUTTON_FONT = ("Helvetica", 14, "bold")
MAIN_COLOR = "#FF5722" # オレンジ
SECONDARY_COLOR = "#4CAF50" # グリーン
ACCENT_COLOR = "#2196F3" # ブルー
# タイトル
self.title_label = tk.Label(text="ポモドーロタイマー", fg=MAIN_COLOR, bg="#FFF8E1", font=TITLE_FONT)
self.title_label.grid(column=0, row=0, columnspan=4, pady=(0, 20))
# タイマー表示
self.timer_frame = tk.Frame(self.window, bg="#FFE0B2", bd=2, relief="raised")
self.timer_frame.grid(column=0, row=1, columnspan=4, pady=20, padx=20, sticky="nsew")
self.timer_label = tk.Label(self.timer_frame, text="25:00", fg=MAIN_COLOR, bg="#FFE0B2", font=TIMER_FONT)
self.timer_label.pack(pady=20)
# フェーズと進捗表示
self.info_frame = tk.Frame(self.window, bg="#FFF8E1")
self.info_frame.grid(column=0, row=2, columnspan=4, pady=10)
self.phase_label = tk.Label(self.info_frame, text="作業", fg=SECONDARY_COLOR, bg="#FFF8E1", font=LABEL_FONT)
self.phase_label.pack(side="left", padx=10)
self.session_label = tk.Label(self.info_frame, text=f"セッション: 1/{self.settings['phases_in_session']}", fg=ACCENT_COLOR, bg="#FFF8E1", font=LABEL_FONT)
self.session_label.pack(side="left", padx=10)
# ボタン
self.button_frame = tk.Frame(self.window, bg="#FFF8E1")
self.button_frame.grid(column=0, row=3, columnspan=4, pady=20)
button_width = 10
button_height = 2
self.start_button = tk.Button(self.button_frame, text="開始", command=self.start_timer,
bg=SECONDARY_COLOR, fg="white", font=BUTTON_FONT,
width=button_width, height=button_height)
self.start_button.pack(side="left", padx=5)
self.pause_button = tk.Button(self.button_frame, text="一時停止", command=self.pause_timer,
bg=MAIN_COLOR, fg="white", font=BUTTON_FONT,
width=button_width, height=button_height, state=tk.DISABLED)
self.pause_button.pack(side="left", padx=5)
self.resume_button = tk.Button(self.button_frame, text="再開", command=self.resume_timer,
bg=ACCENT_COLOR, fg="white", font=BUTTON_FONT,
width=button_width, height=button_height, state=tk.DISABLED)
self.resume_button.pack(side="left", padx=5)
self.reset_button = tk.Button(self.button_frame, text="リセット", command=self.reset_timer,
bg="#607D8B", fg="white", font=BUTTON_FONT,
width=button_width, height=button_height)
self.reset_button.pack(side="left", padx=5)
# スキップボタン
self.skip_button = tk.Button(self.window, text="スキップ", command=self.skip_phase,
bg="#9C27B0", fg="white", font=BUTTON_FONT,
width=button_width, height=1, state=tk.DISABLED)
self.skip_button.grid(column=0, row=4, columnspan=4, pady=10)
# 完了したポモドーロ数
self.pomodoro_label = tk.Label(text="完了したポモドーロ: 0", fg=MAIN_COLOR, bg="#FFF8E1", font=LABEL_FONT)
self.pomodoro_label.grid(column=0, row=5, columnspan=4, pady=10)
# 設定ボタン
self.settings_button = tk.Button(self.window, text="設定", command=self.open_settings,
bg="#607D8B", fg="white", font=BUTTON_FONT,
width=button_width, height=1)
self.settings_button.grid(column=0, row=6, columnspan=4, pady=10)
def open_settings(self):
settings_window = tk.Toplevel(self.window)
settings_window.title("タイマー設定")
settings_window.config(padx=20, pady=20, bg="#FFF8E1")
# メイン画面をモーダルにする
settings_window.grab_set()
settings_window.transient(self.window)
settings_window.focus_set()
ttk.Label(settings_window, text="作業時間 (分):").grid(column=0, row=0, padx=5, pady=5, sticky="e")
work_time = ttk.Entry(settings_window)
work_time.insert(0, str(self.settings["work_time"]))
work_time.grid(column=1, row=0, padx=5, pady=5)
ttk.Label(settings_window, text="短い休憩時間 (分):").grid(column=0, row=1, padx=5, pady=5, sticky="e")
short_break = ttk.Entry(settings_window)
short_break.insert(0, str(self.settings["short_break_time"]))
short_break.grid(column=1, row=1, padx=5, pady=5)
ttk.Label(settings_window, text="長い休憩時間 (分):").grid(column=0, row=2, padx=5, pady=5, sticky="e")
long_break = ttk.Entry(settings_window)
long_break.insert(0, str(self.settings["long_break_time"]))
long_break.grid(column=1, row=2, padx=5, pady=5)
ttk.Label(settings_window, text="セッション内のフェーズ数:").grid(column=0, row=3, padx=5, pady=5, sticky="e")
phases = ttk.Entry(settings_window)
phases.insert(0, str(self.settings["phases_in_session"]))
phases.grid(column=1, row=3, padx=5, pady=5)
def save_settings():
try:
self.settings["work_time"] = int(work_time.get())
self.settings["short_break_time"] = int(short_break.get())
self.settings["long_break_time"] = int(long_break.get())
self.settings["phases_in_session"] = int(phases.get())
self.reset_timer()
settings_window.destroy()
except ValueError:
messagebox.showerror("エラー", "すべての値は整数である必要があります。")
save_button = ttk.Button(settings_window, text="保存", command=save_settings)
save_button.grid(column=0, row=4, columnspan=2, pady=10)
# ウィンドウが閉じられたときに、grab_release を呼び出す
settings_window.protocol("WM_DELETE_WINDOW", lambda: [settings_window.grab_release(), settings_window.destroy()])
def start_timer(self):
if self.state == State.IDLE:
self.state = State.RUNNING
self.start_button.config(state=tk.DISABLED)
self.pause_button.config(state=tk.NORMAL)
self.resume_button.config(state=tk.DISABLED)
self.skip_button.config(state=tk.NORMAL)
self.countdown()
def pause_timer(self):
if self.state == State.RUNNING:
self.state = State.PAUSED
self.pause_button.config(state=tk.DISABLED)
self.resume_button.config(state=tk.NORMAL)
if self.timer is not None:
self.window.after_cancel(self.timer)
self.timer = None
def resume_timer(self):
if self.state == State.PAUSED:
self.state = State.RUNNING
self.pause_button.config(state=tk.NORMAL)
self.resume_button.config(state=tk.DISABLED)
self.countdown()
def reset_timer(self):
if self.timer is not None:
self.window.after_cancel(self.timer)
self.timer = None
self.state = State.IDLE
self.current_phase = Phase.WORK
self.time_left = self.settings["work_time"] * Time.MINUTES
self.current_session = 1
self.update_timer_display()
self.update_phase_display()
self.start_button.config(state=tk.NORMAL)
self.pause_button.config(state=tk.DISABLED)
self.resume_button.config(state=tk.DISABLED)
self.skip_button.config(state=tk.DISABLED)
def skip_phase(self):
if self.timer is not None:
self.window.after_cancel(self.timer)
self.timer = None
self.next_phase()
def countdown(self):
if self.state == State.RUNNING:
if self.time_left > 0:
self.time_left -= 1
self.update_timer_display()
self.timer = self.window.after(1000, self.countdown)
else:
self.next_phase()
def next_phase(self):
if self.current_phase == Phase.WORK:
self.pomodoros_completed += 1
self.update_pomodoro_count()
self.current_session += 1
if self.current_session > self.settings["phases_in_session"]:
# すべてのセッションが終了した場合
self.current_session = 1
self.current_phase = Phase.LONG_BREAK
self.time_left = self.settings["long_break_time"] * Time.MINUTES
elif self.current_session == self.settings["phases_in_session"]:
# 最後のセッションの場合
self.current_phase = Phase.SHORT_BREAK
self.time_left = self.settings["short_break_time"] * Time.MINUTES
else:
# 通常のセッションの場合
self.current_phase = Phase.SHORT_BREAK
self.time_left = self.settings["short_break_time"] * Time.MINUTES
else:
# 休憩フェーズが終了した場合
self.current_phase = Phase.WORK
self.time_left = self.settings["work_time"] * Time.MINUTES
self.update_phase_display()
self.update_timer_display()
self.state = State.IDLE
self.start_button.config(state=tk.NORMAL)
self.pause_button.config(state=tk.DISABLED)
self.resume_button.config(state=tk.DISABLED)
self.skip_button.config(state=tk.DISABLED)
def update_phase_display(self):
if self.current_phase == Phase.WORK:
self.phase_label.config(text="作業", fg="#4CAF50")
elif self.current_phase == Phase.SHORT_BREAK:
self.phase_label.config(text="短い休憩", fg="#2196F3")
else:
self.phase_label.config(text="長い休憩", fg="#F44336")
self.session_label.config(text=f"セッション: {self.current_session}/{self.settings['phases_in_session']}")
def update_timer_display(self):
minutes, seconds = divmod(self.time_left, 60)
self.timer_label.config(text=f"{minutes:02d}:{seconds:02d}")
def update_phase_display(self):
if self.current_phase == Phase.WORK:
self.phase_label.config(text="作業", fg="#4CAF50")
elif self.current_phase == Phase.SHORT_BREAK:
self.phase_label.config(text="短い休憩", fg="#2196F3")
else:
self.phase_label.config(text="長い休憩", fg="#F44336")
current_session_display = min(self.current_session, self.settings['phases_in_session']) # セッション表示の上限を設定
self.session_label.config(text=f"セッション: {current_session_display}/{self.settings['phases_in_session']}")
def update_pomodoro_count(self):
self.pomodoro_label.config(text=f"完了したポモドーロ: {self.pomodoros_completed}")
def run(self):
self.window.mainloop()
if __name__ == "__main__":
timer = PomodoroTimer()
timer.run()
このポモドーロタイマーアプリでは、「設定」ボタンをクリックすることで、タイマーの詳細設定を変更できます。設定画面では以下の項目をカスタマイズ可能です:
作業時間(分)
短い休憩時間(分)
長い休憩時間(分)
セッション内のフェーズ数
これらの設定を調整することで、ユーザーは自分の作業スタイルに合わせてポモドーロテクニックを最適化できます。変更後は「保存」ボタンをクリックして設定を反映させます。