Chapter 23. 메뉴

메뉴(Menu)는 프로그램의 기능을 목록 형태로 제공하는 GUI 구성 요소입니다. 사용자는 메뉴를 클릭하여 원하는 기능을 실행할 수 있습니다.
대표적인 메뉴는 다음과 같습니다.
- 파일(File)
- 편집(Edit)
- 보기(View)
- 도움말(Help)
메뉴는 거의 모든 데스크톱 프로그램에서 사용되며, 예를 들어 다음과 같은 프로그램에서 메뉴를 쉽게 볼 수 있습니다.
- 메모장
- 그림판
- 계산기
- 회원관리 프로그램
- 게시판 프로그램
메뉴 예: 파일 편집 보기 도움말
────────────────────────
Tkinter 메뉴 구성은 다음과 같은 구조로 만듭니다.
Menu │ ├── 파일 │ ├── 새로 만들기 │ ├── 열기 │ ├── 저장 │ └── 종료 │ ├── 편집 │ ├── 복사
│ ├── 잘라내기
│ ├── 붙여넣기
│
└── 도움말
└── 프로그램 정보
Tkinter에서는 Menu 클래스를 이용하여 메뉴를 만듭니다.
import tkinter as tk # tkinter 모듈 임포트 window = tk.Tk() # 창 생성 menu = tk.Menu(window) # 메뉴 생성 window.config(menu=menu) # 메뉴 설정 window.mainloop() # 이벤트 루프 시작
실행하면 빈 메뉴가 생성됩니다.
파일 메뉴 만들기는 다음과 같이 합니다.
file_menu = tk.Menu( # 파일 메뉴 생성 menu, # 부모 메뉴 지정 tearoff=0 # 분리선 제거 ) menu.add_cascade( # 메뉴 항목 추가 label="파일", # 항목 레이블 menu=file_menu # 서브 메뉴 지정 )
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=window.destroy # 종료 명령 설정 )
메뉴 클릭 이벤트는 다음과 같이 설정합니다.
import tkinter as tk # tkinter 모듈 임포트 def hello(): # hello 함수 정의 print("메뉴 선택") # 메시지 출력 window = tk.Tk() # 창 생성 menu = tk.Menu(window) # 메뉴 생성 window.config(menu=menu) # 메뉴 설정 file = tk.Menu(menu, tearoff=0) # 파일 메뉴 생성 menu.add_cascade(label="파일", menu=file) # 메뉴 항목 추가 file.add_command( # 새로 만들기 명령 추가 label="새로 만들기", # 항목 레이블 command=hello # 함수 연결 ) window.mainloop() # 이벤트 루프 시작
메뉴를 클릭하면 "메뉴 선택"이 출력됩니다.
Toolbar는 자주 사용하는 기능을 버튼 형태로 모아 놓은 영역입니다. 메뉴보다 빠르게 기능을 실행할 수 있어 실무 프로그램에서 많이 사용됩니다.
Toolbar 예: [새로] [열기] [저장] [삭제]
────────────────────────────
Toolbar 만들기는 다음과 같이 합니다.
toolbar = tk.Frame( # 툴바 프레임 생성 window, # 부모 창 지정 bd=1, # 테두리 두께 relief="raised" # 테두리 스타일 ) toolbar.pack( # 툴바 배치 side="top", # 상단에 배치 fill="x" # 가로로 채우기 )
버튼 추가는 다음과 같이 합니다.
tk.Button( # 등록 버튼 생성 toolbar, # 툴바에 추가 text="등록" # 버튼 텍스트 ).pack(side="left") # 왼쪽에 배치 tk.Button( # 조회 버튼 생성 toolbar, # 툴바에 추가 text="조회" # 버튼 텍스트 ).pack(side="left") # 왼쪽에 배치 tk.Button( # 삭제 버튼 생성 toolbar, # 툴바에 추가 text="삭제" # 버튼 텍스트 ).pack(side="left") # 왼쪽에 배치
실행 화면은 다음과 같습니다.
[등록] [조회] [삭제]
회원관리 Toolbar는 다음과 같이 만들 수 있습니다.
toolbar = tk.Frame(window) # 툴바 프레임 생성 toolbar.pack(fill="x") # 툴바 배치 tk.Button(toolbar, text="등록").pack(side="left") # 등록 버튼 tk.Button(toolbar, text="수정").pack(side="left") # 수정 버튼 tk.Button(toolbar, text="삭제").pack(side="left") # 삭제 버튼 tk.Button(toolbar, text="종료").pack(side="right") # 종료 버튼
단축키는 키보드만으로 프로그램 기능을 실행하는 기능입니다.
대표적인 단축키는 다음과 같습니다.
| 단축키 | 기능 |
|---|---|
| Ctrl + N | 새로 만들기 |
| Ctrl + O | 열기 |
| Ctrl + S | 저장 |
| Ctrl + X | 잘라내기 |
| Ctrl + C | 복사 |
| Ctrl + V | 붙여넣기 |
bind()를 사용하여 단축키를 등록합니다.
import tkinter as tk # tkinter 모듈 임포트 def save(event): # 저장 함수 정의 print("저장") # 메시지 출력 window = tk.Tk() # 창 생성 window.bind( # 키 이벤트 바인딩 "<Control-s>", # Ctrl+S 키 save # 저장 함수 연결 ) window.mainloop() # 이벤트 루프 시작
Ctrl + S를 누르면 "저장"이 출력됩니다.
Ctrl + N과 ESC, F1 단축키도 다음과 같이 등록할 수 있습니다.
window.bind( # 키 이벤트 바인딩 "<Control-n>", # Ctrl+N 키 newFile # 새 파일 함수 연결 ) window.bind( # 키 이벤트 바인딩 "<Escape>", # Esc 키 exitProgram # 종료 함수 연결 ) window.bind( # 키 이벤트 바인딩 "<F1>", # F1 키 helpProgram # 도움말 함수 연결 )
메뉴에 단축키 표시를 추가하려면 다음과 같이 합니다.
file.add_command( # 저장 명령 추가 label="저장", # 항목 레이블 accelerator="Ctrl+S" # 단축키 설정 )
accelerator는 메뉴에 단축키를 표시하는 역할만 하며, 실제 동작은 bind()로 등록해야 합니다.
from tkinter import * # tkinter 기본 위젯 불러오기 from tkinter import filedialog, messagebox # 파일 대화상자, 알림창 불러오기 def register(): # 등록 버튼 클릭 시 실행 emp_id = entry_id.get().strip() # 사번 입력값 가져오기 name = entry_name.get().strip() # 이름 입력값 가져오기 phone = entry_phone.get().strip() # 전화번호 입력값 가져오기 address = entry_address.get().strip() # 주소 입력값 가져오기 if not emp_id and not name and not phone and not address: # 모두 비어 있으면 return # 등록하지 않고 종료 text_area.insert( # 텍스트 영역에 회원 정보 추가 END, f"사번: {emp_id} 이름: {name} 전화번호: {phone} 주소: {address}\n", ) entry_id.delete(0, END) # 사번 입력란 비우기 entry_name.delete(0, END) # 이름 입력란 비우기 entry_phone.delete(0, END) # 전화번호 입력란 비우기 entry_address.delete(0, END) # 주소 입력란 비우기 entry_id.focus() # 사번 입력란에 커서 두기 def new_file(event=None): # 새로 만들기 (Ctrl+N) text_area.delete("1.0", END) # 텍스트 영역 내용 지우기 entry_id.delete(0, END) # 사번 입력란 비우기 entry_name.delete(0, END) # 이름 입력란 비우기 entry_phone.delete(0, END) # 전화번호 입력란 비우기 entry_address.delete(0, END) # 주소 입력란 비우기 entry_id.focus() # 사번 입력란에 커서 두기 return "break" # 기본 단축키 동작과 중복 방지 def open_file(event=None): # 파일 열기 (Ctrl+O) path = filedialog.askopenfilename( # 열기 대화상자 표시 title="열기", filetypes=[("텍스트 파일", "*.txt"), ("모든 파일", "*.*")], ) if path: # 파일을 선택했으면 with open(path, encoding="utf-8") as f: # UTF-8로 파일 열기 text_area.delete("1.0", END) # 기존 내용 지우기 text_area.insert("1.0", f.read()) # 파일 내용 넣기 return "break" # 기본 단축키 동작과 중복 방지 def save_file(event=None): # 파일 저장 (Ctrl+S) path = filedialog.asksaveasfilename( # 저장 대화상자 표시 title="저장", defaultextension=".txt", filetypes=[("텍스트 파일", "*.txt"), ("모든 파일", "*.*")], ) if path: # 저장 경로를 선택했으면 with open(path, "w", encoding="utf-8") as f: # UTF-8로 파일 쓰기 f.write(text_area.get("1.0", "end-1c")) # 텍스트 영역 내용 저장 return "break" # 기본 단축키 동작과 중복 방지 def _focused_widget(): # 현재 포커스된 위젯 반환 return window.focus_get() # 커서가 있는 위젯 가져오기 def copy_text(event=None): # 복사 (Ctrl+C) widget = _focused_widget() # 현재 선택된 위젯 try: if isinstance(widget, Text): # 텍스트 영역이면 selected = widget.get("sel.first", "sel.last") # 선택한 글자 가져오기 elif isinstance(widget, Entry): # 입력란이면 selected = widget.selection_get() # 선택한 글자 가져오기 else: return # 해당 없으면 종료 window.clipboard_clear() # 클립보드 비우기 window.clipboard_append(selected) # 선택한 글자를 클립보드에 넣기 except TclError: # 선택한 글자가 없으면 pass # 무시 return "break" # 기본 단축키 동작과 중복 방지 def cut_text(event=None): # 잘라내기 (Ctrl+X) widget = _focused_widget() # 현재 선택된 위젯 try: if isinstance(widget, Text): # 텍스트 영역이면 selected = widget.get("sel.first", "sel.last") # 선택한 글자 가져오기 widget.delete("sel.first", "sel.last") # 선택한 글자 삭제 elif isinstance(widget, Entry): # 입력란이면 selected = widget.selection_get() # 선택한 글자 가져오기 widget.delete("sel.first", "sel.last") # 선택한 글자 삭제 else: return # 해당 없으면 종료 window.clipboard_clear() # 클립보드 비우기 window.clipboard_append(selected) # 선택한 글자를 클립보드에 넣기 except TclError: # 선택한 글자가 없으면 pass # 무시 return "break" # 기본 단축키 동작과 중복 방지 def paste_text(event=None): # 붙여넣기 (Ctrl+V) widget = _focused_widget() # 현재 선택된 위젯 try: clip = window.clipboard_get() # 클립보드 내용 가져오기 if isinstance(widget, Text): # 텍스트 영역이면 try: widget.delete("sel.first", "sel.last") # 선택한 글자 있으면 지우기 except TclError: pass # 선택이 없으면 무시 widget.insert("insert", clip) # 커서 위치에 붙여넣기 elif isinstance(widget, Entry): # 입력란이면 try: widget.delete("sel.first", "sel.last") # 선택한 글자 있으면 지우기 except TclError: pass # 선택이 없으면 무시 widget.insert(INSERT, clip) # 커서 위치에 붙여넣기 except TclError: # 클립보드가 비어 있으면 pass # 무시 return "break" # 기본 단축키 동작과 중복 방지 def show_info(): # 프로그램 정보 표시 messagebox.showinfo("프로그램 정보", "회원관리 프로그램입니다.") # 알림창 띄우기 window = Tk() # 메인 창 생성 window.title("회원관리 프로그램") # 창 제목 설정 window.geometry("480x460") # 창 크기 설정 window.resizable(False, False) # 창 크기 조절 잠금 menubar = Menu(window) # 메뉴바 생성 file_menu = Menu(menubar, tearoff=0) # 파일 메뉴 (분리 방지) file_menu.add_command(label="새로 만들기", command=new_file, accelerator="Ctrl+N") # 새로 만들기 file_menu.add_command(label="열기", command=open_file, accelerator="Ctrl+O") # 열기 file_menu.add_command(label="저장", command=save_file, accelerator="Ctrl+S") # 저장 file_menu.add_separator() # 구분선 file_menu.add_command(label="종료", command=window.destroy) # 종료 menubar.add_cascade(label="파일", menu=file_menu) # 상단에 파일 메뉴 붙이기 edit_menu = Menu(menubar, tearoff=0) # 편집 메뉴 (분리 방지) edit_menu.add_command(label="복사", command=copy_text, accelerator="Ctrl+C") # 복사 edit_menu.add_command(label="잘라내기", command=cut_text, accelerator="Ctrl+X") # 잘라내기 edit_menu.add_command(label="붙여넣기", command=paste_text, accelerator="Ctrl+V") # 붙여넣기 menubar.add_cascade(label="편집", menu=edit_menu) # 상단에 편집 메뉴 붙이기 help_menu = Menu(menubar, tearoff=0) # 도움말 메뉴 (분리 방지) help_menu.add_command(label="프로그램 정보", command=show_info) # 프로그램 정보 menubar.add_cascade(label="도움말", menu=help_menu) # 상단에 도움말 메뉴 붙이기 window.config(menu=menubar) # 창에 메뉴바 연결 window.bind_all("<Control-n>", new_file) # Ctrl+N → 새로 만들기 window.bind_all("<Control-o>", open_file) # Ctrl+O → 열기 window.bind_all("<Control-s>", save_file) # Ctrl+S → 저장 window.bind_all("<Control-x>", cut_text) # Ctrl+X → 잘라내기 window.bind_all("<Control-c>", copy_text) # Ctrl+C → 복사 window.bind_all("<Control-v>", paste_text) # Ctrl+V → 붙여넣기 Label(window, text="회원관리 프로그램", font=("맑은 고딕", 18, "bold")).pack(pady=16) # 제목 레이블 form = Frame(window) # 입력 폼을 담을 프레임 form.pack() # 프레임 배치 Label(form, text="사번:", font=("맑은 고딕", 11)).grid( # 사번 레이블 row=0, column=0, sticky=E, padx=8, pady=6 ) entry_id = Entry(form, width=30, font=("맑은 고딕", 11)) # 사번 입력란 entry_id.grid(row=0, column=1, padx=8, pady=6) # 사번 입력란 배치 Label(form, text="이름:", font=("맑은 고딕", 11)).grid( # 이름 레이블 row=1, column=0, sticky=E, padx=8, pady=6 ) entry_name = Entry(form, width=30, font=("맑은 고딕", 11)) # 이름 입력란 entry_name.grid(row=1, column=1, padx=8, pady=6) # 이름 입력란 배치 Label(form, text="전화번호:", font=("맑은 고딕", 11)).grid( # 전화번호 레이블 row=2, column=0, sticky=E, padx=8, pady=6 ) entry_phone = Entry(form, width=30, font=("맑은 고딕", 11)) # 전화번호 입력란 entry_phone.grid(row=2, column=1, padx=8, pady=6) # 전화번호 입력란 배치 Label(form, text="주소:", font=("맑은 고딕", 11)).grid( # 주소 레이블 row=3, column=0, sticky=E, padx=8, pady=6 ) entry_address = Entry(form, width=30, font=("맑은 고딕", 11)) # 주소 입력란 entry_address.grid(row=3, column=1, padx=8, pady=6) # 주소 입력란 배치 buttons = Frame(window) # 버튼을 담을 프레임 buttons.pack(pady=16) # 버튼 프레임 배치 Button(buttons, text="등록", width=10, font=("맑은 고딕", 10), command=register).pack( # 등록 버튼 side=LEFT, padx=8 ) Button( # 종료 버튼 buttons, text="종료", width=10, font=("맑은 고딕", 10), command=window.destroy ).pack(side=LEFT, padx=8) text_frame = Frame(window) # 텍스트 영역과 스크롤바를 담을 프레임 text_frame.pack(padx=16, pady=(0, 16), fill=BOTH, expand=True) # 아래쪽을 채우며 배치 scrollbar = Scrollbar(text_frame) # 세로 스크롤바 생성 scrollbar.pack(side=RIGHT, fill=Y) # 오른쪽에 스크롤바 배치 text_area = Text( # 회원 목록을 보여줄 텍스트 영역 text_frame, width=52, height=10, font=("맑은 고딕", 10), yscrollcommand=scrollbar.set, # 텍스트 스크롤과 스크롤바 연결 ) text_area.pack(side=LEFT, fill=BOTH, expand=True) # 텍스트 영역 배치 scrollbar.config(command=text_area.yview) # 스크롤바 동작 연결 entry_id.focus() # 시작 시 사번 입력란에 커서 window.mainloop() # 창 실행 (이벤트 대기)

- 메뉴는 프로그램의 기능을 목록 형태로 제공하는 GUI 구성 요소이다.
- Tkinter에서 Menu 클래스를 이용하여 메뉴를 만든다.
- Toolbar는 자주 사용하는 기능을 버튼 형태로 모아 놓은 영역이다.
- 단축키는 키보드만으로 프로그램 기능을 실행하는 기능이다.
- bind()를 사용하여 단축키를 등록할 수 있다.