본문 바로가기
코딩 연습/코딩배우기

파이썬 Tkinter 처음부터 차근차근 따라 하면서 배워보기

by good4me 2021. 11. 24.

goodthings4me.tistory.com

파이썬 Tkinter는 파이썬으로 gui 프로그램을 만들 수 있도록 여러 컨테이너를 제공하는 라이브러리로 이를 배워두면 PC에서 실행할 수 있는 여러 응용 프로그램을 만들 수 있다. 그리고 tkinter는 button위젯, text위젯, frame위젯 등 모든 것이 위젯으로 구성되었다.

 

 

파이썬 Tkinter 모듈 따라 하면서 배우기

■ Label() 위젯

☞ tkinter 모듈의 Tk() 호출

 

☞ pakc() : 윈도우 스크린에 보이게 하기

 

 

☞ 아래로 위젯 배치

 

 

▣ 그리드 활용

☞ grid(row= , colume= ) 사용 시

 

 

good4me.co.kr

 

■ Button() 위젯

☞ btn2 위젯은 DISABLED 시킴

 

 

☞ 버튼 사이즈 변경 - padx, pady

 

 

☞ fg=color, bg=color, command=함수 호출 → "Click" 버튼 누를 때마다 Label 위젯을 호출해 표시

- fg(foreground color), bg(background color) → RGB 색상코드도 입력 가능

 

 

 

 

■ Input Filed 관련 위젯 - Entry()

☞ 한 줄 입력하는 Entry 위젯

- 속성 : width, border, borderwidth, relief

- border의 relief는 solid, raised, ridge, groove, sunken, flat 중에서 선택할 수 있다.

 

☞ Button의 command=로 호출된 함수의 label1 위젯에서 Entry 위젯의 값을 text= 값으로 사용함

 

 

 

■ 계산기 만들어보기

from tkinter import *

root = Tk()
root.title('간단한 계산기')
# root.geometry('300x400+800+100')

entry = Entry(root, width=40, borderwidth=5)
entry.grid(row=0, column=0, columnspan=5, padx=10, pady=10)

def btn_click(number):
    current = entry.get()  # 입력값 얻기
    entry.delete(0, END)  # 입력값 지우기
    entry.insert(0, str(current) + str(number))  # 얻은 입력값에 새로운 값 붙이기
    return

def content_clear():
    entry.delete(0, END)

def content_add():
    first_number = entry.get()
    global f_num
    global math
    math = 'add'
    f_num = int(first_number)
    entry.delete(0, END)

def content_sub():
    first_number = entry.get()
    global f_num
    global math
    math = 'sub'    
    f_num = int(first_number)
    entry.delete(0, END)

def content_mul():
    first_number = entry.get()
    global f_num
    global math
    math = 'mul'    
    f_num = int(first_number)
    entry.delete(0, END)

def content_div():
    first_number = entry.get()
    global f_num
    global math
    math = 'div'    
    f_num = int(first_number)
    entry.delete(0, END)

def contetn_equal():
    second_number = entry.get()
    entry.delete(0, END)
    if math == 'add':
        entry.insert(0, f_num + int(second_number))
    if math == 'sub':
        entry.insert(0, f_num - int(second_number))
    if math == 'mul':
        entry.insert(0, f_num * int(second_number))
    if math == 'div':
        entry.insert(0, f_num / int(second_number))                

button1 = Button(root, text='1', padx=30, pady=20, command=lambda: btn_click(1))
button2 = Button(root, text='2', padx=30, pady=20, command=lambda: btn_click(2))
button3 = Button(root, text='3', padx=30, pady=20, command=lambda: btn_click(3))
button4 = Button(root, text='4', padx=30, pady=20, command=lambda: btn_click(4))
button5 = Button(root, text='5', padx=30, pady=20, command=lambda: btn_click(5))
button6 = Button(root, text='6', padx=30, pady=20, command=lambda: btn_click(6))
button7 = Button(root, text='7', padx=30, pady=20, command=lambda: btn_click(7))
button8 = Button(root, text='8', padx=30, pady=20, command=lambda: btn_click(8))
button9 = Button(root, text='9', padx=30, pady=20, command=lambda: btn_click(9))
button0 = Button(root, text='0', padx=30, pady=20, command=lambda: btn_click(0))

