Chapter 4: 드래그 앤 드롭 기능¶
이번 챕터에서는 사용자가 파일을 직접 드래그 앤 드롭할 수 있는 기능을 추가하고, 실제 파일 시스템과 상호작용하는 기능을 구현해보겠습니다.
🎯 학습 목표¶
- tkinterdnd2 라이브러리 활용법 익히기
- 파일 시스템 접근 및 파일 정보 처리
- 사용자 친화적인 파일 관리 인터페이스 구현
- 에러 처리 및 예외 상황 대응
📦 필요한 라이브러리¶
tkinterdnd2 설치¶
tkinterdnd2란?
tkinterdnd2는 tkinter에 드래그 앤 드롭 기능을 추가해주는 서드파티 라이브러리입니다. Windows, macOS, Linux에서 모두 동작합니다.
🔧 핵심 기능 설계¶
드래그 앤 드롭 플로우¶
graph TD
A[사용자가 파일 드래그] --> B{드롭 영역에 놓음}
B -->|성공| C[파일 경로 추출]
B -->|실패| D[무시]
C --> E[파일 유효성 검사]
E -->|유효| F[파일 목록에 추가]
E -->|무효| G[에러 메시지]
F --> H[UI 업데이트]
향상된 파일 관리¶
- 중복 파일 체크: 이미 추가된 파일은 제외
- 파일 정보 표시: 파일명, 크기, 확장자 등
- 파일 개수 카운터: 현재 로드된 파일 수 표시
- 선택적 제거: 다중 선택으로 여러 파일 동시 제거
💻 코드 구현¶
1. 라이브러리 Import 및 초기 설정¶
src/chapter4/main.py | |
---|---|
선택적 Import
try-except
를 사용하여 tkinterdnd2가 없어도 기본 기능은 동작하도록 합니다. 이는 배포 시 호환성을 높이는 좋은 패턴입니다.
2. 향상된 클래스 구조¶
3. 드롭 영역 설계¶
시각적 피드백
relief="solid"
로 드롭 영역을 명확히 구분하고, 라이브러리 유무에 따라 다른 안내 메시지를 표시합니다.
4. 향상된 파일 목록 UI¶
다중 선택 모드
selectmode=tk.EXTENDED
로 설정하여 Ctrl+클릭이나 Shift+클릭으로 여러 파일을 선택할 수 있게 합니다.
5. 향상된 버튼 영역¶
🎮 드래그 앤 드롭 구현¶
1. 드래그 앤 드롭 설정¶
이벤트 바인딩
drop_target_register(DND_FILES)
: 파일 드롭을 받을 수 있도록 등록dnd_bind('<<Drop>>', handler)
: 드롭 이벤트 핸들러 연결
2. 드롭 이벤트 처리¶
3. 파일 추가 다이얼로그¶
파일 형식 필터
filetypes
매개변수로 사용자가 특정 형식의 파일만 선택하기 쉽게 만듭니다.
📁 파일 관리 로직¶
1. 스마트 파일 추가¶
중복 검사
os.path.isfile()
: 실제 파일인지 확인file_path not in self.files
: 이미 추가된 파일인지 확인
2. 선택적 파일 제거¶
역순 제거
리스트에서 항목을 제거할 때는 뒤에서부터 제거해야 인덱스가 꼬이지 않습니다.
3. 전체 파일 제거¶
4. 파일 카운터 업데이트¶
🧪 테스트 시나리오¶
1. 드래그 앤 드롭 테스트¶
- 탐색기에서 파일 하나를 선택
- 드롭 영역으로 드래그
- 파일이 목록에 추가되는지 확인
- 탐색기에서 여러 파일을 선택 (Ctrl+클릭)
- 드롭 영역으로 드래그
- 모든 파일이 목록에 추가되는지 확인
- 폴더를 드래그 앤 드롭
- 폴더는 무시되고 파일만 처리되는지 확인
2. 파일 관리 테스트¶
- 같은 파일을 두 번 추가
- 중복이 방지되는지 확인
- 여러 파일을 선택 (Ctrl+클릭)
- "선택 제거" 버튼 클릭
- 선택된 파일들만 제거되는지 확인
- 여러 파일을 추가
- "모두 제거" 버튼 클릭
- 모든 파일이 제거되는지 확인
🎨 UI/UX 개선사항¶
1. 시각적 피드백¶
# 드롭 영역 강조
self.drop_label = ttk.Label(
main_frame,
text=drop_info,
relief="solid", # 테두리 표시
padding="20", # 충분한 패딩
anchor="center" # 중앙 정렬
)
2. 상태 정보 표시¶
# 실시간 파일 개수 표시
self.count_var.set(f"파일 개수: {len(self.files)}")
# 사용자 액션에 대한 피드백
self.status_var.set(f"{added_count}개 파일이 추가되었습니다")
3. 다양한 입력 방법 지원¶
- 드래그 앤 드롭: 직관적인 파일 추가
- 파일 다이얼로그: 전통적인 파일 선택
- 다중 선택: 효율적인 파일 관리
🔍 에러 처리¶
1. 라이브러리 누락 처리¶
try:
from tkinterdnd2 import DND_FILES, TkinterDnD
DND_AVAILABLE = True
except ImportError:
DND_AVAILABLE = False
# 기본 기능으로 fallback
2. 파일 시스템 에러¶
def add_files(self, file_paths):
added_count = 0
for file_path in file_paths:
try:
if os.path.isfile(file_path) and file_path not in self.files:
self.files.append(file_path)
file_name = os.path.basename(file_path)
self.files_listbox.insert(tk.END, file_name)
added_count += 1
except (OSError, PermissionError) as e:
self.status_var.set(f"파일 접근 오류: {e}")
continue
🚀 실행 결과¶
완성된 Chapter 4 예제를 실행하면:
새로 추가된 기능들¶
- 드래그 앤 드롭 영역: 파일을 직접 끌어다 놓을 수 있음
- 파일 개수 표시: 현재 로드된 파일 수 실시간 표시
- 향상된 버튼: 선택 제거, 모두 제거 기능
- 수평 스크롤바: 긴 파일명도 확인 가능
- 다중 선택: 여러 파일을 동시에 선택/제거 가능
📚 핵심 개념 정리¶
드래그 앤 드롭 패턴¶
# 1. 위젯을 드롭 타겟으로 등록
widget.drop_target_register(DND_FILES)
# 2. 드롭 이벤트 바인딩
widget.dnd_bind('<<Drop>>', self.on_drop)
# 3. 이벤트 핸들러에서 데이터 처리
def on_drop(self, event):
files = self.root.tk.splitlist(event.data)
self.process_files(files)
파일 시스템 작업¶
import os
from pathlib import Path
# 파일 존재 확인
if os.path.isfile(file_path):
# 파일 처리
# 파일명 추출
file_name = os.path.basename(file_path)
# 경로 조작 (pathlib 사용 권장)
path = Path(file_path)
name = path.name
extension = path.suffix
리스트 관리 패턴¶
# 중복 방지 추가
if item not in list:
list.append(item)
# 역순 제거
for index in reversed(selection):
del list[index]
# 전체 삭제
list.clear()
🎯 다음 단계 미리보기¶
Chapter 2에서는 파일을 관리하는 기능을 추가했습니다. 다음 Chapter 3에서는:
- 실제 파일명 변경 로직 구현
- 다양한 리네임 방식 지원
- 미리보기 기능 추가
- 안전한 파일 조작 구현
Chapter 4 완료!
드래그 앤 드롭 기능과 파일 관리 기능을 성공적으로 구현했습니다! 이제 실제로 파일명을 변경하는 핵심 기능을 만들어보겠습니다.
연습 과제
- 파일 정보를 더 자세히 표시해보기 (크기, 수정일 등)
- 파일 형식별로 다른 아이콘 표시해보기
- 파일 목록을 저장/불러오기 기능 추가해보기
- 드롭 시 시각적 효과 추가해보기