4 분 소요

SQL과 파이썬 연결

GUI 응용 프로그램

GUI(Graphical User Interface)는 윈도에 그래픽 환경으로 제공되는 화면을 통틀어서 말한다.
파이썬을 통해 윈도에 출력되는 GUI 응용 프로그램을 작성할 수 있다.

이를 도와주는 것이 tkinter라는 라이브러리이다.
tkinter를 활용하면 흔히 사용하는 엑셀, 한글, 크롬 등의 응용 프로그램과 비슷한 형태의 프로그램을 만들 수 있다.

GUI 기본 프로그래밍

파이썬은 윈도 화면을 제공하는 다양한 방법을 제공한다.
그중 가장 기본적이고 쉽게 이용할 수 있는 윈도 생성 라이브러리인 tkinter에 대해 살펴보겠다.

기본 윈도의 구성

GUI의 가장 기본적인 윈도 화면의 구성을 살펴보겠다.

from tkinter import *

root = Tk()

# 이 부분에 코딩을 추가해서 화면을 구성하고 처리한다.

root.mainloop()
  1. tkinter는 파이썬에서 GUI 관련 모듈을 제공해주는 표준 윈도 라이브러리이다.
    윈도 화면이 필요하라 때는 꼭 써줘야 한다.

  2. Tk()는 기본이 되는 윈도를 반환하는데, 이를 root라는 변수에 넣었다.
    Tk()를 루트 윈도(root window)라고도 부르며, 꼭 필요한 요소로 이 행이 실행될 때 윈도가 출력된다.

  3. root.mainloop() 함수는 앞으로 윈도에 키보드 누르기, 마우스 클릭 등의 다양한 작업이 일어날 때 이벤트를 처리하기 위해 필요한 부분이다.

윈도에 제목을 지정하고, 크기를 설정할 수 있다.

from tkinter import *

root = Tk()
root.title("혼공 GUI 연습")
root.geometry("400x200")

root.mainloop()

라벨

라벨(label)은 문자를 표현할 수 있는 위젯으로, label(부모윈도, 옵션 …) 형식을 사용한다.
위젯(widget)은 윈도에 나오는 버튼, 텍스트, 라디오 버튼, 이미지 등을 통합해서 지칭하는 용어이다.
옵션에서 모양에 대한 다양한 설정을 할 수 있다.
그리고 모든 위젯들은 pack() 함수를 사용해야 화면에 나타난다.

from tkinter import *
root = Tk()
root.geometry("300x100")

label1 = Label(root, text="혼공 SQL은")
label2 = Label(root, text="쉽습니다.", font=("궁서체", 30), bg = "blue", fg="yellow")

label1.pack()
label2.pack()

root.mainloop()
  1. Label() 함수는 라벨을 만든다.
    옵션에서 text는 글자 내용을, font는 글꼴과 크기를 지정한다.
    fg는 foreground의 약자로 글자색을, bg는 background의 약자로 배경색을 지정한다.

  2. pack() 함수를 통해서 해당 라벨을 화면에 표시해준다.
    label(부모 윈도, 옵션 …)에서 부모 윈도는 루트 윈도인 root를 지정했다.

버튼

버튼(button)은 마우스로 클릭하면 지정한 작업이 실행되도록 사용되는 위젯으로, Button(부모윈도, 옵션 …) 형식을 사용한다.

라벨과 차이점이 있다면, command 옵션으로 사용자가 버튼을 눌렀을 때 지정한 작업을 처리해야 한다는 것이다.

다음 코드는 버튼을 누리면 메시지 상자가 화면에 나타난다.

from tkinter import *
from tkinter import messagebox

def clickButton() :
    messagebox.showinfo('버튼 클릭', '버튼을 눌렀습니다..')

root = Tk()
root.geometry("200x200")

button1 = Button(root, text="여기를 클릭하세요", fg="red", bg="yellow", command=clickButton)
button1.pack(expand = 1)

root.mainloop()
  1. 메시지 상자를 사용하기 위해서 messagebox를 import한다.

  2. command 옵션에 clickButton() 함수를 호출해 버튼을 클릭하면 메시지 상자가 나타난다.

  3. pack()에서 버튼을 화면 중앙에 표현하기 위해 expand=1 옵션을 추가했다.

위젯의 정렬

pack() 함수의 옵션 중에서 가로로 정렬하는 방법으로 side=LEFT 또는 RIGHT 방식이 있다.

from tkinter import *

root = Tk()

button1 = Button(root, text="혼공1")
button2 = Button(root, text="혼공2")
button3 = Button(root, text="혼공3")

button1.pack(side=LEFT)
button2.pack(side=LEFT)
button3.pack(side=LEFT)

root.mainloop()

스크린샷 2024-06-15 182844

side=LEFT 옵션은 왼쪽부터 채워가라는 의미이다.
LEFT를 모두 RIGHT로 바꾸면 다음고 같이 오른쪽부터 나온다.

스크린샷 2024-06-15 182919

side=TOP 또는 BOTTOM 방식으로 사용하면 수직으로 정렬할 수 있다.

스크린샷 2024-06-15 183254 스크린샷 2024-06-15 183354

위젯 사이에 여백 추가

위젯 사이에 여백을 주려면 pack() 함수의 옵션 중 padx=픽셀값 또는 pady=픽셀값 방식을 사용한다.

from tkinter import *

root = Tk()