btn_add = Button(root, text='+', padx=30, pady=20, command=content_add)
btn_sub = Button(root, text='-', padx=30, pady=20, command=content_sub)
btn_mul = Button(root, text='x', padx=30, pady=20, command=content_mul)
btn_div = Button(root, text='÷', padx=30, pady=20, command=content_div)
btn_equal = Button(root, text='=', padx=30, pady=20, command=contetn_equal)
btn_clear = Button(root, text='C', padx=30, pady=20, command=content_clear)

button1.grid(row=1, column=0)
button2.grid(row=1, column=1)
button3.grid(row=1, column=2)
btn_add.grid(row=1, column=3)

button4.grid(row=2, column=0)
button5.grid(row=2, column=1)
button6.grid(row=2, column=2)
btn_sub.grid(row=2, column=3)

button7.grid(row=3, column=0)
button8.grid(row=3, column=1)
button9.grid(row=3, column=2)
btn_mul.grid(row=3, column=3)

button0.grid(row=4, column=0)
btn_clear.grid(row=4, column=1)
btn_equal.grid(row=4, column=2)
btn_div.grid(row=4, column=3)

mainloop()

 

 

 

■ Tkinter Icon 붙이기, 이미지 뷰어 만들기

# pillow 모듈 설치 : pip install pillow

# PIL(pillow) 모듈 import : from PIL import ImageTk, Image

☞ 아이콘이나 이미지를 불러와서 Tkinter 창에 표시하기

- tkinter icon 변경 : root.iconbitmap()

- 버튼 클릭 시 창 닫히게 하기 : command=root.quit

- 이미지를 불러와서 Tkinter 창에 표시 : ImageTk.PhotoImage()와 Image.open() 활용

 

 

▣ 기능 확장해보기

- 이미지 넘기기(forward, back), 이미지수 표시

from tkinter import *
from PIL import ImageTk, Image

root = Tk()
root.title('Tkinter 연습')
root.iconbitmap('./image/ico/g4m.ico')

image1 = ImageTk.PhotoImage(Image.open('./image/imagetk/output/image_01.jpg'))
image2 = ImageTk.PhotoImage(Image.open('./image/imagetk/output/image_02.jpg'))
image3 = ImageTk.PhotoImage(Image.open('./image/imagetk/output/image_03.jpg'))
image4 = ImageTk.PhotoImage(Image.open('./image/imagetk/output/image_04.jpg'))
image5 = ImageTk.PhotoImage(Image.open('./image/imagetk/output/image_05.jpg'))

img_lst = [image1, image2, image3, image4, image5]
status = Label(root, text=f'Image 1 of {str(len(img_lst))}', bd=1, relief=SUNKEN, anchor=E)  # anchor=E 우측으로
status.grid(row=2, column=0, columnspan=3, pady=5, padx=5, sticky=W+E)  # sticky= 좌우로 늘리기
label1 = Label(image=image1)  # 1번째 이미지 셋팅
label1.grid(row=0, column=0, columnspan=3, padx=5, pady=5)


def forward(img_num):
    global label1
    global btn_forward
    global btn_back

    label1.grid_forget()  # grid() 사라짐
    label1 = Label(image=img_lst[img_num - 1])
    btn_forward = Button(root, text='>>', command=lambda: forward(img_num + 1))
    btn_back = Button(root, text='<<', command=lambda: back(img_num - 1))

    if img_num == len(img_lst):  # 이미지 수 체크해 비활성화
        btn_forward = Button(root, text='>>', state=DISABLED)

    label1.grid(row=0, column=0, columnspan=3)
    btn_back.grid(row=1, column=0, pady=5)
    btn_forward.grid(row=1, column=1)
    
    status = Label(root, text=f'Image {img_num} of {str(len(img_lst))}', bd=1, relief=SUNKEN, anchor=E)  # anchor=E 우측으로
    status.grid(row=2, column=0, columnspan=3, pady=5, padx=5, sticky=W+E)  # sticky= 좌우로 늘리기


