tkinter를 이용하여 버튼이나 레이블만 생성할 수 있는 것은 아닙니다. 점, 선, 사각형, 원을 그릴 수 있습니다.
파이썬에서는 윈도우에 직접 그림을 그리지 않고 캔버스(canvas) 라는 위젯을 윈도우 위에 생성한 후에 캔버스에 그림을 그리게 되어 있습니다.
Canvas 위젯을 사용하면 많은 그래픽 기능을 사용할 수 있습니다.
Canvas 위젯을 이용하여 그래프를 그린다거나 그래픽 에디터를 작성할 수도 있고 많은 종류의 커스텀 위젯을 작성할 수 있습니다.
캔버스 위젯도 tkinter에 포함되어 있습니다. 다음과 같은 절차가 필요합니다.
from tkinter import *
window = Tk()
w = Canvas(window, width = 300, height = 200)
w.pack()
mainloop()
<실행 결과>

캔버스를 생성하려면 Canvas() 생성자를 호출합니다. 이때 윈도우 위젯과 캔버스의 가로와 세로 길이를 전달합니다. 캔버스가 생성되면 pack()을 호출해주어야 화면에 나타납니다.
그림을 그리기 위해서는 좌표계가 있어야 합니다. 일반적으로 그래픽에서는 다음과 같은 좌표계를 사용합니다.
수학에서 카테시안 좌표계를 사용하지만 그래픽에서는 왼쪽 상단이 (0, 0)이 되는 좌표계를 사용합니다.
![]()
캔버스에 직선과 사각형을 그리는 코드는 아래와 같습니다.
from tkinter import *
window = Tk()
w = Canvas(window, width = 300, height = 200)
w.pack()
w.create_line(0, 0, 300, 200)
w.create_line(0, 0, 300, 100, fill = "red")
w.create_rectangle(50, 25, 200, 100, fill = "blue")
mainloop()
<실행 결과>

우리가 생성한 캔버스는 300 픽셀의 폭과 200 픽셀의 높이를 가지고 있습니다. 화면 왼쪽 상단의 좌표는 (0, 0)입니다. 화면 오른쪽 하단의 좌표는 (300, 200)이 됩니다.
다음 문장은 캔버스 위젯 위에 (0, 0)에서 (300, 200)까지 직선을 그립니다.
w.create_line(0, 0, 300, 200)
다음 문장은 캔버스 위젯 위에 (0, 0)에서 (300, 100)까지 직선을 그립니다. 매개변수 fill을 통하여 직선의 색상을 빨강색으로 설정하였습니다.
w.create_line(0, 0, 300, 100, fill = "red")
다음 문장은 캔버스 위젯 위에 사각형을 그립니다. create_rectangle()에 전달되는 매개변수는 사각형의 왼쪽 상단의 좌표와 오른쪽 하단의 좌표입니다.
매개 변수 fill을 통하여 채우기 색상을 파랑색으로 합니다.
w.create_rectangle(50, 25, 200, 100, fill = "blue")

캔버스 위젯에 추가된 항목(선, 사각형, 원)들은 삭제하기 전까지 유지됩니다. 만약 그리기 속성을 변경하고 싶으면 coords(), itemconfig(), move()를 사용할 수 있습니다.
필요 없을 때는 delete()를 이용하여 삭제할 수 있습니다. 캔버스에 그리기 항목이 많아지면 무척 느려지므로 필요 없는 경우에는 지체 없이 삭제하도록 합시다.
from tkinter import *
window = Tk()
w = Canvas(window, width = 300, height = 200)
w.pack()
i = w.create_line(0, 0, 300, 100, fill = "red")
w.coords(i, 0, 0, 300, 100) # 좌표를 변경합니다.
w.itemconfig(i, fill = "blue") # 색상을 변경합니다.
# w.delete(i) # 삭제합니다.
# w.delete(ALL) # 모든 항목을 삭제합니다.
mainloop()
<실행 결과>

