# 실습 CRUD 가이드: Python과 Tkinter로 할 일 관리자 만들기
CRUD(Create, Read, Update, Delete)는 데이터 작업의 핵심 패턴입니다. 이 가이드에서는 Python, Tkinter, JSON 데이터 저장을 사용해 데스크톱 할 일 관리자를 직접 만들어보며 실습합니다. OOP 기초, 파일 처리, GUI 개발을 다지기 딱 좋은 프로젝트입니다.
앱 구조와 환경 설정
앱은 단일 app.py 파일로 구성합니다. 데이터 저장은 JSON을 사용해 간단하게 구현합니다. 각 할 일은 id(고유 식별자), text(설명), completed(완료 상태)를 가진 딕셔너리입니다. 모든 할 일은 리스트에 저장되며 tasks.json으로 직렬화됩니다.
Python 3.6 이상이 설치되어 있는지 확인하세요. Tkinter는 기본 내장되어 있어 별도 설치가 필요 없습니다. 새 프로젝트 폴더를 만들고 IDE에서 엽니다.
데이터 모델과 JSON 처리
먼저 Read와 Update CRUD 작업의 기반이 되는 데이터 로드/저장 함수를 구현합니다.
import json
import os
TASKS_FILE = "tasks.json"
def load_tasks():
"""JSON 파일에서 할 일 로드."""
if not os.path.exists(TASKS_FILE):
return []
with open(TASKS_FILE, "r", encoding="utf-8") as f:
try:
return json.load(f)
except json.JSONDecodeError:
return []
def save_tasks(tasks):
"""할 일 리스트를 JSON 파일에 저장."""
with open(TASKS_FILE, "w", encoding="utf-8") as f:
json.dump(tasks, f, ensure_ascii=False, indent=2)
def get_next_id(tasks):
"""새 할 일의 다음 고유 ID 생성."""
if not tasks:
return 1
return max(task["id"] for task in tasks) + 1
주요 특징:
load_tasks는 파일 누락이나 손상 시 안전하게 처리합니다.json.dump의ensure_ascii=False로 유니코드 제대로 지원합니다.indent=2로 JSON 가독성 높입니다.
Tkinter로 GUI 구축
메인 윈도우와 위젯을 관리하는 TodoApp 클래스를 만듭니다. 인터페이스는 다음과 같습니다:
- 새 할 일 입력 필드.
- 모든 할 일 표시 리스트박스.
- 제어 버튼: 추가, 완료 표시, 삭제.
import tkinter as tk
from tkinter import messagebox
class TodoApp:
def __init__(self, root):
self.root = root
self.root.title("할 일 관리자")
self.root.geometry("500x400")
self.root.resizable(False, False)
self.tasks = load_tasks()
self.create_widgets()
self.refresh_task_list()
def create_widgets(self):
"""모든 UI 요소 설정."""
# 상단 패널: 입력과 추가 버튼
top_frame = tk.Frame(self.root)
top_frame.pack(pady=10, padx=10, fill=tk.X)
self.entry = tk.Entry(top_frame, font=("Arial", 12))
self.entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 5))
self.entry.bind("<Return>", lambda event: self.add_task())
self.add_button = tk.Button(top_frame, text="➕ 추가", command=self.add_task)
self.add_button.pack(side=tk.RIGHT)
# 할 일 리스트와 스크롤바
list_frame = tk.Frame(self.root)
list_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
scrollbar = tk.Scrollbar(list_frame)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
self.task_listbox = tk.Listbox(
list_frame,
font=("Arial", 11),
yscrollcommand=scrollbar.set,
selectmode=tk.SINGLE,
height=15
)
self.task_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
scrollbar.config(command=self.task_listbox.yview)
# 하단 패널: 동작 버튼
bottom_frame = tk.Frame(self.root)
bottom_frame.pack(pady=10, padx=10, fill=tk.X)
self.done_button = tk.Button(bottom_frame, text="✅ 완료", command=self.mark_done)
self.done_button.pack(side=tk.LEFT, padx=5)
self.delete_button = tk.Button(bottom_frame, text="🗑 삭제", command=self.delete_task)
self.delete_button.pack(side=tk.LEFT, padx=5)
self.exit_button = tk.Button(bottom_frame, text="종료", command=self.root.quit)
self.exit_button.pack(side=tk.RIGHT, padx=5)
def refresh_task_list(self):
"""할 일 리스트 표시 새로고침."""
self.task_listbox.delete(0, tk.END)
for task in self.tasks:
status = "✓" if task["completed"] else "○"
display_text = f"{status} {task['id']}. {task['text']}"
self.task_listbox.insert(tk.END, display_text)
refresh_task_list는 Read 작업을 처리하며 현재 데이터 상태를 보여줍니다. 체크 표시(✓/○)로 완료 상태를 시각화합니다.
CRUD 작업 구현
클래스에 사용자 동작 메서드를 추가합니다. 각 메서드는 CRUD 작업과 연결됩니다.
Create: 새 할 일 추가
def add_task(self):
"""새 할 일 추가(Create)."""
text = self.entry.get().strip()
if not text:
messagebox.showwarning("경고", "할 일 내용을 입력하세요")
return
next_id = get_next_id(self.tasks)
new_task = {
"id": next_id,
"text": text,
"completed": False
}
self.tasks.append(new_task)
save_tasks(self.tasks)
self.entry.delete(0, tk.END)
self.refresh_task_list()
messagebox.showinfo("성공", f"할 일 추가됨 (ID: {next_id})")
Update: 할 일 완료 표시
def mark_done(self):
"""선택한 할 일 완료 표시(Update)."""
selection = self.task_listbox.curselection()
if not selection:
messagebox.showwarning("경고", "할 일을 선택하세요")
return
index = selection[0]
task_id = self.tasks[index]["id"]
for task in self.tasks:
if task["id"] == task_id:
if task["completed"]:
messagebox.showinfo("알림", "이미 완료된 할 일입니다")
else:
task["completed"] = True
save_tasks(self.tasks)
self.refresh_task_list()
messagebox.showinfo("성공", f"할 일 #{task_id} 완료로 표시됨")
return
Delete: 할 일 삭제
def delete_task(self):
"""선택한 할 일 삭제(Delete)."""
selection = self.task_listbox.curselection()
if not selection:
messagebox.showwarning("경고", "할 일을 선택하세요")
return
index = selection[0]
task_id = self.tasks[index]["id"]
task_text = self.tasks[index]["text"]
if messagebox.askyesno("확인", f"할 일 #{task_id} \"{task_text}\"을 삭제하시겠습니까?"):
del self.tasks[index]
save_tasks(self.tasks)
self.refresh_task_list()
messagebox.showinfo("성공", f"할 일 #{task_id} 삭제됨")
각 메서드는 입력 검증, 메모리 내 데이터 업데이트, 파일 저장, UI 새로고침을 수행합니다. 메시지박스로 사용자에게 명확한 피드백을 줍니다.
앱 조립 및 실행
모든 것을 하나의 파일에 모으고 메인 진입점을 추가합니다.
if __name__ == "__main__":
root = tk.Tk()
app = TodoApp(root)
root.mainloop()
python app.py로 실행하세요. 모든 CRUD 작업을 테스트해보세요—앱은 세션 간 tasks.json에 데이터를 저장합니다.
주요 요점
- CRUD 기초: Create, Read, Update, Delete는 대부분의 데이터 중심 앱 동력입니다.
- JSON 저장: 작은 프로젝트에 이상적—데이터베이스 불필요.
- Tkinter GUI: 의존성 없이 빠른 크로스플랫폼 데스크톱 UI.
- 깔끔한 코드 구조: 데이터 모델(JSON), 뷰(Tkinter), 로직(TodoApp) 분리로 유지보수 용이.
- 에러 처리: 입력 검증과 JSON 오류 등 문제 포착.
다음 단계
할 일 관리자를 확장해보세요:
- 할 일 카테고리와 필터링.
datetime사용 마감일과 색상 구분.- CSV나 Excel 내보내기.
- 데이터베이스 연동 (SQLite, PostgreSQL).
- 웹 버전 Flask나 Django로.
이 프로젝트는 핵심 프로그래밍 개념이 실제 앱에 어떻게 적용되는지 보여주며, 고급 주제의 튼튼한 기반을 마련합니다.
— Editorial Team
아직 댓글이 없습니다.