Search

μ•ŒλžŒ ν”„λ‘œκ·Έλž¨

μ•ŒλžŒ ν”„λ‘œκ·Έλž¨ - GPTxPython

μ„€λͺ…

ν”„λ‘œκ·Έλž¨

ν”„λ‘¬ν”„νŠΈ

페λ₯΄μ†Œλ‚˜ - 파이썬 ν”„λ‘œκ·Έλž˜λ° ν•™μŠ΅μž μž‘μ—… - μ•ŒλžŒ ν”„λ‘œκ·Έλž¨ 개발 λ§₯락 - μ–Έμ–΄ : 파이썬 - 버전 : 3.13 - ꡬ쑰 : GUI ν”„λ‘œκ·Έλž¨ - κΈ°λŠ₯ * 닀쀑 μ•ŒλžŒ 관리 ν”„λ‘œκ·Έλž¨ * μ €μž₯된 μ•ŒλžŒ λͺ©λ‘ 확인 * MySQL λ°μ΄ν„°λ² μ΄μŠ€λ‘œ μ•ŒλžŒ 정보 관리 * μ•ŒλžŒ 정보 관리 : μ•ŒλžŒ 이름 λ³€κ²½, μ•ŒλžŒ μ†Œλ¦¬ λ³€κ²½, μ•ŒλžŒ λ‚ μ§œ μ‹œκ°„ λ³€κ²½ * μ•ŒλžŒ 관리 λŒ€μ‹œλ³΄λ“œ : λ“±λ‘λœ μ•ŒλžŒ 리슀트둜 확인, μˆ˜μ • μ‚­μ œ μ•„μ΄μ½˜ λ²„νŠΌμœΌλ‘œ 관리 * μ•ŒλžŒ 리슀트의 μΉ΄λ“œ 클릭 μ‹œ μˆ˜μ •ν™”λ©΄μœΌλ‘œ 이동 * μ•ŒλžŒ μˆ˜μ • ν™”λ©΄ : 이름, μ†Œλ¦¬, λ‚ μ§œμ‹œκ°„ λ³€κ²½ * DB 접속 μ‹œ alarm ν…Œμ΄λΈ” 생성 * κΈ°λ³Έ μ•ŒλžŒ μ†Œλ¦¬λŠ” c:/alarm/ ν΄λ”μ—μ„œ 선택 * 졜초 μ•ŒλžŒ μ†Œλ¦¬λŠ” c:/alaram/κΈ°λ³Έ.mp3 ν˜•μ‹ - μ•ŒλžŒ μ‹œκ°„ 도달 μ‹œ, μœˆλ„μš° notification μ•Œλ¦ΌμœΌλ‘œ μ•ŒλžŒ 이름과 μ‹œκ°„ 좜λ ₯ - μ§€μ •ν•œ μ•ŒλžŒ μ†Œλ¦¬λ₯Ό μ•ŒλžŒλ„κΈ° λ²„νŠΌ 클릭 μ „κΉŒμ§€ 반볡 μž¬μƒ μ•ŒλžŒ mp3 파일의 μž¬μƒμ‹œκ°„μ„ ν™•μΈν•˜μ—¬ ν•œ λ²ˆμ— μž¬μƒμ΄ λŠλ‚œ λ’€ λ‹€μŒ μž¬μƒ 반볡 μ˜ˆμ‹œ - μ•ŒλžŒ 등둝 λ²„νŠΌ 클릭 μ‹œ, μ•ŒλžŒ 이름과 μ•ŒλžŒ λ‚ μ§œ μ‹œκ°„ μ„ νƒν•˜κ³  μ•ŒλžŒ λ‚ μ§œμ‹œκ°„μ€ ν…μŠ€νŠΈ μž…λ ₯말고 달λ ₯ μ‹œκ³„ μž…λ ₯으둜 μ•ŒλžŒ μ†Œλ¦¬λ₯Ό μ„ νƒμƒμžμ—μ„œ 선택, 기본은 c:/alaram/κΈ°λ³Έ.mp3 μ΄λ ‡κ²Œ λ“±λ‘ν•œ μ•ŒλžŒμ€ λŒ€μ‹œλ³΄λ“œμ— 좜λ ₯되고, μˆ˜μ • μ‚­μ œλ²„νŠΌμœΌλ‘œ 관리 λŒ€μ‹œλ³΄λ“œμ—μ„œ ν•΄λ‹Ή μ•ŒλžŒ 더블클릭 μ‹œ, ν”„λ‘œκ·Έλ ˆμŠ€λ°”μ™€ 라벨둜 남은 μ‹œκ°„ ν‘œμ‹œν•˜λŠ” ν™”λ©΄μœΌλ‘œ 이동 μΊ”λ²„μŠ€ λͺ¨λ“œλ‘œ 응닡
Plain Text
볡사

