iT邦幫忙

2025 iThome 鐵人賽

DAY 30
0
Software Development

軟體開發養成計畫:以小程式實作深化開發能力系列 第 30

[Day30]時間的印記:Python日曆記事工具與我的30天旅程

  • 分享至 

  • xImage
  •  

開場

三十天前,我只是一位單純想挑戰自己、想透過程式實作磨練邏輯的學習者。如今,這段旅程來到了最後一篇。
我決定用一個「能記錄生活的工具」作為結尾 —— 一個簡單的 Python 日曆記事小程式
它不只是程式,更像是這30天挑戰的象徵:用程式整理時間,用學習記錄成長

1.日曆記事程式碼

接下來是實作流程 + 對應程式碼:

(1)建立主要結構

import tkinter as tk
from tkinter import ttk, messagebox, simpledialog
import calendar, datetime, json, os

class CalendarApp:
    def __init__(self, root):
        self.root = root
        self.root.title("記事日曆")
        self.root.geometry("600x500")

        self.today = datetime.date.today()
        self.current_year = self.today.year
        self.current_month = self.today.month

        self.events = self.load_events()

        self.create_widgets()
        self.update_calendar()

  • 新增 calendar_app.py
  • import tkinter, calendar, datetime, json, os
  • 建立 CalendarApp 類別:
    • 初始化主視窗 (Tk())
    • 設定 title、geometry
    • 建立主框架(包含標題列、日曆格子、記事區)

(2)載入與儲存記事資料(JSON)

    def load_events(self):
        if os.path.exists("events.json"):
            with open("events.json", "r", encoding="utf-8") as f:
                return json.load(f)
        return {}

    def save_events(self):
        with open("events.json", "w", encoding="utf-8") as f:
            json.dump(self.events, f, ensure_ascii=False, indent=2)
  • init 時嘗試讀取 events.json
  • 沒有檔案就建立空的 {}
  • 當使用者新增 / 編輯事件後即自動呼叫 save_events()

(3)顯示當月日曆

    def create_widgets(self):
        header = tk.Frame(self.root)
        header.pack(pady=10)

        tk.Button(header, text="< 上個月", command=self.prev_month).pack(side=tk.LEFT, padx=10)
        self.title_label = tk.Label(header, text="", font=("Arial", 16))
        self.title_label.pack(side=tk.LEFT)
        tk.Button(header, text="下個月 >", command=self.next_month).pack(side=tk.LEFT, padx=10)

        self.calendar_frame = tk.Frame(self.root)
        self.calendar_frame.pack()

        self.event_list = tk.Listbox(self.root, height=8)
        self.event_list.pack(fill="x", padx=10, pady=10)

        tk.Button(self.root, text="新增 / 編輯記事", command=self.add_event).pack(pady=5)

    def update_calendar(self):
        for widget in self.calendar_frame.winfo_children():
            widget.destroy()

        self.title_label.config(text=f"{self.current_year} 年 {self.current_month} 月")

        cal = calendar.monthcalendar(self.current_year, self.current_month)
        for week in cal:
            row = tk.Frame(self.calendar_frame)
            row.pack()
            for day in week:
                if day == 0:
                    tk.Label(row, text=" ", width=6, height=2).pack(side=tk.LEFT)
                else:
                    btn = tk.Button(row, text=str(day), width=6, height=2,
                                    command=lambda d=day: self.show_events(d))
                    btn.pack(side=tk.LEFT, padx=1, pady=1)

  • 使用 calendar.monthcalendar(year, month) 取得週結構
  • 建立 7x6 格的 Button,顯示日期
  • 點擊日期 → 呼叫 show_events(day)

(4)點擊日期顯示記事清單

    def show_events(self, day):
        date_str = f"{self.current_year}-{self.current_month:02d}-{day:02d}"
        self.event_list.delete(0, tk.END)
        if date_str in self.events:
            for item in self.events[date_str]:
                self.event_list.insert(tk.END, f"• {item}")
        else:
            self.event_list.insert(tk.END, "(無記事)")
        self.selected_date = date_str
  • 右側或下方建立 Listbox 顯示選定日期的事件
  • 提供「新增 / 編輯 / 刪除」按鈕

(5)新增 / 編輯記事內容

    def add_event(self):
        if not hasattr(self, 'selected_date'):
            messagebox.showinfo("提示", "請先選擇日期")
            return

        new_event = simpledialog.askstring("新增 / 編輯記事", f"為 {self.selected_date} 新增記事:")
        if new_event:
            self.events.setdefault(self.selected_date, []).append(new_event)
            self.save_events()
            self.show_events(int(self.selected_date.split("-")[2]))
  • 彈出新視窗 (Toplevel)
  • 使用 Entry 或 Text 讓使用者輸入內容
  • 按「儲存」後更新 events[date_str] 並 save_events()
  • 重新刷新日曆顯示

