Yohey's Slow Living

Take a break, have a cup of coffee, and have a nice day.

Python Practice Project #12: 電卓付きカレンダーアプリ(CLI → GUI)

今回は電卓付きカレンダーアプリ。

入力した基準日から、X日後を計算する。

GUI化の勉強も引き続きしたかったので、FletでGUI化。

また、モジュールの扱いも学びたかったので、関数をモジュール化して、それをメインのところでインポートし、使うようにしてみた。


#Day 12: 電卓付きカレンダーアプリ(CLI → GUI)

# === imports ===
import flet as ft
from datetime import datetime, timedelta
#moduleのimport
from input_handler import get_user_input, parse_date_input
from calculator import date_calculation
from result_display import print_result

# === Helper / Background functions ===

# === App Logics ===
def main_gui(page: ft.Page):
    page.title = "Calendar with calculator"
    #入力値を保持するための変数(関数内で共有)
    app_state = {"base_date": None, "days_offset": None, "calculation_result": None}

    theme_switch = ft.Switch(label="Light", value=True)
    def toggle_theme_switch(e):
        if theme_switch.value:
            page.theme_mode = ft.ThemeMode.LIGHT
        else:
            page.theme_mode = ft.ThemeMode.DARK
        page.update()
    toggle_theme_switch(None)
    theme_switch.on_change = toggle_theme_switch

#日付入力欄の処理
    def handle_submit(e):
        try:
            base_date = parse_date_input(e.control.value)
            app_state["base_date"] = base_date #app_stateにbase_dateの値を保存
            page.controls.append(ft.Text(f"Valid date: {base_date}"))
        except ValueError:
            page.controls.append(ft.Text("Invalid date format. Please use yyyy-mm-dd."))
    date_input_field = get_user_input(handle_submit)
    #page.controls.append(date_input_field)
    page.update()

#日数入力欄の処理
    def handle_days_submit(e):
        try:
            days = int(e.control.value)
            app_state["days_offset"] = days
            offset_days_text.value = f"Offset Days: {days}"
            #page.controls.append(ft.Text(f"Offset Days: {days}"))
        except ValueError:
            page.controls.append(ft.Text("Please enter a valid number."))
        page.update()

#計算ボタン処理
    def handle_calculation(e):
        if app_state["base_date"] is None or app_state["days_offset"] is None:
            page.controls.append(ft.Text("Please input a date first."))
        else:
            result = date_calculation(app_state["base_date"], app_state["days_offset"])
            result_text.value = f"New date: {result.date()} ({result.strftime('%A')})"
            #page.controls.append(ft.Text(f"New date: {result.date()} ({result.strftime('%A')})"))
        page.update()

    def quit_app():
        exit()

# === UI Components ===
    result_text = ft.Text(value="", color="green")
    #user_input_button = ft.ElevatedButton(text="Input", on_click=get_user_input) ###日付入力欄で直接GUIに組み込んでいるので、不要
    days_input_field = ft.TextField(label="Enter how many days before / after:", on_submit=handle_days_submit)
    calc_button = ft.ElevatedButton(text="Calculate", on_click=handle_calculation)
    offset_days_text = ft.Text(value="", color="blue")
    #result_button = ft.ElevatedButton(text="Show Result", on_click=print_result)
    quit_app_button = ft.ElevatedButton(text="Quit", on_click=quit_app)

# === User Interface ===
    page.add(
        theme_switch,
        date_input_field,
        #user_input_button,
        days_input_field,
        calc_button,
        result_text,
        offset_days_text,
        #result_button,
        quit_app_button
    )

# === Run App ===
ft.app(target=main_gui)

 

モジュール一覧


#calculator.py
from datetime import timedelta

def date_calculation(base_date, new_days_offset):
    return base_date + timedelta(days = new_days_offset)

 


#input_handler.py
from datetime import datetime
import flet as ft #ModuleでFletを使うのでimportする必要あり

def get_user_input(on_submit_handler):
    return ft.TextField(
        label="Enter a date (yyyy-mm-dd)",
        hint_text="2025-01-01",
        on_submit=on_submit_handler
    )

def parse_date_input(date_str: str):
    return datetime.strptime(date_str, "%Y-%m-%d")

 

まだまだ多くのことを学ぶ必要があるなあ、と思い知るところではあるけれど、何かを作るということと、学ぶことの楽しさがある。

引き続き勉強を続けていこうと思う次第である。