삭제해버리면 화면에 아무것도 표시가 되지 않으므로 삭제 메소드는 주석 처리하였습니다.
create_line() 함수는 식별자를 반환합니다. 따라서 이것을 변수에 기억하여 두었다가 삭제 시에 사용하면 됩니다.
i = w.create_line(0, 0, 300, 100, fill = "red")
색을 지정하려면 색상 이름(영어)을 사용하면 됩니다. 예를 들어서 "red", "white", "blue"와 같은 색상의 이름을 사용하면 됩니다.
tkinter는 일반적인 색상 이름뿐만 아니라 "Moccasin", "PeachPuff"와 같은 이국적인 이름도 기억하고 있습니다.
윈도우 및 매킨토시 시스템에서의 색상 이름들도 tkinter에 내장되어 있습니다.
우리는 앞에서 직선이나 사각형을 그릴 때 fill이라고 하는 이름 매개 변수를 사용하여 색상을 지정하였습니다. fill의 도형의 채우기 색상입니다.
채우기 색상이 아니고 경계선의 색상을 지정하려면 어떻게 하면 될까요? outline이라는 이름 매개 변수를 사용하면 됩니다.
from tkinter import *
window = Tk()
w = Canvas(window, width = 300, height = 200)
w.pack()
w.create_rectangle(50, 25, 200, 100, outline = "blue")
mainloop()
<실행 결과>

이름이 있는 색상이 아니면 어떻게 해야 할까요? 이 세상에 있는 색상은 빨간색(Red), 녹색(green), 파란색(blue)을 잘 섞으면 전부 만들 수 있습니다.
따라서 빨간색, 녹색, 파란색 성분의 양을 숫자로 지정하면 됩니다. 일반적으로 0에서 255 사이의 색상을 사용합니다.
따라서 (0, 0, 0)은 빨간색, 녹색, 파란색 성분이 전부 0이라는 의미가 되고 검정색을 나타냅니다.
(255, 255, 255)는 빨간색, 녹색, 파란색 성분이 전부 255 이라는 의미가 되고 흰색을 나타냅니다.
![]()
파이썬에서는 빨간색, 녹색, 파란색 성분을 16진수로 표시합니다. 16진수는 0부터 F까지의 기호를 사용합니다. A가 10, B가 11, C가 12, D가 13, E가 14, F가 15와 같습니다.
16진수로 흰색은 "#FFFFFF" 가 됩니다. # 기호는 16진수임을 알려주는 기호입니다.
이번에는 우리가 만든 색상을 이용하여 사각형을 채워봅시다.
from tkinter import *
window = Tk()
w = Canvas(window, width = 300, height = 200)
w.pack()
w.create_rectangle(50, 25, 200, 100, outline = "blue", fill = "#FA88AB")
mainloop()
<실행 결과>

tkinter.colorchooser 모듈의 askcolor()를 호출하면 대화 상자를 통하여 사용자로부터 색상의 값을 입력받을 수 있습니다.
import tkinter.colorchooser
color = tkinter.colorchooser.askcolor()
print(color)
<실행 결과>

((160.625, 160.625, 160.625), '#a0a0a0')
askcolor() 는 결과를 튜플로 반환합니다. 튜플의 첫 번째 3개의 숫자는 빨간색, 녹색, 파란색 성분의 값을 나타냅니다.
튜플의 2번째 요소는 색상을 16진수로 표현한 문자열입니다. 이 튜플을 이용하여 색상을 지정하면 됩니다.
사각형을 그릴 때 사용자에게 색상을 물어보도록 코드를 변경합시다.
from tkinter import *
import tkinter.colorchooser
window = Tk()
w = Canvas(window, width = 300, height = 200)
w.pack()
color = tkinter.colorchooser.askcolor()
w.create_rectangle(50, 25, 200, 100, fill=color[1])
mainloop()
<실행 결과>

대부분의 tkinter 위젯은 배경(bg)과 전경(fg) 변수를 사용하여 위젯의 색상을 지정할 수 있습니다. 버튼의 배경색과 전경색은 다음과 같은 형식으로 변경이 가능합니다.
from tkinter import *
window = Tk()
button = Button(window, text = "버튼을 클릭하세요")
button.pack()
button["fg"] = "yellow"
button["bg"] = "green"
mainloop()
<실행 결과>