def back(img_num):
    global label1
    global btn_forward
    global btn_back

    label1.grid_forget()  # grid() 사라짐
    label1 = Label(image=img_lst[img_num - 1])
    btn_forward = Button(root, text='>>', command=lambda: forward(img_num + 1))
    btn_back = Button(root, text='<<', command=lambda: back(img_num - 1))

    if img_num == 1:
        btn_back = Button(root, text='>>', state=DISABLED)

    label1.grid(row=0, column=0, columnspan=3)
    btn_back.grid(row=1, column=0, pady=5)
    btn_forward.grid(row=1, column=1)

    status = Label(root, text=f'Image {str(img_num)} of {str(len(img_lst))}', bd=1, relief=SUNKEN, anchor=E)  # anchor=E 우측으로
    status.grid(row=2, column=0, columnspan=3, pady=5, padx=5, sticky=W+E)  # sticky= 좌우로 늘리기


# btn_back = Button(root, text='<<', command=back, state=DISABLED)
btn_back = Button(root, text='<<', state=DISABLED)
btn_back.grid(row=1, column=0, pady=5)

btn_forward = Button(root, text='>>', command=lambda: forward(2))  # 클릭 시 2번째부터  
btn_forward.grid(row=1, column=1)

btn_quit = Button(root, text='닫기', command=root.quit)
btn_quit.grid(row=1, column=2)

mainloop()

 

 

 

 

 

■ LabelFrame

 

 

 

■ Radiobutton

 

☞ 레디오버튼 선택 시 Label에 값 표시

 

☞ 값을 선택하고 버튼 클릭 시 Label에 값 표시

 

 

 

 

■ 메시지 박스

☞ 메시지 박스 종류

shomwinfo, showwarning, showerror, askquestion, askokcancel, askyesno

 

 

 

■ 새 창 만들기

☞ Toplebel()로 새창을 만들고 Tk()와 동일한 방법으로 사용 가능

 

 

☞ 버튼을 만들어서 새창을 호출하고 닫기 (top.destroy)

 

 

 

■ 파일 가져오기 - 다이알로그 박스

# filedialog 모듈 추가

from tkinter import filedialog
from tkinter import *
from PIL import ImageTk, Image
from tkinter import filedialog

root = Tk()
root.title('Tkinter 연습')
root.geometry('300x350+800+100')

# filedialog.askopenfilename : 파일 오픈이 아닌 파일의 위치와 파일명을 리턴해줌
root.filename = filedialog.askopenfilename(initialdir='./image/imagetk/output', title='파일선택',
                filetypes=(('jpg files', '*.jpg'), ('png files', '*.png'), ('all files', '*.*')))
label1 = Label(root, text=root.filename).pack()
image = ImageTk.PhotoImage(Image.open(root.filename))  # 파일위치와 파일명
img_label = Label(image=image).pack()

mainloop()

# filedialog.askopenfilename(initialdir='./image/imagetk/output', title='파일선택', filetypes=(('jpg files', '*.jpg'), ('png files', '*.png'), ('all files', '*.*')))

filedialog.askopenfilename

 

 

▣ 버튼 클릭 시 이미지 파일을 가져와서 보여주도록 함수로 처리

 

 

 

■ 슬라이더

# Scale()

 

 

 

▣ 수평 슬라이더에 따라 창 크기 변경

from tkinter import *

root = Tk()
root.title('Tkinter 연습')
root.geometry('250x200+800+100')

vertical = Scale(root, from_=0, to=200)
vertical.pack()
horizontal = Scale(root, from_=0, to=400, orient=HORIZONTAL)
horizontal.pack()

def slide():
    label1 = Label(root, text=horizontal.get()).pack()
    root.geometry(str(horizontal.get()) + 'x400+800+100')

btn1 = Button(root, text='Click', command=slide).pack()

mainloop()

 

 

 

■ 체크박스(버튼)

