カレンダー表示アプリ
月のカレンダーをグリッド表示し前後月へ移動できるアプリ。calendarモジュールの活用方法を学びます。
1. アプリ概要
月のカレンダーをグリッド表示し前後月へ移動できるアプリ。calendarモジュールの活用方法を学びます。
このアプリはツールカテゴリに分類される実践的なGUIアプリです。使用ライブラリは tkinter(標準ライブラリ) で、難易度は ★★☆ です。
このアプリは「ツール」カテゴリです。日々の作業を自動化する実用ツールは Python が最も得意とする領域です。短いコードで実用性のある成果物が作れる点が魅力です。tkinter(標準ライブラリ) を活かして実装するこの構造は、他のアプリにも応用が効きます。
完成形を見てから細部の解説に進む流れが効果的です。実行→気になる箇所を解説で確認→自分の手で改造、というサイクルで定着が早まります。
カスタマイズ章では具体的な拡張アイデアを示しています。一つ実装するごとに動作確認することで、変更が予期せぬ副作用を起こさないかも体感できます。
2. 機能一覧
- 「◀」ボタン(
prev_month())・「▶」ボタン(next_month())・「今月」ボタン(goto_today())で操作 - ウィンドウはタイトル「カレンダー表示アプリ」・サイズ 420x360 で起動
3. 事前準備・環境
Python 3.10 以上 / Windows 11(実機)で起動・基本操作を確認 / Linux Mint 22.3(仮想マシン)で起動・画面表示を確認(macOS は未検証)
Windows 11(実機)で起動と基本操作を確認しています(全機能の網羅テストではありません)。Linux Mint 22.3(仮想マシン)では起動と画面表示を確認しました。macOS は標準ライブラリの範囲で動作する想定ですが、未検証です。
- Python 3.10 以上
- OS: Windows 11(実機で起動・基本操作を確認)・Linux Mint 22.3(仮想マシンで起動・画面表示を確認)
4. 完全なソースコード
右上の「コピー」ボタンをクリックするとコードをクリップボードにコピーできます。
import tkinter as tk
from tkinter import ttk
import calendar
from datetime import date
class App18:
"""カレンダー表示アプリ"""
def __init__(self, root):
self.root = root
self.root.title("カレンダー表示アプリ")
self.root.geometry("420x360")
self.root.configure(bg="#f8f9fc")
today = date.today()
self.year = today.year
self.month = today.month
self._build_ui()
self._draw_calendar()
def _build_ui(self):
title_frame = tk.Frame(self.root, bg="#3776ab", pady=12)
title_frame.pack(fill=tk.X)
tk.Label(title_frame, text="カレンダー",
font=("Noto Sans JP", 16, "bold"),
bg="#3776ab", fg="white").pack()
nav_frame = tk.Frame(self.root, bg="#f8f9fc", pady=8)
nav_frame.pack(fill=tk.X, padx=16)
ttk.Button(nav_frame, text="◀", width=3, command=self.prev_month).pack(side=tk.LEFT)
self.month_label = tk.Label(nav_frame, text="", font=("Noto Sans JP", 14, "bold"),
bg="#f8f9fc", width=16, anchor="center")
self.month_label.pack(side=tk.LEFT, expand=True)
ttk.Button(nav_frame, text="▶", width=3, command=self.next_month).pack(side=tk.RIGHT)
ttk.Button(nav_frame, text="今月", width=5, command=self.goto_today).pack(side=tk.RIGHT, padx=4)
self.cal_frame = tk.Frame(self.root, bg="#f8f9fc")
self.cal_frame.pack(fill=tk.BOTH, expand=True, padx=16, pady=(0, 12))
def _draw_calendar(self):
for w in self.cal_frame.winfo_children():
w.destroy()
self.month_label.config(text=f"{self.year}年 {self.month}月")
cal = calendar.monthcalendar(self.year, self.month)
today = date.today()
headers = ["月", "火", "水", "木", "金", "土", "日"]
for col, h in enumerate(headers):
color = "#e74c3c" if h == "日" else "#3776ab" if h == "土" else "#555"
tk.Label(self.cal_frame, text=h, font=("Noto Sans JP", 11, "bold"),
bg="#f8f9fc", fg=color, width=4).grid(row=0, column=col, pady=(0, 4))
for row, week in enumerate(cal):
for col, day in enumerate(week):
if day == 0:
tk.Label(self.cal_frame, text="", bg="#f8f9fc", width=4).grid(
row=row + 1, column=col)
continue
is_today = (day == today.day and self.month == today.month
and self.year == today.year)
fg = "#e74c3c" if col == 6 else "#3776ab" if col == 5 else "#222"
bg = "#3776ab" if is_today else "#f8f9fc"
text_fg = "white" if is_today else fg
lbl = tk.Label(self.cal_frame, text=str(day),
font=("Noto Sans JP", 11, "bold" if is_today else "normal"),
bg=bg, fg=text_fg, width=4, relief="flat",
padx=2, pady=2)
lbl.grid(row=row + 1, column=col, padx=1, pady=1)
def prev_month(self):
if self.month == 1:
self.month = 12
self.year -= 1
else:
self.month -= 1
self._draw_calendar()
def next_month(self):
if self.month == 12:
self.month = 1
self.year += 1
else:
self.month += 1
self._draw_calendar()
def goto_today(self):
today = date.today()
self.year = today.year
self.month = today.month
self._draw_calendar()
if __name__ == "__main__":
root = tk.Tk()
app = App18(root)
root.mainloop()
5. コード解説
カレンダー表示アプリのコードを、実際に書かれている実装に沿って解説します。
クラス設計とコンストラクタ
App18 クラスにアプリの全機能をまとめています(メソッド6個・全99行)。__init__ ではタイトル「カレンダー表示アプリ」とウィンドウサイズ 420x360 を設定します。そのあと _build_ui() → _draw_calendar() の順に呼び出して初期状態を作ります。
※ 該当部分のコード本体は 「4. 完全なソースコード」 をご参照ください(重複表示を避けるため再掲を省略しています)。
ウィジェット構成
画面は tk.Frame×3・tk.Label×2(ほかにループでも生成)・ttk.Button×3 で構成しています。
※ 該当部分のコード本体は 「4. 完全なソースコード」 をご参照ください(重複表示を避けるため再掲を省略しています)。
イベント処理とボタンの接続
「◀」ボタン(prev_month())・「▶」ボタン(next_month())・「今月」ボタン(goto_today())を command= で接続しています。
※ 該当部分のコード本体は 「4. 完全なソースコード」 をご参照ください(重複表示を避けるため再掲を省略しています)。
例外処理を書いていない理由
このコードには try-except による例外処理がありません。テキスト入力欄がなくボタン操作だけで完結し、ファイルやネットワークへのアクセスも無い設計のため、例外を投げうる処理(型変換・ファイル/通信)がそもそも無いからです。入力欄やファイル保存を追加する改造をするときは、例外処理もセットで検討しましょう。
※ 該当部分のコード本体は 「4. 完全なソースコード」 をご参照ください(重複表示を避けるため再掲を省略しています)。
6. ステップバイステップガイド
このアプリをゼロから自分で作る手順を解説します。コードをコピーするだけでなく、実際に手順を追って自分で書いてみましょう。
-
1ファイルを作成する
新しいファイルを作成して app18.py と保存します。使うのは
calendar・datetime・tkinterだけなので、追加インストールは不要です。 -
2クラスの骨格を作る
App18クラスを定義し、__init__と、末尾のroot = tk.Tk()~mainloop()の最小構成を書いて、まず空のウィンドウが出ることを確認します。 -
3ウィンドウを設定する
title("カレンダー表示アプリ")・geometry("420x360")・configure(bg="#f8f9fc")をコンストラクタで設定します。 -
4画面部品を並べる
_build_ui()の中で、tk.Frame×3・tk.Label×2(ほかにループでも生成)・ttk.Button×3 を作って配置します(掲載コードと同じ並び順で書くとレイアウトが一致します)。まず表示だけ確認しましょう。 -
5イベントを接続する
「2. 機能一覧」で挙げた各ボタンを
command=で対応するメソッド(prev_month()・next_month()・goto_today())につなぎます。 -
6中心になるメソッドを実装する
アプリの本体である
prev_month()(7行)・next_month()(7行)・goto_today()(5行) を実装します。 -
7動作確認する
python app18.pyで起動し、各ボタンが反応することを確認します。
7. カスタマイズアイデア
基本機能を習得したら、以下のカスタマイズに挑戦してみましょう。少しずつ機能を追加することで、Pythonのスキルが飛躍的に向上します。
💡 ダークモードを追加する
bg色・fg色を辞書で管理し、ボタン1つでダークモード・ライトモードを切り替えられるようにしましょう。
💡 結果をファイルに保存する
このコードに保存処理はないため、表示中の数値や結果はアプリを閉じると消えます。テキストファイルへ書き出して、次回起動時に読み込む機能を追加してみましょう。
💡 配色をまとめて管理する
背景色 #f8f9fc をはじめ、色コードが各所に直書きされています。色を1つの辞書にまとめると、テーマの切り替えが1か所の変更で済むようになります。
8. よくある問題と解決法
❌ 文字のフォントが崩れる・見た目が違う
原因:このコードは font=("Noto Sans JP", ...) のようにフォント名を直接指定しています。環境にこのフォントが入っていないと、OS が代わりのフォントで表示するため、見本と見た目が変わることがあります。
解決法:動作には支障ありません。気になる場合は font 引数の名前を自分の OS に入っているフォントへ書き換えるか、font 引数を省略してください。
❌ ウィンドウの大きさが画面に合わない
原因:geometry("420x360") の固定サイズで起動するためです。
解決法:この数値を書き換えて起動サイズを調整してください。なお、このコードにはウィンドウサイズを固定する設定(resizable の指定)が無いため、ウィンドウの端をドラッグしたサイズ変更は既定どおり可能です。
9. 練習問題
アプリの理解を深めるための練習問題です。気になるものから挑戦してみてください(課題3は全アプリ共通の定型課題です)。
-
課題1:週番号を左端に表示する
各週の行の左端に、その週がその年の第何週かを表示します。曜日と日付の列は1つ右へずらしてください。
期待結果:◀ ▶ で 2026年9月 に合わせると、行の左端に上から 36 / 37 / 38 / 39 / 40 と並ぶ。
合格条件
- 曜日の見出し(月〜日)と日付の列がそろっている
- 土曜が青・日曜が赤・今日が青背景という今の色分けが変わらない
- 前月・翌月へ移動しても週番号が正しく付け替わる
ヒント①(どこを触るか): 触るのは
_draw_calendar()だけです。column=colと書いているのは3か所(曜日見出し・空白セル・日付セル)で、この3つをcolumn=col + 1にしてから行頭にラベルを足します。
ヒント②(使うもの): 週番号はdate(self.year, self.month, 日).isocalendar()[1]で取得可能です。dateは4行目で読み込み済みで、その週の日付はweekリストに入っています。
つまずきやすい点: 色を決めているcol == 6(日曜)とcol == 5(土曜)の判定はcolのままで正しいので、書き換えないでください。weekには 0(前月・翌月の空き)が混ざるため、0 以外の日を選んで週番号を計算します。 -
課題2:年と月を指定して移動できるようにする
◀ ▶ で1か月ずつ動かす代わりに、年と月を直接指定して移動できるようにします。範囲外の月を入れたときは警告を出し、表示は変えないでください。
期待結果:年に 2030・月に 12 と入れて「移動」を押すと、2030年 12月 のカレンダーになる。
合格条件
- 月に 13 や 0 を入れても落ちず、表示はそのまま
- 数字以外の文字を入れても落ちない
- 移動したあとに「今月」を押すと今月へ戻る
ヒント①(どこを触るか): 入力欄と「移動」ボタンは
_build_ui()のnav_frame(「今月」ボタンが並ぶ場所)に足します。移動の処理はself.yearとself.monthを書き換えてself._draw_calendar()を呼ぶ新しいメソッドにします。
ヒント②(使うもの): 入力欄はttk.Spinbox(nav_frame, from_=1, to=12, width=3)が手軽です。範囲外や数字以外はtry/except ValueErrorで受け止め、messagebox.showwarning()で知らせます。
つまずきやすい点:messageboxはこのコードでは読み込んでいないので、from tkinter import messageboxの追加が必要です。calendar.monthcalendar()に 13 を渡すとIllegalMonthError(ValueErrorの一種)になります。 -
課題3:キー操作に対応させる
ボタンから呼んでいる
prev_month()を、キーボードのキーからも呼べるようにしてみましょう。tkinter では bind を使ってキーイベントとメソッドを結び付けられます。
写経中に赤いエラー文が出たら、Pythonエラー一覧&解決法(英語メッセージ逆引き)で原因と直し方をすぐ確認できます。
写経しながら「なぜこう書くのか」が気になり始めたら、入門書を1冊通して読むと断片的な知識がつながります。Python入門書のおすすめ2冊(当サイトの参考書ランキング総合1〜2位)で、独学者向けの最初の1冊を比較しています。