μ½”λ“œ

import os import tkinter as tk from tkinter import ttk, messagebox, filedialog from tkcalendar import Calendar, DateEntry from datetime import datetime, timedelta import threading import time import pygame import mysql.connector from plyer import notification # ===================== DB SETUP ===================== def connect_db(): # MySQL DB에 μ—°κ²°ν•˜κ³  alarm ν…Œμ΄λΈ” 생성 (status μΆ”κ°€) conn = mysql.connector.connect( host='localhost', user='python', password='123456', database='python' ) cursor = conn.cursor() cursor.execute(''' CREATE TABLE IF NOT EXISTS alarm ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255), time DATETIME, sound_path TEXT, status VARCHAR(10) DEFAULT 'on' -- μ•ŒλžŒ μƒνƒœ (on/off) ) ''') conn.commit() return conn # ===================== ALARM PLAYER ===================== def play_alarm(sound_path): # μ•ŒλžŒ μ†Œλ¦¬λ₯Ό 반볡 μž¬μƒ (stop_eventκ°€ 섀정될 λ•ŒκΉŒμ§€) pygame.mixer.init() pygame.mixer.music.load(sound_path) while not stop_event.is_set(): pygame.mixer.music.play() time.sleep(pygame.mixer.Sound(sound_path).get_length()) def notify_user(title, msg): # μœˆλ„μš° μ•Œλ¦Όμ„ 띄움 notification.notify( title=title, message=msg, timeout=5 ) # ===================== MAIN APP ===================== class AlarmApp: def __init__(self, root): self.root = root self.root.title("μ•ŒλžŒ λŒ€μ‹œλ³΄λ“œ") self.conn = connect_db() self.cursor = self.conn.cursor() self.frame = ttk.Frame(root, padding=10) self.frame.pack(fill='both', expand=True) self.add_button = ttk.Button(self.frame, text="μ•ŒλžŒ 등둝", command=self.open_add_alarm_window) self.add_button.pack(pady=5) # μ•ŒλžŒ 리슀트 좜λ ₯용 TreeView ꡬ성 self.tree = ttk.Treeview(self.frame, columns=('Name', 'Time', 'Sound', 'Status'), show='headings') self.tree.heading('Name', text='μ•ŒλžŒ 이름') self.tree.heading('Time', text='μ•ŒλžŒ μ‹œκ°„') self.tree.heading('Sound', text='μ•ŒλžŒ μ†Œλ¦¬') self.tree.heading('Status', text='μƒνƒœ') self.tree.pack(fill='both', expand=True) self.tree.bind('<Double-1>', self.open_edit_alarm_window) self.load_alarms() self.check_alarms() def load_alarms(self): # DBμ—μ„œ μ•ŒλžŒ λͺ©λ‘μ„ λΆˆλŸ¬μ™€ TreeView에 ν‘œμ‹œ for row in self.tree.get_children(): self.tree.delete(row) self.cursor.execute("SELECT id, name, time, sound_path, status FROM alarm") for id, name, time_, sound, status in self.cursor.fetchall(): self.tree.insert('', 'end', iid=id, values=(name, time_, os.path.basename(sound), status)) def open_add_alarm_window(self): AlarmEditor(self.root, self.conn, self.load_alarms) def open_edit_alarm_window(self, event): selected = self.tree.focus() if selected: alarm_id = int(selected) AlarmEditor(self.root, self.conn, self.load_alarms, alarm_id) def check_alarms(self): # 주기적으둜 ν˜„μž¬ μ‹œκ°κ³Ό μ•ŒλžŒ μ‹œκ°„ λΉ„κ΅ν•˜μ—¬ μ‹€ν–‰ 쑰건 체크 def run(): while True: self.cursor.execute("SELECT id, name, time, sound_path FROM alarm WHERE status='on'") for alarm_id, name, alarm_time, sound in self.cursor.fetchall(): now = datetime.now() # μ•ŒλžŒ μ‹œκ°„μ΄ 지났고 아직 μšΈλ¦¬μ§€ μ•Šμ€ μ•ŒλžŒμ΄λ©΄ μ‹€ν–‰ if now >= alarm_time and not active_alarms.get(alarm_id): active_alarms[alarm_id] = True threading.Thread(target=self.trigger_alarm, args=(alarm_id, name, alarm_time, sound)).start() time.sleep(10) threading.Thread(target=run, daemon=True).start() def trigger_alarm(self, alarm_id, name, alarm_time, sound): # μ•ŒλžŒ μ‹€ν–‰: μ•Œλ¦Ό ν‘œμ‹œ 및 μ†Œλ¦¬ μž¬μƒ notify_user("μ•ŒλžŒ", f"{name} - {alarm_time.strftime('%Y-%m-%d %H:%M:%S')}") global stop_event stop_event = threading.Event() threading.Thread(target=play_alarm, args=(sound,), daemon=True).start() # μ•ŒλžŒ μ’…λ£Œμš© νŒμ—… μœˆλ„μš° stop_window = tk.Toplevel(self.root) stop_window.title("μ•ŒλžŒ 울림") ttk.Label(stop_window, text=f"μ•ŒλžŒ: {name}").pack(pady=10) ttk.Label(stop_window, text=f"μ‹œκ°„: {alarm_time}").pack(pady=5) stop_btn = ttk.Button(stop_window, text="μ•ŒλžŒ 끄기", command=lambda: self.stop_alarm(stop_window, alarm_id)) stop_btn.pack(pady=20) def stop_alarm(self, window, alarm_id): # μ•ŒλžŒ μ •μ§€ 처리: μ†Œλ¦¬ 쀑지 + DB μƒνƒœ λ³€κ²½ stop_event.set() pygame.mixer.music.stop() window.destroy() # μ•ŒλžŒ μƒνƒœλ₯Ό 'off'둜 μ—…λ°μ΄νŠΈ self.cursor.execute("UPDATE alarm SET status='off' WHERE id=%s", (alarm_id,)) self.conn.commit() self.load_alarms() # ===================== ALARM EDITOR ===================== class AlarmEditor: def __init__(self, root, conn, refresh_callback, alarm_id=None): self.conn = conn self.cursor = conn.cursor() self.refresh_callback = refresh_callback self.alarm_id = alarm_id self.top = tk.Toplevel(root) self.top.title("μ•ŒλžŒ μˆ˜μ •" if alarm_id else "μ•ŒλžŒ 등둝") # μ•ŒλžŒ 이름 μž…λ ₯ ttk.Label(self.top, text="μ•ŒλžŒ 이름").grid(row=0, column=0, padx=5, pady=5) self.name_entry = ttk.Entry(self.top) self.name_entry.grid(row=0, column=1, padx=5, pady=5) # λ‚ μ§œ 선택 ttk.Label(self.top, text="μ•ŒλžŒ λ‚ μ§œ").grid(row=1, column=0, padx=5, pady=5) self.date_entry = DateEntry(self.top, width=12, background='darkblue', foreground='white', borderwidth=2) self.date_entry.grid(row=1, column=1, padx=5, pady=5) # μ‹œκ°„ μž…λ ₯ (μ‹œ:λΆ„) ttk.Label(self.top, text="μ‹œκ°„ (HH:MM)").grid(row=2, column=0, padx=5, pady=5) self.time_entry = ttk.Entry(self.top) self.time_entry.insert(0, "08:00") # κΈ°λ³Έκ°’ μ„€μ • self.time_entry.grid(row=2, column=1, padx=5, pady=5) # μ•ŒλžŒ μ†Œλ¦¬ 선택 ttk.Label(self.top, text="μ•ŒλžŒ μ†Œλ¦¬").grid(row=3, column=0, padx=5, pady=5) self.sound_combo = ttk.Combobox(self.top, values=self.load_sounds()) self.sound_combo.set("κΈ°λ³Έ.mp3") self.sound_combo.grid(row=3, column=1, padx=5, pady=5) # μ €μž₯ λ²„νŠΌ save_btn = ttk.Button(self.top, text="μ €μž₯", command=self.save_alarm) save_btn.grid(row=4, column=0, pady=10) # μˆ˜μ • μ‹œ μ‚­μ œ λ²„νŠΌλ„ ν‘œμ‹œ if alarm_id: delete_btn = ttk.Button(self.top, text="μ‚­μ œ", command=self.delete_alarm) delete_btn.grid(row=4, column=1, pady=10) if alarm_id: self.load_alarm_data() def load_sounds(self): # μ•ŒλžŒ μ‚¬μš΄λ“œ ν΄λ”μ—μ„œ mp3 파일 λͺ©λ‘ κ°€μ Έμ˜€κΈ° sound_dir = "c:/alarm" return [f for f in os.listdir(sound_dir) if f.endswith(".mp3")] def load_alarm_data(self): # DBμ—μ„œ μ•ŒλžŒ 정보 λ‘œλ“œν•˜μ—¬ 폼에 μ„€μ • self.cursor.execute("SELECT name, time, sound_path FROM alarm WHERE id=%s", (self.alarm_id,)) name, time_, sound = self.cursor.fetchone() self.name_entry.insert(0, name) self.date_entry.set_date(time_) self.time_entry.delete(0, tk.END) self.time_entry.insert(0, time_.strftime("%H:%M")) self.sound_combo.set(os.path.basename(sound)) def save_alarm(self): # νΌμ—μ„œ μž…λ ₯ν•œ 데이터λ₯Ό μ €μž₯ν•˜κ±°λ‚˜ μ—…λ°μ΄νŠΈ name = self.name_entry.get() date_str = self.date_entry.get_date().strftime("%Y-%m-%d") time_str = self.time_entry.get() datetime_str = f"{date_str} {time_str}:00" sound = os.path.join("c:/alarm", self.sound_combo.get()) if self.alarm_id: self.cursor.execute( "UPDATE alarm SET name=%s, time=%s, sound_path=%s, status='on' WHERE id=%s", (name, datetime_str, sound, self.alarm_id) ) else: self.cursor.execute( "INSERT INTO alarm (name, time, sound_path, status) VALUES (%s, %s, %s, 'on')", (name, datetime_str, sound) ) self.conn.commit() self.refresh_callback() self.top.destroy() def delete_alarm(self): # μ•ŒλžŒ μ‚­μ œ 확인 ν›„ DBμ—μ„œ 제거 if messagebox.askyesno("μ‚­μ œ 확인", "이 μ•ŒλžŒμ„ μ‚­μ œν•˜μ‹œκ² μŠ΅λ‹ˆκΉŒ?"): self.cursor.execute("DELETE FROM alarm WHERE id=%s", (self.alarm_id,)) self.conn.commit() self.refresh_callback() self.top.destroy() # ===================== MAIN ===================== if __name__ == "__main__": active_alarms = {} # ν˜„μž¬ μ‹€ν–‰ 쀑인 μ•ŒλžŒ λͺ©λ‘ stop_event = threading.Event() # μ•ŒλžŒ 쀑지 이벀트 root = tk.Tk() app = AlarmApp(root) root.mainloop()
Python
볡사