# Checkbutton

# 체크되면 1, 안되면 0

# 문자(열)인 경우 onvalue=, offvalue= 에 값 설정 후 실행시킬 수 있음

 

 

■ 드롭박스(옵션 메뉴)

# OptionMenu()

☞ 메뉴 클릭 시 리스트가 보임

 

 

☞ 기능

- options 변수 만들고 요일 리스트 할당,

- 초기값으로 index 0번 설정,

- options 리스트는 가변 매개변수 *options로,

- show() 함수로 Label() 만들어서 선택된 값을 출력

 

 

 

■ Tkinter에서 데이터베이스 사용하는 방법

from tkinter import *
import sqlite3

root = Tk()
root.title('Tkinter 연습')

# database 생성 및 연결
conn = sqlite3.connect('address.db')
cursor = conn.cursor()  # 커서 생성

# # table 생성 - 생성되면 주석 처리함
# cursor.execute('''create table addresstb (
#             name text,
#             tel text,
#             address text
#             )''')

name_label = Label(root, text='이름')
name_label.grid(row=0, column=0)
name = Entry(root, width=10)
name.grid(row=0, column=1, padx=20, pady=5)

tel_label = Label(root, text='전화번호')
tel_label.grid(row=1, column=0)
tel = Entry(root, width=20)
tel.grid(row=1, column=1, padx=20, pady=5)

address_label = Label(root, text='주소')
address_label.grid(row=2, column=0)
address = Entry(root, width=30)
address.grid(row=2, column=1, padx=20, pady=5)

submit_btn = Button(root, text='저장', command='submit')
submit_btn.grid(row=3, column=0, columnspan=2, padx=10, pady=10, ipadx=30)

conn.commit()
conn.close()

mainloop()

 

 

▣ CRUD 해보기

from tkinter import *
import sqlite3

root = Tk()
root.title('Tkinter 연습')

# # database 생성 및 연결
# conn = sqlite3.connect('address.db')
# cur = conn.cursor()  # 커서 생성
#
# # table 생성 - 생성되면 주석 처리함
# cur.execute('''create table addresstb (
#             name text,
#             tel text,
#             address text
#             )''')
#
# conn.commit()
# conn.close()

def submit():
    conn = sqlite3.connect('address.db')
    cur = conn.cursor()  # 커서 생성

    # 데이터 입력
    cur.execute('insert into addresstb values(:name, :tel, :address)', {
            'name': name.get(),
            'tel': tel.get(),
            'address': address.get()
            })

    conn.commit()
    conn.close()

    name.delete(0, END)  # 입력값 지우기
    tel.delete(0, END)
    address.delete(0, END)


def select_query():
    conn = sqlite3.connect('address.db')
    cur = conn.cursor()

    # 데이터 조회
    cur.execute('select *, oid from addresstb')
    rs = cur.fetchall()
    print(rs)
    records = ''
    for record in rs:  # rs[0]: # rs[0]는 맨 처음 값 1개
        records += str(record) + '\n'

    # for record in rs:  # 구분자를 넣어서 문자열로 관리
    #     records += record[0] + '/' + record[1] + '/' + record[2] + '\n'

    q_label = Label(root, text=records)
    q_label.grid(row=5, column=0, columnspan=3)

    conn.commit()
    conn.close()

    name.delete(0, END)
    tel.delete(0, END)
    address.delete(0, END)


def delete_query():
    conn = sqlite3.connect('address.db')
    cur = conn.cursor()

    # 데이터 삭제
    cur.execute('delete from addresstb where oid = ' + delete_entry.get())
    print('삭제!!')
    del_label = Label(root, text='oid ' + delete_entry.get() + ' 삭제 완료!')
    del_label.grid(row=8, column=0, columnspan=3)

    conn.commit()
    conn.close()

    name.delete(0, END)
    tel.delete(0, END)
    address.delete(0, END)


