学校や塾などで時間割を作成するとき、先生ごとの「出勤可能な曜日や時間帯」の情報は欠かせません。
そこで今回は、PythonのTkinterを使って、GUIで簡単に先生の勤務可能スケジュールを登録し、CSVに保存するアプリを作ってみます!
💡 アプリの特徴
- 名前・科目・出勤可能な曜日と時限をGUIで入力
- 複数の曜日・時限をチェックボックスで選択可能
- CSVファイルに保存(再利用・分析が簡単)
- 簡単に拡張可能(一覧表示や編集機能など)
🖥 実行画面イメージ
1限 | 2限 | 3限 | 4限 | 5限 | |
---|---|---|---|---|---|
Monday | ✅ | ✅ | |||
Tuesday | ✅ | ✅ | ✅ | ||
… | … | … | … | … | … |
🧩 サンプルコード:teacher.py
import tkinter as tk
from tkinter import ttk, messagebox
import csv
import os
from PIL import ImageGrab
class TimetableApp:
def __init__(self, root):
self.root = root
self.root.title("時間割作成アプリ")
self.root.geometry("900x550")
self.font = ("Arial", 12)
self.csv_file = "timetable.csv"
self.days = ["月曜", "火曜", "水曜", "木曜", "金曜", "土曜"]
self.periods = ["1限", "2限", "3限", "4限", "5限", "6限"]
style = ttk.Style()
style.configure("TLabel", font=self.font)
style.configure("TButton", font=self.font)
style.configure("TEntry", font=self.font)
style.configure("TCombobox", font=self.font)
# 入力エリア
input_frame = ttk.Frame(root, padding=10)
input_frame.grid(row=0, column=0, sticky="ew", padx=10, pady=10)
# 1行目
ttk.Label(input_frame, text="曜日:").grid(row=0, column=0, padx=5, pady=2)
self.day_var = tk.StringVar()
self.day_combo = ttk.Combobox(input_frame, textvariable=self.day_var, values=self.days, state="readonly", width=10)
self.day_combo.grid(row=0, column=1, padx=5, pady=2)
self.day_combo.current(0)
ttk.Label(input_frame, text="限:").grid(row=0, column=2, padx=5, pady=2)
self.period_var = tk.StringVar()
self.period_combo = ttk.Combobox(input_frame, textvariable=self.period_var, values=self.periods, state="readonly", width=10)
self.period_combo.grid(row=0, column=3, padx=5, pady=2)
self.period_combo.current(0)
ttk.Label(input_frame, text="科目名:").grid(row=0, column=4, padx=5, pady=2)
self.subject_var = tk.StringVar()
self.subject_entry = ttk.Entry(input_frame, textvariable=self.subject_var, width=20)
self.subject_entry.grid(row=0, column=5, padx=5, pady=2)
self.add_button = ttk.Button(input_frame, text="追加", command=self.add_entry)
self.add_button.grid(row=0, column=6, padx=5, pady=2)
# 2行目
self.save_button = ttk.Button(input_frame, text="💾保存", command=self.save_data)
self.save_button.grid(row=1, column=0, padx=5, pady=2)
self.image_button = ttk.Button(input_frame, text="画像保存", command=self.save_as_image)
self.image_button.grid(row=1, column=1, padx=5, pady=2)
self.clear_button = ttk.Button(input_frame, text="初期化", command=self.clear_all)
self.clear_button.grid(row=1, column=2, padx=5, pady=2)
# 表エリア
self.table_frame = ttk.Frame(root)
self.table_frame.grid(row=1, column=0, sticky="nsew", padx=10, pady=10)
for i, day in enumerate([""] + self.days):
label = tk.Label(self.table_frame, text=day, font=self.font, bg="#d0eaff", relief="ridge", width=12)
label.grid(row=0, column=i, sticky="nsew", padx=1, pady=1)
for j, period in enumerate(self.periods):
label = tk.Label(self.table_frame, text=period, font=self.font, bg="#ffe1e1", relief="ridge", width=10)
label.grid(row=j+1, column=0, sticky="nsew", padx=1, pady=1)
self.cells = {}
for i, day in enumerate(self.days):
for j, period in enumerate(self.periods):
key = (day, period)
lbl = tk.Label(self.table_frame, text="", font=self.font, bg="#ffffff", relief="groove", width=12, height=2)
lbl.grid(row=j+1, column=i+1, sticky="nsew", padx=1, pady=1)
self.cells[key] = lbl
# 伸縮対応
root.grid_rowconfigure(1, weight=1)
root.grid_columnconfigure(0, weight=1)
for i in range(len(self.days)+1):
self.table_frame.grid_columnconfigure(i, weight=1)
for j in range(len(self.periods)+1):
self.table_frame.grid_rowconfigure(j, weight=1)
# 読み込み
self.load_data()
def add_entry(self):
day = self.day_var.get()
period = self.period_var.get()
subject = self.subject_var.get().strip()
if not subject:
messagebox.showwarning("入力エラー", "科目名を入力してください")
return
key = (day, period)
if key in self.cells:
self.cells[key].config(text=subject)
self.subject_var.set("")
def save_data(self):
try:
with open(self.csv_file, "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
for (day, period), label in self.cells.items():
text = label.cget("text")
if text:
writer.writerow([day, period, text])
messagebox.showinfo("保存完了", "時間割を保存しました!")
except Exception as e:
messagebox.showerror("保存エラー", str(e))
def load_data(self):
if os.path.exists(self.csv_file):
try:
with open(self.csv_file, newline="", encoding="utf-8") as f:
reader = csv.reader(f)
for row in reader:
if len(row) == 3:
day, period, subject = row
key = (day, period)
if key in self.cells:
self.cells[key].config(text=subject)
except Exception as e:
messagebox.showerror("読み込みエラー", str(e))
def save_as_image(self):
x = self.root.winfo_rootx()
y = self.root.winfo_rooty()
w = x + self.root.winfo_width()
h = y + self.root.winfo_height()
img = ImageGrab.grab(bbox=(x, y, w, h))
img.save("timetable.png")
messagebox.showinfo("保存完了", "時間割を画像(timetable.png)で保存しました!")
def clear_all(self):
answer = messagebox.askyesno("確認", "本当に時間割を初期化しますか?")
if answer:
for label in self.cells.values():
label.config(text="")
if os.path.exists(self.csv_file):
try:
os.remove(self.csv_file)
except Exception as e:
messagebox.showerror("エラー", f"ファイル削除に失敗しました:\n{e}")
messagebox.showinfo("初期化完了", "時間割を初期化しました。")
def main():
root = tk.Tk()
app = TimetableApp(root)
root.mainloop()
if __name__ == "__main__":
main()
📂 出力されるCSVの例
Name,Subject,AvailableSlots
Mr. Tanaka,Math,Monday-1|Monday-3|Tuesday-2
Ms. Sato,English,Wednesday-1|Wednesday-2|Friday-3
🚀 応用アイデア
- 一覧表示機能を追加して、登録済みの先生情報をGUIで確認
- 削除・編集機能をつけて、スケジュールの変更を簡単に
- 時間割自動生成アプリと連携し、先生のスケジュール制約を活用
まとめ
このアプリを使えば、学校や塾の先生の出勤情報を簡単にデータ化できます。
CSV保存なのでExcelやPythonの他のプログラムとも連携が容易!
Tkinterを使えば、Python初心者でも直感的に使えるアプリを作れるのが魅力ですね。