또 다른 방법은 "#ff0000" 과 같은 형식으로 RGB 값을 16진수로 표시하는 방법입니다.
from tkinter import *
window = Tk()
button = Button(window, text = "버튼을 클릭하세요")
button.pack()
button["fg"] = "#ff0000"
button["bg"] = "#00ff00"
mainloop()
<실행 결과>

타원(oval)을 그리려면 아래와 같이 사각형을 지정합니다. 타원은 지정된 사각형 안에 그려집니다.
from tkinter import *
window = Tk()
canvas = Canvas(window, width = 300, height = 200)
canvas.pack()
canvas.create_oval(10, 10, 200, 150)
mainloop()
<실행 결과>

호(arc)는 원의 일부입니다. 호도 마찬가지로 사각형을 지정하여서 그립니다. 추가되는 매개 변수 extent를 사용하여 각도를 지정합니다.
from tkinter import *
window = Tk()
canvas = Canvas(window, width = 300, height = 200)
canvas.pack()
canvas.create_arc(10, 10, 200, 150, extent = 90, style = ARC)
mainloop()
<실행 결과>

위의 코드는 (10, 10)이 왼쪽 상단이고 (200, 15)이 오른쪽 하단인 사각형을 지정합니다. 이 사각형에 내접한 원이 그려지고 원 중에서 90도만 그려집니다.
반복문을 사용하여 각도를 증가시키면서 호를 그리는 프로그램을 작성해봅시다.
from tkinter import *
window = Tk()
canvas = Canvas(window, width = 300, height = 200)
canvas.pack()
for degree in range(0, 360, 30):
canvas.create_arc(10, 10 + degree // 5, 200, 150 + degree // 5, extent = degree, style = ARC)
mainloop()
<실행 결과>

각도가 증가되면서 동시의 사각형의 y 좌표도 증가되었습니다.
다각형(polygon)은 3개 이상의 선분으로 둘러싸인 도형입니다. 삼각형이나 사각형도 다각형의 일종입니다. 다각형을 사용하면 불규칙적인 형상도 유사하게 그릴 수 있습니다.
tkinter로 다각형을 그리려면 다각형의 각 점에 대한 좌표를 제공하면 됩니다.
from tkinter import *
window = Tk()
canvas = Canvas(window, width = 300, height = 200)
canvas.pack()
canvas.create_polygon(10, 10, 150, 110, 250, 20, fill="blue")
mainloop()
위의 예제에서는 다각형이 (10, 10)에서 출발하여서 (150, 110)으로 가고 최종적으로 (250, 20)에서 종료됩니다. 다각형의 채우기 색상이 fill 매개 변수를 이용하여 파란색으로 지정되었습니다.
<실행 결과>

다각형의 좌표를 지정할 때, 우리는 리스트를 사용할 수 있습니다. 아래의 예제를 살펴봅시다.
from tkinter import *
w = 300
h = 200
window = Tk()
w = Canvas(window, width = w, height = h)
w.pack()
points = [0, 0, 80, 150, 250, 20]
w.create_polygon(points, outline = "red", fill = "yellow", width = 5)
mainloop()
<실행 결과>

tkinter로 각종 도형도 그릴 수 있지만 캔버스 위에 텍스트도 표시할 수 있습니다. 텍스트를 표시하는 함수는 create_text() 입니다.
create_text()는 텍스트의 중앙 위치를 나타내는 (x, y) 좌표와 표시할 텍스트가 전달되는 매개 변수 text를 가집니다. 다음 코드에서는 (100, 100) 위치에 간단한 텍스트를 표시합니다.
from tkinter import *
window = Tk()
canvas = Canvas(window, width=300, height=200)
canvas.pack()
canvas.create_text(100, 100, text='싱 스트리트(Sing Street)')
mainloop()
<실행 결과>

create_text()도 텍스트의 색상을 표시하는 매개 변수 fill을 가지고 있습니다.
canvas.create_text(100, 100, text='싱 스트리트(Sing Street)')
폰트를 나타내는 매개 변수 font를 전달할 수 있습니다. 예를 들어서 font = ('Courier', 30) 이라고 하면 크기는 20 포인트인 "Courier" 폰트를 나타냅니다.
폰트의 크기와 색상을 변경할 수 있다면 재미있는 그래픽을 만들 수 있습니다.
from tkinter import *
window = Tk()
canvas = Canvas(window, width=500, height=200)
canvas.pack()
canvas.create_text(250, 10, text='Sing Street', fill = 'blue', font = ('Courier', 20))
canvas.create_text(250, 100, text='Sing Street', fill = 'red', font = ('Hevetica', 30))
canvas.create_text(250, 150, text='Sing Street', fill = 'green', font = ('Times', 40))
mainloop()
<실행 결과>

화면에 이미지를 표시하는 것은 게임과 같은 애플리케이션에서 무척 중요한 기능입니다. tkinter에서 이미지를 표시하려면 먼저 이미지를 로드하여야 합니다.
그 후에 create_image() 함수를 사용하면 됩니다.
파이썬이 접근할 수 있는 디렉토리에 이미지가 있어야 합니다. 예를 들어 D 드라이브에 있는 starship.png 이미지 파일을 두어도 됩니다. tkinter가 읽을 수 있는 이미지 파일은 GIF 및 PGM / PPM 이미지입니다.
만약 다른 형식의 이미지 파일을 읽는 기능이 필요하다면 Python Imaging Library ( http://pythonware.com/products/pil/ )를 사용하여야 합니다.
D 드라이브에 있는 seulgi.gif 이미지 파일을 읽어서 캔버스에 표시하는 예제는 다음과 같습니다.
from tkinter import *
window = Tk()
canvas = Canvas(window, width=500, height=250)
canvas.pack()
img = PhotoImage(file = "D:\seulgi.gif")
canvas.create_image(0, 0, anchor = NW, image = img)
mainloop()
<실행 결과>

D 드라이브에 있는 seulgi.gif 이미지 파일은 PhotoImage()에 의하여 읽혀져 img 변수에 저장되었습니다.
이미지가 올바르게 읽혀졌다면 create_image() 함수가 이미지를 화면에 표시합니다. create_image() 함수에 첫 번째 매개 변수는 이미지가 표시되는 좌표입니다.
anchor=NW 는 이미지의 왼쪽 상단(NW : NorthWest)을 기준점으로 사용하라는 것을 의미합니다. 즉 이미지의 왼쪽 상단이 좌표 (20, 20)에 놓여집니다.
마지막 매개 변수 image는 표시할 이미지가 저장된 변수입니다.
우리는 앞에서 움직이지 않는 그림만 그려보았습니다. 여기서는 움직이는 그림을 만들어 봅시다. 즉 애니메이션을 작성해봅시다.
컴퓨터를 이용하여 애니메이션을 만드는 것은 생각보다 어렵지 않습니다. 근본적으로 애니메이션은 유사한 정지 영상을 연속적으로 빠르게 보여주는 것입니다.
사람은 뇌로 이것들을 연결시켜서 움직인다고 생각합니다.
파이썬을 이용하여 애니메이션을 작성하려면 일정한 시간 간격으로 조금씩 달라지는 그림을 화면에 그리면 됩니다.
예를 들어 공이 왼쪽에서 오른쪽으로 움직이는 애니메이션을 작성해봅시다. 아래의 코드를 입력하고 실행하여 봅시다.
import time
from tkinter import *
window = Tk()
canvas = Canvas(window, width = 400, height = 300)
canvas.pack()
id = canvas.create_oval(10, 100, 50, 150, fill = "green")
for i in range(100):
canvas.move(id, 3, 0)
window.update()
time.sleep(0.05)
위의 코드를 실행하면 원이 왼쪽에서 오른쪽으로 움직이는 애니메이션이 나타납니다.
<실행 결과>
-> 
설명해야 할 것이 많습니다.
create_oval() 함수의 반환값을 변수 id에 저장합니다.
sleep()의 단위는 초입니다. 0.05초만 잠을 자게 합니다.
두 번째와 세 번째 매개변수는 x 방향과 y 방향의 이동거리입니다. 현재 우리의 코드 canvas.move(id, 3, 0)에서는 x 방향으로 3만큼 움직입니다.
따라서 우리는 마지막 원의 위치만을 볼 것입니다.
원을 대각선 방향으로 움직이려면 어떻게 하면 될까요? canvas.move(id, 3, 2)로 변경하면 됩니다.
...
for i in range(100):
canvas.move(id, 3, 2)
window.update()
time.sleep(0.05)
<실행 결과>
-> 
항상 똑같은 화면만 보여주는 애니메이션은 별 쓸모가 없습니다. 만약 우리가 키보드에 반응하는 애니메이션을 만들 수 있다면 좋을 것입니다.
컴퓨터 용어로 키를 누르거나 마우스를 움직이는 것을 이벤트(event)가 발생하였다고 합니다.
이벤트는 "사전"이라는 의미로서 컴퓨터 입장에서는 사용자가 키를 누르는 것이 큰 사건이 되는 것입니다.
이벤트를 처리하는 일반적인 방법은 이벤트에 함수를 연결(등록)하는 것입니다. 이벤트가 발생하면 등록된 함수가 자동으로 호출됩니다.
이벤트 구동 프로그래밍은 이벤트에 의하여 실행 순서가 결정되는 방식입니다.

tkinter에서도 이벤트 처리를 지원하는 기능이 제공됩니다. 함수를 만들고 이 함수를 특정한 이벤트에 등록할 수 있는 것입니다.
예를 들어 왼쪽 화살표 키가 눌리면 원을 왼쪽으로 이동하는 함수를 작성합니다.
def call_back(event):
canvas.move(id, -10, 0)
이 함수는 하나의 매개 변수 event만을 받는데, event에는 발생한 이벤트에 대한 여러 가지 정보가 들어 있습니다.
이벤트가 발생했을 때 이 함수가 호출되게 하려면 bind_all() 함수를 사용합니다.
from tkinter import *
window = Tk()
canvas = Canvas(window, width=400, height=300)
canvas.pack()
id = canvas.create_oval(10, 100, 50, 150, fill="green")
def move_right(event):
canvas.move(id, 5, 0)
canvas.bind_all('<KeyPress-Right>', move_right)
mainloop()
bind_all() 함수의 첫 번째 매개 변수는 tkinter가 처리해야 하는 이벤트를 지정합니다.
지금은 ''로 되어 있는데, 이것은 "오른쪽 화살표가 눌리는 이벤트"를 나타냅니다. 이 이벤트가 발생하면 tkinter는 move_right() 함수를 호출하게 됩니다.
따라서 우리는 move_right() 함수 안에 오른쪽 화살표가 눌렸을 때, 해야할 일을 추가하면 됩니다. 여기서는 물론 원을 오른쪽으로 움직이는 일입니다.
<실행 결과>


원을 왼쪽으로 이동시키는 코드는 아래의 코드를 추가하면 됩니다.
...
def move_right(event):
canvas.move(id, 5, 0)
def move_left(event):
canvas.move(id, -5, 0)
canvas.bind_all('<KeyPress-Right>', move_right)
canvas.bind_all('<KeyPress-Left>', move_left)
...
이벤트에 대한 상세한 정보는 http://effbot.org/tkinterbook/tkinter-events-and-bindings.html 에서 찾을 수 있습니다.
1. 윈도우를 하나 만들고 여기에 랜덤한 크기의 사각형을 여러 개 그려봅시다. 위치, 크기, 색상 모두 랜덤으로 설정합니다.

random 모듈은 많은 함수를 제공하지만 가장 많이 사용되는 것은 다음의 2가지입니다.
색상을 랜덤하게 선택하여 그리려면 다음과 같은 코드를 사용합니다.
color = ["red", "orange", "yellow", "green", "blue", "violet"]
...
canvas.create_rectangle(x, y, w, h, fill = random.choice(color))
2. 아래와 같이 마우스를 움직여서 화면에 그림을 그리는 애플리케이션을 작성해봅시다.
<실행 결과>

여러 가지 방법으로 작성할 수 있습니다.
마우스 이벤트는 아래와 같은 문장으로 처리할 수 있습니다.
def drawDot(event):
x1, y1 = (event.x - 1), (event.y - 1)
x2, y2 = (event.x + 1), (event.y + 1)
canvas.create_oval(x1, y1, x2, y2, fill = "red")
...
canvas.bind("<B1-Motion>", drawDot)