1. 레이아웃
# Project) 여러 이미지를 합치는 프로그램을 만드시오.
# [사용자 시나리오]
# 1. 사용자는 합치려는 이미지를 1개 이상 선택한다.
# 2. 합쳐진 이미지가 저장될 경로를 지정한다.
# 3. 가로넓이, 간격, 포맷 옵션을 지정한다.
# 4. 시작 버튼을 통해 이미지를 합친다.
# 5. 닫기 버튼을 통해 프로그램을 종료한다.
# [기능 명세]
# 1. 파일추가 : 리스트 박스에 파일 추가
# 2. 선택삭제 : 리스트 박스에서 선택된 항목 삭제
# 3. 찾아보기 : 저장 폴더를 선택하면 텍스트 위젯에 입력
# 4. 가로넓이 : 이미지 넓이 지정 (원본유지, 1024, 800, 640)
# 5. 간격 : 이미지 간의 간격지정 (없음, 좁게, 보통, 넓게)
# 6. 포맷 : 저장 이미지 포맷지정 (PNG, JPG, BMP)
# 7. 시작 : 이미지 합치기 작업 실행
# 8. 진행상황 : 현재 진행중인 파일 순서에 맞게 반영
# 9. 닫기 : 프로그램 종료
레이아웃 코드
import tkinter.ttk as ttk #콤보사용 위함
from tkinter import *
root = Tk()
root.title("nado gui")
#파일 프레임 ############################################
file_frame = Frame(root)
file_frame.pack(fill="x" , padx=5, pady=5)
#버튼 생성
btn_add_file = Button(file_frame, padx=5, pady=5, width=12, text="파일추가") # 어디에 만들지, 버튼텍스트
btn_add_file.pack(side="left")
btn_del_file = Button(file_frame, padx=5, pady=5, width=12, text="선택삭제") # 어디에 만들지, 버튼텍스트
btn_del_file.pack(side="right")
#리스트 프레임###########################################
list_frame = Frame(root)
list_frame.pack(fill="both" , padx=5, pady=5)
#스크롤바
scrollbar = Scrollbar(list_frame)
scrollbar.pack(side="right" , fill="y") #fill=y : 위아래로 꽉 채움
#리스트박스
list_file = Listbox(list_frame, selectmode = "extended" , height=15 , yscrollcommand=scrollbar.set) # selectmode : single 은 하나만 선택가능 extended 는 다중선택가능 # 0이면 리스트에 있는 텍스트 만큼, 높이지정하면 그 갯수만큼 (스크롤바 필요)
list_file.pack(side="left" , fill="both" , expand=True)
scrollbar.config(command=list_file.yview) #스크롤바에 리스트박스 매핑
#저장경로 프레임#########################################
path_frame = LabelFrame(root, text="저장경로")
path_frame.pack(fill="x" , padx=5, pady=5 , ipady= 5)
txt_dest_path = Entry(path_frame)
txt_dest_path.pack(side="left", fill="x", expand=True ,padx=5, pady=5 , ipady= 4) #ipad= innerpadding
btn_dest_path = Button(path_frame, text="찾아보기" , width=10)
btn_dest_path.pack(side="right" , padx=5, pady=5)
#옵션 프레임 ################################################################################
option_frame = LabelFrame(root, text="옵션")
option_frame.pack(padx=5, pady=5 ,ipadx=5, ipady= 10)
#가로 넓이 옵션
#가로 넓이 레이블
lbl_width = Label(option_frame, text="가로넓이" , width=8)
lbl_width.pack(side="left")
#가로 넓이 콤보
opt_width = ["원본유지","1024","800","640"]
cmb_width = ttk.Combobox(option_frame, state="readonly" , values=opt_width , width=10)
cmb_width.current(0)
cmb_width.pack(side="left")
#간격 옵션
#간격 옵션 레이블
lbl_space = Label(option_frame, text="간격" , width=8)
lbl_space.pack(side="left")
#간격 옵션 콤보
opt_space = ["없음","좁게","보통","넓게"]
cmb_space= ttk.Combobox(option_frame, state="readonly" , values=opt_space , width=10)
cmb_space.current(0)
cmb_space.pack(side="left")
#파일 포맷 옵션
#파일 포맷 옵션 레이블
lbl_format = Label(option_frame, text="포맷" , width=8)
lbl_format.pack(side="left")
#파일 포맷 옵션 콤보
opt_format = ["PNG","JPG","BMP"]
cmb_format= ttk.Combobox(option_frame, state="readonly" , values=opt_format , width=10)
cmb_format.current(0)
cmb_format.pack(side="left")
#진행 상황 Progress Bar ################################################################
progress_frame = LabelFrame(root, text="진행상황")
progress_frame.pack(fill="x" , padx=5, pady=5 , ipady= 5)
p_var = DoubleVar()
progress_bar = ttk.Progressbar(progress_frame, maximum = 100 , variable=p_var)
progress_bar.pack(fill="x" ,padx=5, pady=5)
#실행 프레임 ############################################################################
run_frame = Frame(root)
run_frame.pack(fill="x" , padx=5, pady=5)
#버튼 생성
btn_close = Button(run_frame, padx=5, pady=5, width=12, text="닫기" , command=root.quit) # 어디에 만들지, 버튼텍스트
btn_close.pack(side="right" , padx=5, pady=5)
btn_start = Button(run_frame, padx=5, pady=5, width=12, text="시작") # 어디에 만들지, 버튼텍스트
btn_start.pack(side="right" , padx=5, pady=5)
root.resizable(False, False) # x 너비 , y 높이 값 변경 불가 (창크기 변경 못하게)
root.mainloop() # 창이 닫히지 않도록
2. 파일 추가
import tkinter.ttk as ttk
from tkinter import *
from tkinter import filedialog # 서브모듈이라 임포트 해줘야 한다. 파일 찾기
root = Tk()
root.title("nado gui")
file_frame = Frame(root)
file_frame.pack(fill="x" , padx=5, pady=5)
# 함수정의
# 파일추가 #선택한 목록 저장
def add_file():
files = filedialog.askopenfilenames(title="이미지 파일을 선택하세요.", \
filetypes=(("PNG파일","*.png"),("모든파일","*")), \
initialdir=r"E:\PythonWorkspace\pygame_project\images") #최초에 C:/경로를 보여줌 r을 스트링이 그대로 쓰여진다.
#사용자가 선택한 파일 목록 파일 리스트에 뿌리기
for file in files:
list_file.insert(END,file)
# 선택삭제
def del_file():
#print(list_file.curselection()) #index 값 반환
for index in reversed(list_file.curselection()): #revered 를 써서 index 값 뒷번호 지워준다. 앞(0)에서 부터 지우면 지운뒤 1번이 0번으로 바뀌기 때문에 엉뚱한 파일이 삭제된다.
list_file.delete(index)
btn_add_file = Button(file_frame, padx=5, pady=5, width=12, text="파일추가", command=add_file)
btn_add_file.pack(side="left")
btn_del_file = Button(file_frame, padx=5, pady=5, width=12, text="선택삭제", command=del_file)
btn_del_file.pack(side="right")
list_frame = Frame(root)
list_frame.pack(fill="both" , padx=5, pady=5)
scrollbar = Scrollbar(list_frame)
scrollbar.pack(side="right" , fill="y")
list_file = Listbox(list_frame, selectmode = "extended" , height=15 , yscrollcommand=scrollbar.set)
list_file.pack(side="left" , fill="both" , expand=True)
scrollbar.config(command=list_file.yview)
path_frame = LabelFrame(root, text="저장경로")
path_frame.pack(fill="x" , padx=5, pady=5 , ipady= 5)
txt_dest_path = Entry(path_frame)
txt_dest_path.pack(side="left", fill="x", expand=True ,padx=5, pady=5 , ipady= 4)
btn_dest_path = Button(path_frame, text="찾아보기" , width=10)
btn_dest_path.pack(side="right" , padx=5, pady=5)
option_frame = LabelFrame(root, text="옵션")
option_frame.pack(padx=5, pady=5 ,ipadx=5, ipady= 10)
lbl_width = Label(option_frame, text="가로넓이" , width=8)
lbl_width.pack(side="left")
opt_width = ["원본유지","1024","800","640"]
cmb_width = ttk.Combobox(option_frame, state="readonly" , values=opt_width , width=10)
cmb_width.current(0)
cmb_width.pack(side="left")
lbl_space = Label(option_frame, text="간격" , width=8)
lbl_space.pack(side="left")
opt_space = ["없음","좁게","보통","넓게"]
cmb_space= ttk.Combobox(option_frame, state="readonly" , values=opt_space , width=10)
cmb_space.current(0)
cmb_space.pack(side="left")
lbl_format = Label(option_frame, text="포맷" , width=8)
lbl_format.pack(side="left")
opt_format = ["PNG","JPG","BMP"]
cmb_format= ttk.Combobox(option_frame, state="readonly" , values=opt_format , width=10)
cmb_format.current(0)
cmb_format.pack(side="left")
progress_frame = LabelFrame(root, text="진행상황")
progress_frame.pack(fill="x" , padx=5, pady=5 , ipady= 5)
p_var = DoubleVar()
progress_bar = ttk.Progressbar(progress_frame, maximum = 100 , variable=p_var)
progress_bar.pack(fill="x" ,padx=5, pady=5)
run_frame = Frame(root)
run_frame.pack(fill="x" , padx=5, pady=5)
btn_close = Button(run_frame, padx=5, pady=5, width=12, text="닫기" , command=root.quit)
btn_close.pack(side="right" , padx=5, pady=5)
btn_start = Button(run_frame, padx=5, pady=5, width=12, text="시작")
btn_start.pack(side="right" , padx=5, pady=5)
root.resizable(False, False)
root.mainloop()
#reverse() : 실제 순서를 뒤바꿈 revered(): 바뀐 새로운 값을 반환함 , 실제 값에는 영향을 미치지 않음
2. 함수정의 ( 폴더경로 , 시작 함수)
import tkinter.ttk as ttk
import tkinter.messagebox as msgbox # 메세지 박스 띄우기 위해 추가
from tkinter import *
from tkinter import filedialog # 서브모듈이라 임포트 해줘야 한다. 파일 찾기
root = Tk()
root.title("nado gui")
file_frame = Frame(root)
file_frame.pack(fill="x" , padx=5, pady=5)
# 함수정의
# 파일추가 #선택한 목록 저장
def add_file():
files = filedialog.askopenfilenames(title="이미지 파일을 선택하세요.", \
filetypes=(("PNG파일","*.png"),("모든파일","*")), \
initialdir=r"E:\PythonWorkspace\pygame_project\images") #최초에 C:/경로를 보여줌 r을 스트링이 그대로 쓰여진다.
#사용자가 선택한 파일 목록 파일 리스트에 뿌리기
for file in files:
list_file.insert(END,file)
# 선택삭제
def del_file():
#print(list_file.curselection()) #index 값 반환
for index in reversed(list_file.curselection()):
list_file.delete(index)
# 저장 경로 (폴더)
def browse_dest_path():
folder_selected = filedialog.askdirectory()
if folder_selected == '': #사용자가 취소를 누를때
return
#print(folder_selected)
txt_dest_path.delete(0,END)
txt_dest_path.insert(0, folder_selected)
#시작
def start():
# 각 옵션들 값을 확인
print("가로넓이 : ", cmb_width.get())
print("간격 : ", cmb_space.get())
print("포맷 : ", cmb_format.get())
#파일 목록 확인
if list_file.size() == 0 : #파일이 하나도 없다면
msgbox.showwarning("경고","이미지 파일을 추가하세요")
return # 빠져나간다.
#저장 경로 확인
if len(txt_dest_path.get()) == 0 : #파일이 하나도 없다면
msgbox.showwarning("경고","저장 경로를 선택하세요.")
return # 빠져나간다.
btn_add_file = Button(file_frame, padx=5, pady=5, width=12, text="파일추가", command=add_file)
btn_add_file.pack(side="left")
btn_del_file = Button(file_frame, padx=5, pady=5, width=12, text="선택삭제" ,command=del_file)
btn_del_file.pack(side="right")
list_frame = Frame(root)
list_frame.pack(fill="both" , padx=5, pady=5)
scrollbar = Scrollbar(list_frame)
scrollbar.pack(side="right" , fill="y")
list_file = Listbox(list_frame, selectmode = "extended" , height=15 , yscrollcommand=scrollbar.set)
list_file.pack(side="left" , fill="both" , expand=True)
scrollbar.config(command=list_file.yview)
path_frame = LabelFrame(root, text="저장경로")
path_frame.pack(fill="x" , padx=5, pady=5 , ipady= 5)
txt_dest_path = Entry(path_frame)
txt_dest_path.pack(side="left", fill="x", expand=True ,padx=5, pady=5 , ipady= 4)
btn_dest_path = Button(path_frame, text="찾아보기" , width=10 , command=browse_dest_path)
btn_dest_path.pack(side="right" , padx=5, pady=5)
option_frame = LabelFrame(root, text="옵션")
option_frame.pack(padx=5, pady=5 ,ipadx=5, ipady= 10)
lbl_width = Label(option_frame, text="가로넓이" , width=8)
lbl_width.pack(side="left")
opt_width = ["원본유지","1024","800","640"]
cmb_width = ttk.Combobox(option_frame, state="readonly" , values=opt_width , width=10)
cmb_width.current(0)
cmb_width.pack(side="left")
lbl_space = Label(option_frame, text="간격" , width=8)
lbl_space.pack(side="left")
opt_space = ["없음","좁게","보통","넓게"]
cmb_space= ttk.Combobox(option_frame, state="readonly" , values=opt_space , width=10)
cmb_space.current(0)
cmb_space.pack(side="left")
lbl_format = Label(option_frame, text="포맷" , width=8)
lbl_format.pack(side="left")
opt_format = ["PNG","JPG","BMP"]
cmb_format= ttk.Combobox(option_frame, state="readonly" , values=opt_format , width=10)
cmb_format.current(0)
cmb_format.pack(side="left")
progress_frame = LabelFrame(root, text="진행상황")
progress_frame.pack(fill="x" , padx=5, pady=5 , ipady= 5)
p_var = DoubleVar()
progress_bar = ttk.Progressbar(progress_frame, maximum = 100 , variable=p_var)
progress_bar.pack(fill="x" ,padx=5, pady=5)
run_frame = Frame(root)
run_frame.pack(fill="x" , padx=5, pady=5)
btn_close = Button(run_frame, padx=5, pady=5, width=12, text="닫기" , command=root.quit)
btn_close.pack(side="right" , padx=5, pady=5)
btn_start = Button(run_frame, padx=5, pady=5, width=12, text="시작" , command=start) # command=start 추가
btn_start.pack(side="right" , padx=5, pady=5)
root.resizable(False, False)
root.mainloop()
4. 이미지 합치기
코드
import os
import tkinter.ttk as ttk
import tkinter.messagebox as msgbox
from tkinter import *
from tkinter import filedialog
from PIL import Image # Paython Image Library 사용 위해
root = Tk()
root.title("nado gui")
file_frame = Frame(root)
file_frame.pack(fill="x" , padx=5, pady=5)
# 함수정의
# 파일추가 #선택한 목록 저장
def add_file():
files = filedialog.askopenfilenames(title="이미지 파일을 선택하세요.", \
filetypes=(("PNG파일","*.png"),("모든파일","*")), \
initialdir=r"E:\PythonWorkspace\pygame_project\images") #최초에 C:/경로를 보여줌 r을 스트링이 그대로 쓰여진다.
#사용자가 선택한 파일 목록 파일 리스트에 뿌리기
for file in files:
list_file.insert(END,file)
# 선택삭제
def del_file():
#print(list_file.curselection()) #index 값 반환
for index in reversed(list_file.curselection()):
list_file.delete(index)
# 저장 경로 (폴더)
def browse_dest_path():
folder_selected = filedialog.askdirectory()
if folder_selected == '': #사용자가 취소를 누를때
return
#print(folder_selected)
txt_dest_path.delete(0,END)
txt_dest_path.insert(0, folder_selected)
# 이미지 통합
def merge_image():
#print(list_file.get(0,END))
images = [Image.open(x) for x in list_file.get(0,END)]
# size -> size[0] : width, size[1] : height
# 가장 넓은 이미지의 넓이와 전체 높이를 구한다.
widths = [x.size[0] for x in images]
heights = [x.size[1] for x in images]
# print("width :", widths)
# print("height :", heights)
#스케치북 준비
max_width,total_height = max(widths),sum(heights)
# print("max width:", max_width)
# print("totalheight:", total_height)
result_img = Image.new("RGB", (max_width, total_height), (255,255,255)) # 배경 흰색
y_offset = 0 # x좌표는 그대로 지만 y좌표는 변경
for img in images:
result_img.paste(img,(0,y_offset)) #이미지 붙이고
y_offset += img.size[1] #height 값 만큼 더해줌
dest_path = os.path.join(txt_dest_path.get(), "nado_photo.jpg") # 최종 결과물 이미지명
result_img.save(dest_path) # 저장
msgbox.showinfo("알림", "작업이 완료 되었습니다.")
#시작
def start():
# 각 옵션들 값을 확인
print("가로넓이 : ", cmb_width.get())
print("간격 : ", cmb_space.get())
print("포맷 : ", cmb_format.get())
#파일 목록 확인
if list_file.size() == 0 : #파일이 하나도 없다면
msgbox.showwarning("경고","이미지 파일을 추가하세요")
return # 빠져나간다.
#저장 경로 확인
if len(txt_dest_path.get()) == 0 : #파일이 하나도 없다면
msgbox.showwarning("경고","저장 경로를 선택하세요.")
return # 빠져나간다.
# 이미지 통합 작업
merge_image()
btn_add_file = Button(file_frame, padx=5, pady=5, width=12, text="파일추가", command=add_file)
btn_add_file.pack(side="left")
btn_del_file = Button(file_frame, padx=5, pady=5, width=12, text="선택삭제" ,command=del_file)
btn_del_file.pack(side="right")
list_frame = Frame(root)
list_frame.pack(fill="both" , padx=5, pady=5)
scrollbar = Scrollbar(list_frame)
scrollbar.pack(side="right" , fill="y")
list_file = Listbox(list_frame, selectmode = "extended" , height=15 , yscrollcommand=scrollbar.set)
list_file.pack(side="left" , fill="both" , expand=True)
scrollbar.config(command=list_file.yview)
path_frame = LabelFrame(root, text="저장경로")
path_frame.pack(fill="x" , padx=5, pady=5 , ipady= 5)
txt_dest_path = Entry(path_frame)
txt_dest_path.pack(side="left", fill="x", expand=True ,padx=5, pady=5 , ipady= 4)
btn_dest_path = Button(path_frame, text="찾아보기" , width=10 , command=browse_dest_path)
btn_dest_path.pack(side="right" , padx=5, pady=5)
option_frame = LabelFrame(root, text="옵션")
option_frame.pack(padx=5, pady=5 ,ipadx=5, ipady= 10)
lbl_width = Label(option_frame, text="가로넓이" , width=8)
lbl_width.pack(side="left")
opt_width = ["원본유지","1024","800","640"]
cmb_width = ttk.Combobox(option_frame, state="readonly" , values=opt_width , width=10)
cmb_width.current(0)
cmb_width.pack(side="left")
lbl_space = Label(option_frame, text="간격" , width=8)
lbl_space.pack(side="left")
opt_space = ["없음","좁게","보통","넓게"]
cmb_space= ttk.Combobox(option_frame, state="readonly" , values=opt_space , width=10)
cmb_space.current(0)
cmb_space.pack(side="left")
lbl_format = Label(option_frame, text="포맷" , width=8)
lbl_format.pack(side="left")
opt_format = ["PNG","JPG","BMP"]
cmb_format= ttk.Combobox(option_frame, state="readonly" , values=opt_format , width=10)
cmb_format.current(0)
cmb_format.pack(side="left")
progress_frame = LabelFrame(root, text="진행상황")
progress_frame.pack(fill="x" , padx=5, pady=5 , ipady= 5)
p_var = DoubleVar()
progress_bar = ttk.Progressbar(progress_frame, maximum = 100 , variable=p_var)
progress_bar.pack(fill="x" ,padx=5, pady=5)
run_frame = Frame(root)
run_frame.pack(fill="x" , padx=5, pady=5)
btn_close = Button(run_frame, padx=5, pady=5, width=12, text="닫기" , command=root.quit)
btn_close.pack(side="right" , padx=5, pady=5)
btn_start = Button(run_frame, padx=5, pady=5, width=12, text="시작" , command=start) # command=start 추가
btn_start.pack(side="right" , padx=5, pady=5)
root.resizable(False, False)
root.mainloop()
5. 프로그레스바 연동
import os
import tkinter.ttk as ttk
import tkinter.messagebox as msgbox
from tkinter import *
from tkinter import filedialog
from PIL import Image # Paython Image Library 사용 위해
root = Tk()
root.title("nado gui")
file_frame = Frame(root)
file_frame.pack(fill="x" , padx=5, pady=5)
def add_file():
files = filedialog.askopenfilenames(title="이미지 파일을 선택하세요.", \
filetypes=(("PNG파일","*.png"),("모든파일","*")), \
initialdir=r"E:\PythonWorkspace\pygame_project\images") #최초에 C:/경로를 보여줌 r을 스트링이 그대로 쓰여진다.
for file in files:
list_file.insert(END,file)
def del_file():
for index in reversed(list_file.curselection()):
list_file.delete(index)
def browse_dest_path():
folder_selected = filedialog.askdirectory()
if folder_selected == '':
return
txt_dest_path.delete(0,END)
txt_dest_path.insert(0, folder_selected)
def merge_image():
images = [Image.open(x) for x in list_file.get(0,END)]
widths = [x.size[0] for x in images]
heights = [x.size[1] for x in images]
max_width,total_height = max(widths),sum(heights)
result_img = Image.new("RGB", (max_width, total_height), (255,255,255))
y_offset = 0
# for img in images:
# result_img.paste(img,(0,y_offset))
# y_offset += img.size[1]
# 프로그레스바에 표현 하기 위해 다시 처리
for idx , img in enumerate(images):
result_img.paste(img,(0,y_offset))
y_offset += img.size[1]
progress = (idx + 1) / len(images) * 100 # 실제 % 정보를 계산, idx 는 0부터 시작하므로 더하기 1
p_var.set(progress)
progress_bar.update()
dest_path = os.path.join(txt_dest_path.get(), "nado_photo.jpg")
result_img.save(dest_path)
msgbox.showinfo("알림", "작업이 완료 되었습니다.")
#시작
def start():
# 각 옵션들 값을 확인
print("가로넓이 : ", cmb_width.get())
print("간격 : ", cmb_space.get())
print("포맷 : ", cmb_format.get())
#파일 목록 확인
if list_file.size() == 0 : #파일이 하나도 없다면
msgbox.showwarning("경고","이미지 파일을 추가하세요")
return # 빠져나간다.
#저장 경로 확인
if len(txt_dest_path.get()) == 0 : #파일이 하나도 없다면
msgbox.showwarning("경고","저장 경로를 선택하세요.")
return # 빠져나간다.
# 이미지 통합 작업
merge_image()
btn_add_file = Button(file_frame, padx=5, pady=5, width=12, text="파일추가", command=add_file)
btn_add_file.pack(side="left")
btn_del_file = Button(file_frame, padx=5, pady=5, width=12, text="선택삭제" ,command=del_file)
btn_del_file.pack(side="right")
list_frame = Frame(root)
list_frame.pack(fill="both" , padx=5, pady=5)
scrollbar = Scrollbar(list_frame)
scrollbar.pack(side="right" , fill="y")
list_file = Listbox(list_frame, selectmode = "extended" , height=15 , yscrollcommand=scrollbar.set)
list_file.pack(side="left" , fill="both" , expand=True)
scrollbar.config(command=list_file.yview)
path_frame = LabelFrame(root, text="저장경로")
path_frame.pack(fill="x" , padx=5, pady=5 , ipady= 5)
txt_dest_path = Entry(path_frame)
txt_dest_path.pack(side="left", fill="x", expand=True ,padx=5, pady=5 , ipady= 4)
btn_dest_path = Button(path_frame, text="찾아보기" , width=10 , command=browse_dest_path)
btn_dest_path.pack(side="right" , padx=5, pady=5)
option_frame = LabelFrame(root, text="옵션")
option_frame.pack(padx=5, pady=5 ,ipadx=5, ipady= 10)
lbl_width = Label(option_frame, text="가로넓이" , width=8)
lbl_width.pack(side="left")
opt_width = ["원본유지","1024","800","640"]
cmb_width = ttk.Combobox(option_frame, state="readonly" , values=opt_width , width=10)
cmb_width.current(0)
cmb_width.pack(side="left")
lbl_space = Label(option_frame, text="간격" , width=8)
lbl_space.pack(side="left")
opt_space = ["없음","좁게","보통","넓게"]
cmb_space= ttk.Combobox(option_frame, state="readonly" , values=opt_space , width=10)
cmb_space.current(0)
cmb_space.pack(side="left")
lbl_format = Label(option_frame, text="포맷" , width=8)
lbl_format.pack(side="left")
opt_format = ["PNG","JPG","BMP"]
cmb_format= ttk.Combobox(option_frame, state="readonly" , values=opt_format , width=10)
cmb_format.current(0)
cmb_format.pack(side="left")
progress_frame = LabelFrame(root, text="진행상황")
progress_frame.pack(fill="x" , padx=5, pady=5 , ipady= 5)
p_var = DoubleVar()
progress_bar = ttk.Progressbar(progress_frame, maximum = 100 , variable=p_var)
progress_bar.pack(fill="x" ,padx=5, pady=5)
run_frame = Frame(root)
run_frame.pack(fill="x" , padx=5, pady=5)
btn_close = Button(run_frame, padx=5, pady=5, width=12, text="닫기" , command=root.quit)
btn_close.pack(side="right" , padx=5, pady=5)
btn_start = Button(run_frame, padx=5, pady=5, width=12, text="시작" , command=start) # command=start 추가
btn_start.pack(side="right" , padx=5, pady=5)
root.resizable(False, False)
root.mainloop()
6. zip 이용해보기
import os
import tkinter.ttk as ttk
import tkinter.messagebox as msgbox
from tkinter import *
from tkinter import filedialog
from PIL import Image # Paython Image Library 사용 위해
root = Tk()
root.title("nado gui")
file_frame = Frame(root)
file_frame.pack(fill="x" , padx=5, pady=5)
def add_file():
files = filedialog.askopenfilenames(title="이미지 파일을 선택하세요.", \
filetypes=(("PNG파일","*.png"),("모든파일","*")), \
initialdir=r"E:\PythonWorkspace\pygame_project\images") #최초에 C:/경로를 보여줌 r을 스트링이 그대로 쓰여진다.
for file in files:
list_file.insert(END,file)
def del_file():
for index in reversed(list_file.curselection()):
list_file.delete(index)
def browse_dest_path():
folder_selected = filedialog.askdirectory()
if folder_selected == '':
return
txt_dest_path.delete(0,END)
txt_dest_path.insert(0, folder_selected)
def merge_image():
images = [Image.open(x) for x in list_file.get(0,END)]
# widths = [x.size[0] for x in images]
# heights = [x.size[1] for x in images]
#zip 을 이용 위 두줄과 같은 결과
widths,heights = zip(*(x.size for x in images))
max_width,total_height = max(widths),sum(heights)
result_img = Image.new("RGB", (max_width, total_height), (255,255,255))
y_offset = 0
for idx , img in enumerate(images):
result_img.paste(img,(0,y_offset))
y_offset += img.size[1]
progress = (idx + 1) / len(images) * 100 # 실제 % 정보를 계산, idx 는 0부터 시작하므로 더하기 1
p_var.set(progress)
progress_bar.update()
dest_path = os.path.join(txt_dest_path.get(), "nado_photo.jpg")
result_img.save(dest_path)
msgbox.showinfo("알림", "작업이 완료 되었습니다.")
#시작
def start():
# 각 옵션들 값을 확인
print("가로넓이 : ", cmb_width.get())
print("간격 : ", cmb_space.get())
print("포맷 : ", cmb_format.get())
#파일 목록 확인
if list_file.size() == 0 : #파일이 하나도 없다면
msgbox.showwarning("경고","이미지 파일을 추가하세요")
return # 빠져나간다.
#저장 경로 확인
if len(txt_dest_path.get()) == 0 : #파일이 하나도 없다면
msgbox.showwarning("경고","저장 경로를 선택하세요.")
return # 빠져나간다.
# 이미지 통합 작업
merge_image()
btn_add_file = Button(file_frame, padx=5, pady=5, width=12, text="파일추가", command=add_file)
btn_add_file.pack(side="left")
btn_del_file = Button(file_frame, padx=5, pady=5, width=12, text="선택삭제" ,command=del_file)
btn_del_file.pack(side="right")
list_frame = Frame(root)
list_frame.pack(fill="both" , padx=5, pady=5)
scrollbar = Scrollbar(list_frame)
scrollbar.pack(side="right" , fill="y")
list_file = Listbox(list_frame, selectmode = "extended" , height=15 , yscrollcommand=scrollbar.set)
list_file.pack(side="left" , fill="both" , expand=True)
scrollbar.config(command=list_file.yview)
path_frame = LabelFrame(root, text="저장경로")
path_frame.pack(fill="x" , padx=5, pady=5 , ipady= 5)
txt_dest_path = Entry(path_frame)
txt_dest_path.pack(side="left", fill="x", expand=True ,padx=5, pady=5 , ipady= 4)
btn_dest_path = Button(path_frame, text="찾아보기" , width=10 , command=browse_dest_path)
btn_dest_path.pack(side="right" , padx=5, pady=5)
option_frame = LabelFrame(root, text="옵션")
option_frame.pack(padx=5, pady=5 ,ipadx=5, ipady= 10)
lbl_width = Label(option_frame, text="가로넓이" , width=8)
lbl_width.pack(side="left")
opt_width = ["원본유지","1024","800","640"]
cmb_width = ttk.Combobox(option_frame, state="readonly" , values=opt_width , width=10)
cmb_width.current(0)
cmb_width.pack(side="left")
lbl_space = Label(option_frame, text="간격" , width=8)
lbl_space.pack(side="left")
opt_space = ["없음","좁게","보통","넓게"]
cmb_space= ttk.Combobox(option_frame, state="readonly" , values=opt_space , width=10)
cmb_space.current(0)
cmb_space.pack(side="left")
lbl_format = Label(option_frame, text="포맷" , width=8)
lbl_format.pack(side="left")
opt_format = ["PNG","JPG","BMP"]
cmb_format= ttk.Combobox(option_frame, state="readonly" , values=opt_format , width=10)
cmb_format.current(0)
cmb_format.pack(side="left")
progress_frame = LabelFrame(root, text="진행상황")
progress_frame.pack(fill="x" , padx=5, pady=5 , ipady= 5)
p_var = DoubleVar()
progress_bar = ttk.Progressbar(progress_frame, maximum = 100 , variable=p_var)
progress_bar.pack(fill="x" ,padx=5, pady=5)
run_frame = Frame(root)
run_frame.pack(fill="x" , padx=5, pady=5)
btn_close = Button(run_frame, padx=5, pady=5, width=12, text="닫기" , command=root.quit)
btn_close.pack(side="right" , padx=5, pady=5)
btn_start = Button(run_frame, padx=5, pady=5, width=12, text="시작" , command=start) # command=start 추가
btn_start.pack(side="right" , padx=5, pady=5)
root.resizable(False, False)
root.mainloop()
5. 옵션처리
import os
import tkinter.ttk as ttk
import tkinter.messagebox as msgbox
from tkinter import *
from tkinter import filedialog
from PIL import Image # Paython Image Library 사용 위해
root = Tk()
root.title("nado gui")
file_frame = Frame(root)
file_frame.pack(fill="x" , padx=5, pady=5)
def add_file():
files = filedialog.askopenfilenames(title="이미지 파일을 선택하세요.", \
filetypes=(("PNG파일","*.png"),("모든파일","*")), \
initialdir=r"E:\PythonWorkspace\pygame_project\images") #최초에 C:/경로를 보여줌 r을 스트링이 그대로 쓰여진다.
for file in files:
list_file.insert(END,file)
def del_file():
for index in reversed(list_file.curselection()):
list_file.delete(index)
def browse_dest_path():
folder_selected = filedialog.askdirectory()
if folder_selected == '':
return
txt_dest_path.delete(0,END)
txt_dest_path.insert(0, folder_selected)
# 이미지 통합
def merge_image():
# print("가로넓이 : ", cmb_width.get())
# print("간격 : ", cmb_space.get())
# print("포맷 : ", cmb_format.get())
# 가로 넓이
img_width = cmb_width.get() #콤보의 선택값 가지고 온다
if img_width == "원본유지":
img_width= -1 # -1일 때는 원본 기준으로 원본을 통합해라
else:
img_width= int(img_width)
#간격
img_space = cmb_space.get()
if img_space == "좁게" :
img_space = 30
elif img_space == "보통" :
img_space = 60
elif img_space == "넓게" :
img_space = 90
else :
img_space = 0
img_format = cmb_format.get().lower() #PNG, JPG,BMP 를 소문자로 변경
images = [Image.open(x) for x in list_file.get(0,END)]
#이미지 사이즈 리스트 넣어서 하나씩 처리
imate_sizes = [] # [(width1,height1),(width2,height2), ...]
if img_width > -1:
# width 값 변경
image_sizes = [int(img_width), int(img_width * x.size[1]/x.size[0]) for x in images]
else:
image_sizes = [(x.size[0],x.size[1]) for x in images] # 원본 사이즈 사용
#계산식
# 100x 60 이미지 -> width를 80으로 줄이면 height는?
# 원본 width: 원본 height = 변경 width : 변경 height
# 100 : 60 = 80 : ?
# x : y = x' : y'
# xy' = x'y
# y; = x'y / x -> 이 식을 적용하면 된다.
# 10: 60 = 80 : 48
# 코드에 대입
# x = width = size[0]
# y = height = size[1]
# x' = img_width # 이 값으로 변경 해야 함
# y' = x'y / x = img_width * size[1] / size[0]
widths,heights = zip(*(image_sizes))
max_width,total_height = max(widths),sum(heights)
result_img = Image.new("RGB", (max_width, total_height), (255,255,255))
y_offset = 0
for idx , img in enumerate(images):
result_img.paste(img,(0,y_offset))
y_offset += img.size[1]
progress = (idx + 1) / len(images) * 100 # 실제 % 정보를 계산, idx 는 0부터 시작하므로 더하기 1
p_var.set(progress)
progress_bar.update()
dest_path = os.path.join(txt_dest_path.get(), "nado_photo.jpg")
result_img.save(dest_path)
msgbox.showinfo("알림", "작업이 완료 되었습니다.")
#시작
def start():
# 각 옵션들 값을 확인
# print("가로넓이 : ", cmb_width.get())
# print("간격 : ", cmb_space.get())
# print("포맷 : ", cmb_format.get())
#파일 목록 확인
if list_file.size() == 0 : #파일이 하나도 없다면
msgbox.showwarning("경고","이미지 파일을 추가하세요")
return # 빠져나간다.
#저장 경로 확인
if len(txt_dest_path.get()) == 0 : #파일이 하나도 없다면
msgbox.showwarning("경고","저장 경로를 선택하세요.")
return # 빠져나간다.
# 이미지 통합 작업
merge_image()
btn_add_file = Button(file_frame, padx=5, pady=5, width=12, text="파일추가", command=add_file)
btn_add_file.pack(side="left")
btn_del_file = Button(file_frame, padx=5, pady=5, width=12, text="선택삭제" ,command=del_file)
btn_del_file.pack(side="right")
list_frame = Frame(root)
list_frame.pack(fill="both" , padx=5, pady=5)
scrollbar = Scrollbar(list_frame)
scrollbar.pack(side="right" , fill="y")
list_file = Listbox(list_frame, selectmode = "extended" , height=15 , yscrollcommand=scrollbar.set)
list_file.pack(side="left" , fill="both" , expand=True)
scrollbar.config(command=list_file.yview)
path_frame = LabelFrame(root, text="저장경로")
path_frame.pack(fill="x" , padx=5, pady=5 , ipady= 5)
txt_dest_path = Entry(path_frame)
txt_dest_path.pack(side="left", fill="x", expand=True ,padx=5, pady=5 , ipady= 4)
btn_dest_path = Button(path_frame, text="찾아보기" , width=10 , command=browse_dest_path)
btn_dest_path.pack(side="right" , padx=5, pady=5)
option_frame = LabelFrame(root, text="옵션")
option_frame.pack(padx=5, pady=5 ,ipadx=5, ipady= 10)
lbl_width = Label(option_frame, text="가로넓이" , width=8)
lbl_width.pack(side="left")
opt_width = ["원본유지","1024","800","640"]
cmb_width = ttk.Combobox(option_frame, state="readonly" , values=opt_width , width=10)
cmb_width.current(0)
cmb_width.pack(side="left")
lbl_space = Label(option_frame, text="간격" , width=8)
lbl_space.pack(side="left")
opt_space = ["없음","좁게","보통","넓게"]
cmb_space= ttk.Combobox(option_frame, state="readonly" , values=opt_space , width=10)
cmb_space.current(0)
cmb_space.pack(side="left")
lbl_format = Label(option_frame, text="포맷" , width=8)
lbl_format.pack(side="left")
opt_format = ["PNG","JPG","BMP"]
cmb_format= ttk.Combobox(option_frame, state="readonly" , values=opt_format , width=10)
cmb_format.current(0)
cmb_format.pack(side="left")
progress_frame = LabelFrame(root, text="진행상황")
progress_frame.pack(fill="x" , padx=5, pady=5 , ipady= 5)
p_var = DoubleVar()
progress_bar = ttk.Progressbar(progress_frame, maximum = 100 , variable=p_var)
progress_bar.pack(fill="x" ,padx=5, pady=5)
run_frame = Frame(root)
run_frame.pack(fill="x" , padx=5, pady=5)
btn_close = Button(run_frame, padx=5, pady=5, width=12, text="닫기" , command=root.quit)
btn_close.pack(side="right" , padx=5, pady=5)
btn_start = Button(run_frame, padx=5, pady=5, width=12, text="시작" , command=start) # command=start 추가
btn_start.pack(side="right" , padx=5, pady=5)
root.resizable(False, False)
root.mainloop()
최종
import os
import tkinter.ttk as ttk
import tkinter.messagebox as msgbox
from tkinter import *
from tkinter import filedialog
from PIL import Image
root = Tk()
root.title("nado gui")
file_frame = Frame(root)
file_frame.pack(fill="x" , padx=5, pady=5)
def add_file():
files = filedialog.askopenfilenames(title="이미지 파일을 선택하세요.", \
filetypes=(("PNG파일","*.png"),("모든파일","*")), \
initialdir=r"E:\PythonWorkspace\pygame_project\images")
for file in files:
list_file.insert(END,file)
def del_file():
for index in reversed(list_file.curselection()):
list_file.delete(index)
def browse_dest_path():
folder_selected = filedialog.askdirectory()
if folder_selected == '':
return
txt_dest_path.delete(0,END)
txt_dest_path.insert(0, folder_selected)
def merge_image():
try:
img_width = cmb_width.get()
if img_width == "원본유지":
img_width= -1
else:
img_width= int(img_width)
img_space = cmb_space.get()
if img_space == "좁게" :
img_space = 30
elif img_space == "보통" :
img_space = 60
elif img_space == "넓게" :
img_space = 90
else :
img_space = 0
img_format = cmb_format.get().lower()
images = [Image.open(x) for x in list_file.get(0,END)]
image_sizes = []
if img_width > -1 :
image_sizes = [(int(img_width), int(img_width * x.size[1] / x.size[0])) for x in images]
else :
image_sizes = [(x.size[0],x.size[1]) for x in images]
widths,heights = zip(*(image_sizes))
max_width,total_height = max(widths),sum(heights)
#스케치북 준비
# 옵션 중 스페이스 주기 위한 작업
if img_space > 0 :
total_height += (img_space * (len(images) - 1))
result_img = Image.new("RGB", (max_width, total_height), (255,255,255))
y_offset = 0
for idx , img in enumerate(images):
#width가 원본유지가 아닐 때에는 이미지 크기 조정
if img_width > -1:
img = img.resize(image_sizes[idx])
result_img.paste(img,(0,y_offset))
y_offset += (img.size[1] + img_space) #heigt 값 + 사용자가 지정한 간격
progress = (idx + 1) / len(images) * 100
p_var.set(progress)
progress_bar.update()
# 포맷 옵션 처리
file_name = "nado_photo." + img_format
dest_path = os.path.join(txt_dest_path.get(), file_name)
result_img.save(dest_path)
msgbox.showinfo("알림", "작업이 완료 되었습니다.")
except Exception as err : # 예외처리
msgbox.showerror("에러" , err)
#시작
def start():
#파일 목록 확인
if list_file.size() == 0 : #파일이 하나도 없다면
msgbox.showwarning("경고","이미지 파일을 추가하세요")
return # 빠져나간다.
#저장 경로 확인
if len(txt_dest_path.get()) == 0 : #파일이 하나도 없다면
msgbox.showwarning("경고","저장 경로를 선택하세요.")
return # 빠져나간다.
# 이미지 통합 작업
merge_image()
btn_add_file = Button(file_frame, padx=5, pady=5, width=12, text="파일추가", command=add_file)
btn_add_file.pack(side="left")
btn_del_file = Button(file_frame, padx=5, pady=5, width=12, text="선택삭제" ,command=del_file)
btn_del_file.pack(side="right")
list_frame = Frame(root)
list_frame.pack(fill="both" , padx=5, pady=5)
scrollbar = Scrollbar(list_frame)
scrollbar.pack(side="right" , fill="y")
list_file = Listbox(list_frame, selectmode = "extended" , height=15 , yscrollcommand=scrollbar.set)
list_file.pack(side="left" , fill="both" , expand=True)
scrollbar.config(command=list_file.yview)
path_frame = LabelFrame(root, text="저장경로")
path_frame.pack(fill="x" , padx=5, pady=5 , ipady= 5)
txt_dest_path = Entry(path_frame)
txt_dest_path.pack(side="left", fill="x", expand=True ,padx=5, pady=5 , ipady= 4)
btn_dest_path = Button(path_frame, text="찾아보기" , width=10 , command=browse_dest_path)
btn_dest_path.pack(side="right" , padx=5, pady=5)
option_frame = LabelFrame(root, text="옵션")
option_frame.pack(padx=5, pady=5 ,ipadx=5, ipady= 10)
lbl_width = Label(option_frame, text="가로넓이" , width=8)
lbl_width.pack(side="left")
opt_width = ["원본유지","1024","800","640"]
cmb_width = ttk.Combobox(option_frame, state="readonly" , values=opt_width , width=10)
cmb_width.current(0)
cmb_width.pack(side="left")
lbl_space = Label(option_frame, text="간격" , width=8)
lbl_space.pack(side="left")
opt_space = ["없음","좁게","보통","넓게"]
cmb_space= ttk.Combobox(option_frame, state="readonly" , values=opt_space , width=10)
cmb_space.current(0)
cmb_space.pack(side="left")
lbl_format = Label(option_frame, text="포맷" , width=8)
lbl_format.pack(side="left")
opt_format = ["PNG","JPG","BMP"]
cmb_format= ttk.Combobox(option_frame, state="readonly" , values=opt_format , width=10)
cmb_format.current(0)
cmb_format.pack(side="left")
progress_frame = LabelFrame(root, text="진행상황")
progress_frame.pack(fill="x" , padx=5, pady=5 , ipady= 5)
p_var = DoubleVar()
progress_bar = ttk.Progressbar(progress_frame, maximum = 100 , variable=p_var)
progress_bar.pack(fill="x" ,padx=5, pady=5)
run_frame = Frame(root)
run_frame.pack(fill="x" , padx=5, pady=5)
btn_close = Button(run_frame, padx=5, pady=5, width=12, text="닫기" , command=root.quit)
btn_close.pack(side="right" , padx=5, pady=5)
btn_start = Button(run_frame, padx=5, pady=5, width=12, text="시작" , command=start) # command=start 추가
btn_start.pack(side="right" , padx=5, pady=5)
root.resizable(False, False)
root.mainloop()
더보기
블로그에는 우클릭 방지가 걸려있어요. 코드복사는 카페에서 가능 합니다.
파이썬 기초는 나도코딩님이 인프런사이트에서 강의한 내용을 바탕으로 공부한 내용을 정리한 것 입니다.
추천 : ★★★★★
'코딩(개발) > 파이썬' 카테고리의 다른 글
파이썬 스크랩데이터 csv로 저장하기 (0) | 2021.01.01 |
---|---|
파이썬 웹스크래핑1 (0) | 2020.12.31 |
파이썬 오토스크린 샷 (0) | 2020.12.30 |
파이썬 GUI (0) | 2020.12.29 |
파이썬 게임 2 (0) | 2020.12.27 |
댓글