Python Tkinter - 4. 메뉴, 다이얼로그, 스타일링

2025. 2. 3. 16:09프로그래밍 언어/Python

이론

메뉴 구현

macOS에서는 메뉴바 동작이 다를 수 있으므로 플랫폼별 처리가 필요합니다. 아래 예제 코드에 macOS 대응이 추가되어 있습니다. Tkinter는 GUI 애플리케이션에서 메뉴바 (MenuBar), 서브메뉴 (Submenu), 컨텍스트 메뉴 (Context Menu)를 지원합니다.

1. 메뉴바 (MenuBar)

메뉴바는 애플리케이션 상단에 위치하며, 여러 개의 서브메뉴를 포함할 수 있습니다.

import tkinter as tk
from tkinter import Menu

root = tk.Tk()
root.title("메뉴바 예제")

# 메뉴바 생성
menubar = Menu(root)

# 파일 메뉴 생성
file_menu = Menu(menubar, tearoff=0)  # tearoff=0을 설정하지 않으면 메뉴가 분리 가능함
file_menu.add_command(label="새 파일")
file_menu.add_command(label="열기")
file_menu.add_command(label="저장")
file_menu.add_separator()
file_menu.add_command(label="닫기", command=root.quit)

# 메뉴바에 파일 메뉴 추가
menubar.add_cascade(label="파일", menu=file_menu)

import platform
if platform.system() == "Darwin":  # macOS의 경우 메뉴바 위치 변경 필요
    root.createcommand('tk::mac::Quit', root.quit)
    root.createcommand('tk::mac::About', lambda: messagebox.showinfo("About", "앱 정보"))

root.option_add('*tearOff', False)  # 모든 메뉴 tearoff 비활성화
root.config(menu=menubar)
root.mainloop()

2. 컨텍스트 메뉴 (Context Menu)

우클릭했을 때 나타나는 메뉴입니다.

def show_context_menu(event):
    context_menu.post(event.x_root, event.y_root)

context_menu = Menu(root, tearoff=0)
context_menu.add_command(label="복사")
context_menu.add_command(label="붙여넣기")

if platform.system() != 'Darwin':
    root.bind("<Button-3>", show_context_menu)
else:
    root.bind("<Button-2>", show_context_menu)

다이얼로그

Tkinter 다이얼로그에서 버튼이 4개 이상일 경우 문제가 발생할 수 있습니다. 복잡한 다이얼로그 설계 시 주의가 필요합니다. Tkinter에서는 파일 선택 (filedialog), 메시지 박스 (messagebox), 사용자 입력 (simpledialog) 다이얼로그를 제공합니다.

 

1. 파일 선택 다이얼로그

from tkinter import filedialog

def open_file():
    file_path = filedialog.askopenfilename()
    try:
        file_path = filedialog.askopenfilename()
        print(f"선택된 파일: {file_path}")
    except Exception as e:
        print(f"오류 발생: {e}")

btn = tk.Button(root, text="파일 열기", command=open_file)
btn.pack()

 

2. 메시지 박스

from tkinter import messagebox

def show_message():
    messagebox.showinfo("알림", "파일이 저장되었습니다.")

btn = tk.Button(root, text="메시지 출력", command=show_message)
btn.pack()

 

3. 사용자 입력 다이얼로그

from tkinter import simpledialog

def ask_user():
    name = simpledialog.askstring("입력", "이름을 입력하세요:")
    print(f"사용자 입력: {name}")

btn = tk.Button(root, text="이름 입력", command=ask_user)
btn.pack()

스타일링

ttk 스타일링이 모든 플랫폼에서 동일하게 적용되지 않을 수 있습니다. 특히 macOS에서는 일부 스타일이 무시될 수 있으므로 주의가 필요합니다. Tkinter는 ttk 위젯을 사용하여 테마를 적용할 수 있습니다.

 

1. ttk 테마 적용

from tkinter import ttk