button1 = Button(root, text="혼공1")
button2 = Button(root, text="혼공2")
button3 = Button(root, text="혼공3")

button1.pack(side=TOP, fill=X, padx=10, pady=10)
button2.pack(side=TOP, fill=X, padx=10, pady=10)
button3.pack(side=TOP, fill=X, padx=10, pady=10)

root.mainloop()

스크린샷 2024-06-15 184029

위젯 사이에 여백이 생겨서 화면이 좀 더 여유 있게 보인다.

프레임, 엔트리, 리스트 박스

프레임(frame)은 화면을 여러 구역으로 나눌 때 사용한다.
엔트리(entry)는 입력 상자를 표현하고, 리스트 박스(listbox) 는 목록을 표현한다.
먼저 간단한 코드로 확인해보겠다.

from tkinter import *
root = Tk()
root.geometry("200x250")

upFrame = Frame(root)
upFrame.pack()
downFrame = Frame(root)
downFrame.pack()

editBox = Entry(upFrame, width = 10)
editBox.pack(padx = 20, pady = 20)

listbox = Listbox(downFrame, bg = 'yellow')
listbox.pack()

listbox.insert(END, "하나")
listbox.insert(END, "둘")
listbox.insert(END, "셋")

root.mainloop()
  1. upFrame 및 downFrame이라는 2개의 프레임을 생성하고 화면에 출력한다.
    프레임은 구역을 나눈 것일 뿐 화면에 표시되지 않는다.

  2. 입력을 위한 엔트리를 root가 아닌 upFrame에 나오도록 한다.

  3. 리스트 박스는 아래쪽인 downFrame에 나오도록 한다.

  4. 리스트 박스에 데이터 3건을 입력했다.
    옵션 중 END는 데이터를 제일 뒤에 첨부하라는 의미이다.

스크린샷 2024-06-15 184935

완전한 형태의 GUI 응용 프로그래밍

import pymysql
from tkinter import *
from tkinter import messagebox

## 메인 코드부
def insertData() :
    con, cur = None, None
    data1, data2, data3, data4 = "", "", "", ""
    sql=""

    conn = pymysql.connect(host='127.0.0.1', user='root', password='0000', db='soloDB', charset='utf8')
    cur = conn.cursor()

    data1 = edt1.get();    data2 = edt2.get();    data3 = edt3.get();    data4 = edt4.get()
    sql = "INSERT INTO userTable VALUES('" + data1 + "','" + data2 + "','" + data3 + "'," + data4 + ")"
    cur.execute(sql)

    conn.commit()
    conn.close()

    messagebox.showinfo('성공', '데이터 입력 성공')


def selectData() :
    strData1, strData2, strData3, strData4  = [], [], [], []

    conn = pymysql.connect(host='127.0.0.1', user='root', password='0000', db='soloDB', charset='utf8')
    cur = conn.cursor()
    cur.execute("SELECT * FROM userTable")
    
    strData1.append("사용자 ID");      strData2.append("사용자 이름")
    strData3.append("사용자 이메일");   strData4.append("사용자 출생연도")
    strData1.append("-----------");    strData2.append("-----------")
    strData3.append("-----------");    strData4.append("-----------")
    
    while (True) :
        row = cur.fetchone()
        if row== None :
            break;
        strData1.append(row[0]);        strData2.append(row[1])
        strData3.append(row[2]);        strData4.append(row[3])

    listData1.delete(0,listData1.size() - 1);    listData2.delete(0,listData2.size() - 1)
    listData3.delete(0,listData3.size() - 1);    listData4.delete(0,listData4.size() - 1)
    
    for item1, item2, item3, item4 in zip(strData1, strData2, strData3, strData4 ):
        listData1.insert(END, item1);        listData2.insert(END, item2)
        listData3.insert(END, item3);        listData4.insert(END, item4)
        
    conn.close()    


## 메인 코드부
root = Tk()
root.geometry("600x300")
root.title("완전한 GUI 응용 프로그램")

edtFrame = Frame(root);
edtFrame.pack()
listFrame = Frame(root)
listFrame.pack(side = BOTTOM,fill=BOTH, expand=1)

edt1= Entry(edtFrame, width=10);    edt1.pack(side=LEFT,padx=10,pady=10)
edt2= Entry(edtFrame, width=10);    edt2.pack(side=LEFT,padx=10,pady=10)
edt3= Entry(edtFrame, width=10);    edt3.pack(side=LEFT,padx=10,pady=10)
edt4= Entry(edtFrame, width=10);    edt4.pack(side=LEFT,padx=10,pady=10)

btnInsert = Button(edtFrame, text="입력", command = insertData)
btnInsert.pack(side=LEFT,padx=10,pady=10)
btnSelect = Button(edtFrame, text="조회", command =selectData )
btnSelect.pack(side=LEFT,padx=10,pady=10)

listData1 = Listbox(listFrame,bg = 'yellow');
listData1.pack(side=LEFT,fill=BOTH, expand=1)
listData2 = Listbox(listFrame,bg = 'yellow')
listData2.pack(side=LEFT,fill=BOTH, expand=1)
listData3 = Listbox(listFrame,bg = 'yellow')
listData3.pack(side=LEFT,fill=BOTH, expand=1)
listData4 = Listbox(listFrame,bg = 'yellow')
listData4.pack(side=LEFT,fill=BOTH, expand=1)

root.mainloop()

스크린샷 2024-06-15 190852