def update():
    conn = sqlite3.connect('address.db')
    cur = conn.cursor()
    record_id = delete_entry.get()

    # 데이터 업데이트
    cur.execute('UPDATE addresstb SET name=:name, tel=:tel, address=:address WHERE oid=:oid', {
            'name': edit_name.get(),
            'tel': edit_tel.get(),
            'address': edit_address.get(),
            'oid': record_id
            })

    print('수정 완료!!')
    result_update_label = Label(root, text='oid ' + delete_entry.get() + ' 수정 완료!')
    result_update_label.grid(row=10, column=0, columnspan=3)

    conn.commit()
    conn.close()
    delete_entry.delete(0, END)
    editor.destroy()


def edit():
    global editor
    editor = Tk()  # 새창 만들어서 업데이트 진행
    editor.title('Update Records')

    conn = sqlite3.connect('address.db')
    cur = conn.cursor()  # 커서 생성
    record_id = delete_entry.get()
    cur.execute('select * from addresstb where oid=' + record_id)
    rs = cur.fetchall()
    print(rs)

    conn.commit()
    conn.close()

    global edit_name
    global edit_tel
    global edit_address

    edit_name_label = Label(editor, text='이름')
    edit_name_label.grid(row=0, column=0)
    edit_name = Entry(editor, width=30)
    edit_name.grid(row=0, column=1, padx=20, pady=5)

    edit_tel_label = Label(editor, text='전화번호')
    edit_tel_label.grid(row=1, column=0)
    edit_tel = Entry(editor, width=30)
    edit_tel.grid(row=1, column=1, padx=20, pady=5)

    edit_address_label = Label(editor, text='주소')
    edit_address_label.grid(row=2, column=0)
    edit_address = Entry(editor, width=30)
    edit_address.grid(row=2, column=1, padx=20, pady=5)

    edit_save_btn = Button(editor, text='수정하기', command=update)
    edit_save_btn.grid(row=3, column=0, columnspan=3, padx=10, pady=10, ipadx=30)

    for record in rs:
        edit_name.insert(0, record[0])
        edit_tel.insert(0, record[1])
        edit_address.insert(0, record[2])


name_label = Label(root, text='이름')
name_label.grid(row=0, column=0)
name = Entry(root, width=30)
name.grid(row=0, column=1, padx=20, pady=5)

tel_label = Label(root, text='전화번호')
tel_label.grid(row=1, column=0)
tel = Entry(root, width=30)
tel.grid(row=1, column=1, padx=20, pady=5)

address_label = Label(root, text='주소')
address_label.grid(row=2, column=0)
address = Entry(root, width=30)
address.grid(row=2, column=1, padx=20, pady=5)

delete_label = Label(root, text='선택 ID')
delete_label.grid(row=6, column=0, pady=5)
delete_entry = Entry(root, width=30)
delete_entry.grid(row=6, column=1, pady=5)

submit_btn = Button(root, text='저장', command=submit)
submit_btn.grid(row=3, column=0, columnspan=2, padx=10, pady=10, ipadx=53)

q_select_btn = Button(root, text='Select Record', command=select_query)
q_select_btn.grid(row=4, column=0, columnspan=3, padx=10, pady=10, ipadx=30)

q_del_btn = Button(root, text='Delete Record', command=delete_query)
q_del_btn.grid(row=7, column=0, columnspan=3, padx=10, pady=10, ipadx=30)

q_update_btn = Button(root, text='Update Record', command=edit)
q_update_btn.grid(row=9, column=0, columnspan=3, padx=10, pady=10, ipadx=30)

mainloop()

 

 

 

※ [출처] Tkinter Course - Create Graphic User Interfaces in Python Tutorial

 

 

tkinter 예제 따라하면서 배워보기>>

 

 

파이썬 GUI 모듈 tkinter 연습(쿠팡 파트너스 상품 링크 관리 프로그램 만들기)

파이썬 GUI 프로그램 작성용 tkinter 모듈을 이용하여 쿠팡 파트너스에서 생성한 간편 링크인 쿠팡 단축 URL을 관리하는 프로그램을 만들어보는 예제 소스코드 파이썬 tkinter로 쿠팡 파트너스 링크

goodthings4me.tistory.com

 

 

댓글