style = ttk.Style()
style.theme_use('clam')
style.map('TButton', background=[('active', '!disabled', 'darkgray'), ('!active', 'lightgray')])
style.theme_use("clam")

 

2. CSS와 유사한 스타일링

style.configure("TButton", foreground="blue", background="lightgray", font=("Arial", 12))
# Windows 환경에서는 기본 UI 스타일을 유지하는 것이 더 적합할 수 있음.

실습

1. 텍스트 편집기 제작

  • 메뉴바와 툴바 추가
  • 파일 열기, 저장, 새 파일 만들기 기능 구현
from tkinter import filedialog, messagebox

def new_file():
    text.delete("1.0", tk.END)

def open_file():
    file_path = filedialog.askopenfilename()
    try:
        with open(file_path, "r", encoding="utf-8") as file:
            text.delete("1.0", tk.END)
            text.insert(tk.END, file.read())
    except Exception as e:
        messagebox.showerror("오류", f"파일을 열 수 없습니다: {e}")

def save_file():
    file_path = filedialog.asksaveasfilename()
    try:
        with open(file_path, "w", encoding="utf-8") as file:
            file.write(text.get("1.0", tk.END))
    except Exception as e:
        messagebox.showerror("오류", f"파일을 저장할 수 없습니다: {e}")

text = tk.Text(root, wrap="word")
text.pack(expand=True, fill="both")

menubar = Menu(root)
file_menu = Menu(menubar, tearoff=0)
file_menu.add_command(label="새 파일", command=new_file)
file_menu.add_command(label="열기", command=open_file)
file_menu.add_command(label="저장", command=save_file)
menubar.add_cascade(label="파일", menu=file_menu)
root.config(menu=menubar)

 

2. 사용자 정의 다이얼로그 설계

  • 색상 선택 다이얼로그
from tkinter import colorchooser, simpledialog

def choose_color():
    color = colorchooser.askcolor()[1]
    root.config(bg=color)

btn = tk.Button(root, text="색상 선택", command=choose_color)
btn.pack()
  • 간단한 계산기 다이얼로그
def calculate():
    try:
        num1 = simpledialog.askinteger("입력", "첫 번째 숫자:", parent=root)
        if num1 is None:
            return

        num2 = simpledialog.askinteger("입력", "두 번째 숫자:", parent=root)
        if num2 is None:
            return

        messagebox.showinfo("결과", f"덧셈 결과: {num1 + num2}")
    except (TypeError, ValueError):
        messagebox.showerror("오류", "숫자를 입력해주세요")
    except Exception as e:
        messagebox.showerror("오류", f"계산 오류: {str(e)}")
    except Exception as e:
        messagebox.showerror("오류", f"계산 중 오류 발생: {e}")

btn = tk.Button(root, text="계산기 열기", command=calculate)
btn.pack()

 

3. 현대적인 UI 구현

  • ttk 테마 적용 및 스타일링
style = ttk.Style()
style.theme_use("clam")
style.configure("TButton", font=("Arial", 12), foreground="black", background="lightgray")
# macOS에서는 Treeview 등의 특정 위젯에 스타일이 적용되지 않을 수 있음

과제

파일 탐색기 프로그램

  • 파일 열기, 복사, 이동, 삭제 기능 구현
def open_file():
    file_path = filedialog.askopenfilename()
    print(f"열린 파일: {file_path}")

def delete_file():
    try:
        file_path = filedialog.askopenfilename()
        import os
        os.remove(file_path)
        print("파일 삭제 완료")
    except Exception as e:
        messagebox.showerror("오류", f"삭제 실패: {str(e)}")

btn_open = tk.Button(root, text="파일 열기", command=open_file)
btn_open.pack()
btn_delete = tk.Button(root, text="파일 삭제", command=delete_file)
btn_delete.pack()

기대 효과

  • Tkinter 메뉴 및 다이얼로그 활용 능력을 향상할 수 있습니다.
  • 현대적인 UI 스타일링을 적용하여 더욱 완성도 높은 GUI 애플리케이션을 제작할 수 있습니다.