(6)上 / 下個月切換

    def prev_month(self):
        if self.current_month == 1:
            self.current_month = 12
            self.current_year -= 1
        else:
            self.current_month -= 1
        self.update_calendar()

    def next_month(self):
        if self.current_month == 12:
            self.current_month = 1
            self.current_year += 1
        else:
            self.current_month += 1
        self.update_calendar()
  • 「< 上個月」與「下個月 >」按鈕
  • 按下後更新 self.current_month、self.current_year
  • 呼叫 update_calendar() 重新繪製按鈕

(7)自訂顏色與主題

使用 ttk.Style() 變更主題,例如:

        style = ttk.Style()
        style.theme_use('clam')
        style.configure('TButton', background='#4e73df', foreground='white', font=('Arial', 10))

(8)每日提醒通知

        today_str = self.today.strftime("%Y-%m-%d")
        if today_str in self.events:
            messagebox.showinfo("今日提醒", f"今日有 {len(self.events[today_str])} 項記事!")
  • 啟動程式時檢查「今天日期」是否有事件,則使用 tkinter.messagebox.showinfo() 提醒使用者今日記事

(9)主程式執行

if __name__ == "__main__":
    root = tk.Tk()
    app = CalendarApp(root)
    root.mainloop()

2.日曆記事成果展現

(1)"新增"功能

點選想記事的日期,接著點選"新增"按鈕

https://ithelp.ithome.com.tw/upload/images/20251006/20178527zWOaEoyzwa.jpg

在清單內輸入想新增的內容

https://ithelp.ithome.com.tw/upload/images/20251006/20178527hwgIoqjVcp.jpg

有記事內容的日期會加上星號

https://ithelp.ithome.com.tw/upload/images/20251006/20178527N6Xox9A1Et.jpg

(2)"修改"功能

點選想編輯的日期,接著點選"修改"按鈕,就可以直接修改內容了

https://ithelp.ithome.com.tw/upload/images/20251006/20178527J7YNZImkZE.jpg

(3)"刪除"功能

點選想編輯的日期,接著點選"刪除"按鈕,整天的記事內容就會被刪除了

https://ithelp.ithome.com.tw/upload/images/20251006/201785278HaxE3fzIi.jpg


30天學習回顧與心得總結

30天主題歷程

回顧這30天的主題歷程,我這一個月的學習內容,主要分為四個類別:基礎篇、應用篇、工具篇、趨勢篇

基礎篇:從程式思維到動手實作

這類的學習中,是這階段奠定了我整個鐵人賽的根基,從軟體開發流程出發,學會如何選擇合適的工具、理解開發模型,並逐步透過簡單的 Python 小專案強化邏輯與語法,也開始接觸 GUI 介面,從文字邏輯跨入互動式應用

應用篇:從程式邏輯到架構設計

在這階段,我不再只是寫程式,而是開始理解「程式如何組成一個完整的系統」。
從設計模式(MVC、Factory、Observer)到 JSON / API 串接,逐步打開對軟體架構的視野,掌握資料交換與邏輯分層;同時透過遊戲與工具開發,強化實作能力

工具篇:從開發者到工程師的進化

這部分的重點是「讓程式更穩、更完整」。
寫出功能之外,還開始考慮「版本控管、效能優化、錯誤處理」等軟體品質問題。
從單純寫功能到能進行專案維護與版本控管,慢慢邁入「軟體工程思維」的層次。

趨勢篇:AI × 開發的未來

在最後階段,除了完成程式外,也開始思考「程式的未來」。
AI 與軟體測試、自動化開發、智能應用的結合,是每個新時代工程師都該關注的議題。理解 AI 如何輔助開發流程,並開始思考「人與程式的共創關係」—— 讓技術真正走進生活

收穫與感想

鐵人賽的這三十天,說長不長,說短不短,卻是我自開始學習軟體開發以來,最專注於設計自己小程式的一段時光。今天回顧整個過程,會有種看著自己一步步成長的感覺。原本只是想開發幾個簡單程式作為練習,沒想到隨著練習的深入,我累積了更多心得:除了實作程式外,我還學會了各種開發工具與技巧,並透過摸索與思考,對軟體開發這個領域有了更多認識——這是平常課堂中難以學到的寶貴經驗。每一個小程式,不只是練習,更是我成長的痕跡。

這三十天讓我深刻感受到,只要持續動手、持續反思,就能一步步提升程式能力與專案思維。而這次 IT 鐵人賽的結束,並不是學習的終點,反而成了督促自己每日進步的契機。相信每一位參與的朋友也都付出了努力,也期待未來能繼續與賽友們一起奮鬥、一起成長。下一屆鐵人賽,我們再見囉!

三十天,從第一行 print() 到完整的 GUI 工具,
我用程式紀錄了挑戰、紀錄了生活,也紀錄了自己成長的軌跡。
如果說鐵人賽是一場馬拉松,那我最大的收穫,不是作品本身,而是——
「我真的堅持下來了」。

這不是結束,而是我下一段學習旅程的起點。


上一篇
[Day29]AI 與自動化測試的未來:TDD 新思維下的軟體品質革命
系列文
軟體開發養成計畫:以小程式實作深化開發能力30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言