[원문] http://coreapython.hosting.paran.com/GUI/TkinterSummary.html

Tkinter 요약

작성 러셀 오웬(Russell Owen).
한글판 johnsonj 2008.04.19 토

이 글은 Tkinter를 위한 간편 참조서이다. 이 글의 목표는 적절한 참고 재료를 보충하기 위한 것이지, 대체하고자 하는 것이 아니다. 단순한 것에서부터 비밀스러운 것까지 모두 다룬다. 본인이 필요한 정보를 찾으면서 힘들다고 생각했기 때문에 새로운 주제를 덧붙이고자 한다.

기본적인 Tk 어플리케이션

import Tkinter	root = Tkinter.Tk()	# 인터페이스를 설정하고, 시작:	root.mainloop()

표준 창부품들

기본 창부품: Toplevel, Frame, Button, Checkbutton, Entry, Label, Listbox, OptionMenu, Photoimage, Radiobutton, Scale.

고급 창부품: Canvas, Text. 이 창부품들의 내용물에 이름표를 붙이면 객체처럼 행위한다.

고난도 창부품: Menu, Menubutton, Scrollbar.

Tk 변수들: StringVar, IntVar, DoubleVar, BooleanVar. 특정한 위젯에 필요한 데이터를 담아 놓은 그릇으로서, 다른 객체들이 자신의 내용에 쉽게 접근할 수 있어서 편리하며 자신의 데이터가 바뀌면 역호출을 촉발시킬 수 있다.

기타 모듈들 ("import Tkinter"로 적재되지 않음)

tkFont에는 Font 클래스가 정의되어 있어서 폰트를 구성할 수 있고 폰트의 이름들을 얻을 수 있다. 한 창부품의 폰트를 Font 객체에 설정하고, Font를 바꾸면 바로바로 창부품이 갱신된다.

FileDialog에는 FileDialog, LoadFileDialog, SaveFileDialog이 정의되어 있다. 다음은 그 예이다:

fdlg = FileDialog.LoadFileDialog(root, title="Choose A File")	fname = fdlg.go() # 선택 인자들: dir_or_file=os.curdir, pattern="*", default="", key=None)	if file == None: # 사용자 취소함

tkColorChooser에는 askcolor(initialcolor)이 정의되어 있는데, 이 메쏘드는 사용자가-선택한 색상을 돌려준다.

tkSimpleDialog에는 askinteger(title, prompt, initialvalue, minvalue, maxvalue), askfloat 그리고 askstring이 정의되어 있다.

소스 코드를 조사해 보자. .../Lib/lib-tk에서 다른 사용법들을 찾아보자.

위치 관리

꾸림자

pack(side="top/right/bottom/left", expand=0/1, anchor="n/nw/w...", fill="x/y/both")

  • 기본적으로, 창부품은 꾸러미의 가운데 위치한다; 닻(anchor)을 사용하여 이것을 변경하자.
  • 기본적으로, 창부품은 꾸러미를 채우도록 커지지 않는다; expand와 fill을 사용하여 이를 변경하자.

격자 관리자

grid(row, column, rowspan=?, columnspan=?, sticky="news", ipadx=?, ipady=?, padx=?, pady=?)

rowconfigure(row, weight=?, minsize=?, pad=?)

columnconfigure(column, weight=?, minsize=?, pad=?)

  • 각 행과 열은 자신 안에서 가장 작은 요소에 크기가 맞도록 줄어든다.
  • 기본적으로, 창부품은 셀안에서 가운데에 위치하고 셀을 다 채우도록 커지지 않는다; sticky를 사용하여 이를 바꾸자.
  • 기본적으로 행과 열은 사용자가 창의 크기를 변경하더라도 커지지 않는다; 0이 아닌 값을 rowconfigure와 columnconfigure를 사용하여 설정하면 이를 바꿀 수 있다.
  • Rowconfigure와 columnconfigure는 또한 일반적인 문제를 해결하는데에도 도움이 된다: 늘이기(spanning)는 행과 열의 크기를 증가시킨다. 너비가 각각 20 픽셀 30 픽셀인 컬럼이 있다고 해보자. 또 기존의 컬럼을 더 키우지 않고 "넓은 창부품"을 100 픽셀 너비로 격자처리하고 싶다고 해보자. 단순히 두 컬럼을 차지하도록 격자처리하면 두 창부품이 함께 총 100 픽셀만큼 늘어난다 (25 픽셀을 더 얻어서, 각각 45픽셀 55 픽셀이다). 넓은 객체가 컬럼을 두 개 차지하도록 (남는 픽셀들을 다른 여러 컬럼에 분산시켜서) 격자 처리하면 문제가 줄어들지만 문제가 해결되지는 않는다. 해결책은 넓은 창부품이 추가로 적어도 한개의 컬럼만큼 더 늘어나게 하고 columnconfigure를 사용하여 그 늘어난 컬럼에 비율(weight)을 1이 되도록 설정하는 것이다.

사건과 호출

사건

사건은 문자열로 기술된다: "<modifiers-type-qualifier>".

사건 유형은 다음과 같다:

  • mouse (수식키 B1, 등등. 어느 마우스 버튼인지 지정한다):
    • ButtonPress (약자로 Button으로 표기, 수식자 Double)
    • ButtonRelease
    • Enter
    • Leave
    • Motion
  • keyboard (수식키에는 Control, Shift, Meta...등등 포함)
    • KeyPress (약자로 Key로 표기)
    • KeyRelease
  • window (Tk에서 창은 창부품이다):
    • Configure (창 크기 조절, 이동, 등등.)
    • Expose
    • FocusIn
    • FocusOut
    • Map
    • Unmap

경고: 어느 창부품이 어느 사건을 볼지는 플랫폼에 따라 달라진다.

KeyPressd와 KeyRelease에 대한 자격부여자는 keysyms이다. 문자와 숫자는 그대로 사용된다. 그러나 구두점과 기타 모든 키는 특별한 이름이 대소문자에 민감하게 사용되는데 여기에는: comma, period, dollar, asciicircum, numbersign, exclam, Return, Escape, BackSpace, Tab, Up, Down, Left, Right... 등등이 포함됨. 잘 모르겠으면, 아래에 주어진 예와 같이 대화 쉘에서 테스트해 보자.

창부품이 사건을 볼 때 역호출을 촉발시키려면, bind를 사용하자:
widget.bind(event, callback)

  • 역호출은 정확하게 인자를 event 하나만 받는다:
  • 사건에는 다음과 같은 속성이 포함된다 (완벽한 목록이 아님):
    • keysym: the keysm, 위에 기술한 바와 같이 (KeyPress 사건과 KeyRelease 사건)
    • height, width (구성 사건)
    • serial: 사건의 일련 번호 (모든 사건)
    • type: 사건 유형을 나타내는 숫자 (모든 사건)
    • time: 사건이 일어난 시간 (모든 사건)
    • widget: 사건을 받은 창부품 (모든 사건)
    • x, y: 창부품에 대한 마우스 포인터의 상대 위치 (마우스 사건과 거의 모든 사건)
    • x_root, y_root: 루트 창에 대한 마우스 포인터의 상대 위치 (마우스 사건과 거의 모든 사건)
  • 사건 전파를 막으려면, 역호출에서 "break"라는 문자열을 돌려주자; 기본 창부품의 행위를 오버라이드 하고 싶다면 필요할 것이다.
  • 다른 유형/수준의 묶기가 있다. 예를 들면 한 사건을 특정 클래스의 모든 실체에 묶을 수 있다 (예를 들어, 모든 버튼). 더 자세한 정보는 Tkinter 개론 참조하자.

다음은 키 눌림에 대하여 키 심볼을 보여주는 예제이다:

	#!/usr/local/bin/Python	"""타자할 때마다 각 키눌림에 대하여 keysym을 보여준다."""	import Tkinter		root = Tkinter.Tk()	root.title("Keysym Logger")		def reportEvent(event):	print 'keysym=%s, keysym_num=%s' % (event.keysym, event.keysym_num)		text  = Tkinter.Text(root, width=20, height=5, highlightthickness=2)		text.bind('<KeyPress>', reportEvent)		text.pack(expand=1, fill="both")	text.focus_set()	root.mainloop()

프로토콜 처리자 WM_DELETE_WINDOW

사건 역호출 파괴는 너무 늦게 촉발되기 때문에 창부품을 미처 청소하지 못하거나 창 파괴를 막을 수 없다. 이렇게 하려면 WM_DELETE_WINDOW 프로토콜 처리자를 사용하자. (그러나 어플리케이션이 종료할 때 청소하려고 한다면, 대신에 표준 파이썬 라이브러리에 있는 "atexit"을 사용하자; 그게 더 간단하다!) 이렇게 하면 기본 행위가 바뀐다. 그러므로 창을 없애고 싶다면 손수 파괴해야 한다. 역호출 함수는 아무 인자도 받지 않는다.

toplevel.protocol("WM_DELETE_WINDOW", callback)

두가지 프로토콜이 있다: WM_SAVE_YOURSELF와 WM_TAKE_FOCUS가 그것인데 본인도 그것이 무엇인지 잘 모른다.

창부품 명령어들

버튼 같은 창부품은 "command" 매개변수를 지원한다. 이 역호출은 인자를 받지 않는다. 이런 방법은 버튼이 눌렸을 때 역호출을 촉발시키기에는 별로 좋은 방법이 아니다. 왜냐하면 같은 일을 하는데 단 한번의 마우스 사건이란 없기 때문이다. "command" 역호출은 역호출 함수에게 아무 데이터도 보내지 않기 때문에 문제가 된다. 그러나 역호출 싸개를 이용하면 쉽게 상황을 바로 잡을 수 있다.

변수 추적하기

Tk 변수가 변하면 역호출을 촉발시키려면, trace_variable을 사용하자:
traceName = tkvar.trace_variable(mode, callback)

  • Mode는 "r"이나 "w" 또는 "u"중 하나이다 (read, write or update)
  • 역호출 함수는 인자를 세개 받는다: varName (Tk 변수의 이름), index (언제나 ''?), mode
  • 역호출 함수는 그 변수의 내용물을 바꿀 수 있다. 또다른 역호출 함수를 촉발시키지 않고서도 말이다.
  • 이름으로 변수를 얻거나 수정하려면, anywdg.getvar(varName)나 anywdg.setvar(varName, value)를 사용하자
  • 역호출 함수를 삭제하려면, tkvar.trace_delete(traceName)를 사용하자
  • 더 자세한 정보는 Tkinter Folklore를 참조하자.

After: 시간을 설정한 사건과 애니메이션

예를 들어 애니메니션을 위하여, 일정시간을 지연시킨후 역호출을 촉발시키려면, after를 사용하자:
widget.after(timems, callback, arg1, arg2...)

  • arg1, arg2... 는 0개 이상의 선택적인 추가 인자들을 뜻한다
  • 역호출함수는 지정된 것만, 선택적인 인자들을 추가로 받는다.
  • 역호출 함수는 일정시간 후에 호출될때 단 한번만 호출된다.

파일/소켓 처리자

문제는 사건 처리자를 묶지 않고서 어떻게 소켓을 통하여 통신하는가이다 (특히 데이터를 읽는 법). 그렇지 못하다면 아주 비효율적이다. 선택은 여러가지이다:

파일 처리자

파일이나 소켓에 읽거나 쓸 데이터가 있으면 파일 처리자는 역호출 함수를 부를 것이다. 파일 처리자는 간단하며 Tkinter에 통합이 잘 되어 있다. 불행하게도 윈도우즈에서는 작동하지 않는다 (적어도 Python 2.3.4 그리고 Windows XP에서는 그렇다). 그러나 프로그램이 unix 또는 MacOS X에서 실행된다면, 고려해볼 가치가 있는데 너무 사용하기 쉽기 때문이다.

wdg.tk.createfilehandler(file_or_socket, mask, callback)
wdg는 Tkinter 창부품이면 아무거나 된다 (당장 쓸 것이 없다면, 새로 만들어 보자).

  • Mask: 다음을 OR 연산한 것: Tkinter.READABLE, Tkinter.WRITABLE, Tkinter.EXCEPTION
  • 역호출함수는 인자를 정확하게 두 개 받는다: file_or_socket, mask
  • 파일은 처리자를 오직 하나만 가질 수 있다. createfilehandler를 다시 호출하더라도 그냥 예전 처리자를 대체한다.
  • 처리자를 아주 제거하려면, deletefilehandler(file_or_socket)를 호출하자
  • 잠깐만 처리자를 제거하려면, createfilehandler(file_or_socket, None)를 호출하자. 파일 처리자를 삭제하고 다시 만드는 것보다 이 편이 더 좋다.
  • 2003-05-06에 표기법을 바꾸었다. 예전에 tkinter를 사용했던 방법을 바꾸었다; 예전 방법은 파이썬 2.2.x에서는 잘 작동했지만 파이썬 2.3에서는 망가졌다 (적어도 tcl이 쓰레드를 지원하도록 구축되었다면 말이다). 새로운 방법은 파이썬 2.3과 2.2.2와 잘 작동하며 아마도 그 보다 이전 버전이라도 잘 작동할 것 같다.

Tcl 소켓

Tcl 소켓은 완벽하게 크로스-플랫폼을 지원한다. 그러나 tcl 코드가 좀 필요하기 때문에 약간 사용하기 어렵다. 그래도, 아주 어려운 것은 아니며 완벽한 크로스-플랫폼 코드를 얻기 위해 노력해 볼 가치가 있다. tcl 소켓을 사용하는 방법에 관한 예를 보려면, 본인의 RO 꾸러미를 내려받아 RO.Comm.TkSocket을 살펴보자. 또 다음 매튜 신세라(Matthew Cincera)가 게시한 글도 참조하다. 본인도 이 글을 읽고 시작했다 (스테판 빌랜드(Stephane Beland)에게 감사함).

Twisted 작업틀

Twisted 작업틀은 자유 라이브러리로서 플랫폼에 독립적이며 여러 다양한 GUI 툴킷과 작동한다 (실제로는 GUI 툴킷이 전혀 요구하지 않는다). 평판이 좋다. 솔직히 직접 사용해 본 바가 없지만, 언젠가는 옮겨갈 생각이다.

역호출 싸개 (함수내포 함수)

정상적으로 주어지는 데이터 말고도, 데이터를 추가로 역호출 함수에 보내고 싶은 경우가 있다. 예를 들면 버튼 창부품은 자신의 명령어 역호출에 전혀 인자를 보내지 않는다. 그러나 역호출 함수 하나를 여러 버튼에 사용하고 싶다면, 어느 버튼이 눌렸는지 알아야 할 필요가 있다.

이를 처리하는 방법은 먼저 역호출 함수를 정의하고 나서 그 역호출 함수를 창부품에 건네고 기타 필요한 정보를 포함시키는 것이다. 불행하게도 대부분의 언어들처럼 파이썬은 (함수가 정의될 때 정보가 알려지는) 이른 묶기와 (함수가 호출될 때 정보가 알려지는) 나중 묶기를 혼용하면 제대로 처리하지 못한다. 개인적으로 쉽고 깔끔한 해결책을 제시하라면 다음과 같다:

  • 원하는 데이터를 모두 인자로 취하도록 역호출 함수를 작성하자.
  • 역호출 싸개 클래스를 사용하여 호출가능 객체를 만들자. 이 객체에 함수와 기타 인자들이 저장되며 호출될 때 제대로 일을 한다. 다른 말로 하면, 저장된 데이터와 거기에 호출자가 공급한 데이터로 함수가 호출된다.

아래에 보여주는 예제가 이해에 도움이 되었으면 한다.

여기에서 사용한 역호출 싸개는 RO.Alg.GenericCallback에 있는데, 이는 RO 꾸러미에서 얻을 수 있다. 키워드 인자를 처리하지 못하지만 간단하게 만든 버전을 아래에 예제로 제시한다. 모든 shim 코드는 기반이 스코트 데이비드 다니엘스(Scott David Daniels)가 만든 파이썬 요리법인데, 그는 이를 "함수 내포시키기(currying a function)"라고 부른다 (아무래도 이 용어가 "역호출 싸개(callback shim)" 보다 더 일반적인 것 같다).

	#!/usr/local/bin/Python	"""역호출 싸개의 사용법을 보여주는 예제"""	import Tkinter		def doButton(buttonName):	"""내가 원하는 역호출 함수. 역호출 싸개가 필요하다	Button 명령어 역호출에서는 인자를 아무것도 받지 않기 때문이다.	"""	print buttonName, "pressed"		class SimpleCallback:	"""역호출 싸개를 만들어라. 스콧 다니엘스(Scott David Daniels)가 만든 코드에 기반함	(이 코드는 키워드 인자도 처리함).	"""	def __init__(self, callback, *firstArgs):		self.__callback = callback		self.__firstArgs = firstArgs		def __call__(self, *args):		return self.__callback (*(self.__firstArgs + args))		root = Tkinter.Tk()		buttonNames = ("Button 1", "Button 2", "Button 3")	for name in buttonNames:	callback = SimpleCallback(doButton, name)	Tkinter.Button(root, text=name, command=callback).pack()		root.mainloop()

인덱싱

Text 창부품

  • "line.col" line = 줄 번호, 1부터 시작 (!); col = 컬럼 # 0부터 시작함
  • "current" 마우스 포인터 아래에 있는 문자
  • "insert" 커서 뒤의 문자
  • "end" 마지막 문자 바로 다음까지
  • "@x,y" 지정된 화면 좌표 아래에 있는 문자
  • "tag.first", "tag.last" 지정된 태그의 첫 문자에서부터 그 이후의 마지막 문자까지

다음 문자열을 추가하면 바꿀 수 있다:

  • " +/- n chars"
  • " +/- n lines"
  • " linestart"
  • " linend"
  • " wordstart"
  • " wordend"

예를 들어 "1.0 lineend"는 첫 줄의 끝까지 가리킨다

Entry 창부품

  • 정수는 0부터 시작함 (또는 문자열 표현)
  • "end", "insert", "@x,y" (위의 Text 창부품 참조)
  • "anchor" (또다른 선택 방법), "sel.first", "sel.last"

창부품으로부터 정보 얻기

창부품으로부터 구성 정보를 열람하는 방법은 여러가지가 있다:

  • 창부품을 사전처럼 취급하자: aWidget["text"]. (주의: 이 방법은 정보를 설정하고 얻는데 모두 작동한다.)
  • cget 메쏘드를 사용하자: aWidget.cget("text").
  • 인자 없이 configure 메쏘드를 호출하면 한꺼번에 사전으로 받을 수 있다: aWidget.configure().

어떤 경우든지 각 설정은 문자열로 반환된다. 이 때문에 아주 골치거리가 될 수 있다. 예를 들면 불리언 값은 "0"이나 "1"이 된다. (두가지 모두 파이썬에서는 논리적으로 참이다). Tk 변수나 창부품 같은 정상적인 Tkinter 객체를 열람하려고 하면 문제는 더욱 악화된다. 다음 예제에 문제를 보여준다 (그렇지만 그런 간단한 상황이라면 이미 오리지널 Tk가 있다) 해결책 몇 가지를 아래에서 연구해 보았다:

import Tkinterroot = Tkinter.Tk()aVar = Tkinter.StringVar()aLabel = Tkinter.Label(textvar = aVar)aLabel["textvar"]  'PY_VAR0'root.setvar(aLabel["textvar"], "foo")aLabel.getvar(aLabel["textvar"])  'foo'str(aLabel)  '.8252000'root.nametowidget(str(aLabel))  <Tkinter.Label instance at 0x7dea60>aLabel.master  <Tkinter.Label instance at 0x7dea60>root.master  None	

해결책은 무엇을 열람하려고 하는가에 달려 있다:

  • StringVar같은 변수일 경우, 변수의 이름을 알고 있다면 그 변수를 읽거나 쓰려면 getvar(name_of_var) 그리고 setvar(name_of_var, new_value)를 사용하면 된다. 또한 원래의 변수처럼 작동하는 Tkinter 변수를 만드는 것도 가능하다. 그러나 보기에 좋지 않으므로 대신에 getvar와 setvar를 사용하시기를 권한다 (즉 원래의 Tkinter 변수에 보관하자). 정말 그렇게 하고 싶다면, 먼저 새로 Tkinter 변수를, 예를 들어 v = Tkinter.StringVar()와 같이 만들고 그의 _name 특성에 다음과 같이 설정하자: v._name = name_of_variable. 여기에서 문제는 새로 만들어진 Tk 변수를 사용하지도 않으며 이것이 Tkinter의 변수의 특성에 있는지 제대로 문서화되어 있지 않다는 것이다. (쓰레기 수집 문제가 있기 때문에, 안전한지 확신조차 할 수 없다.)
  • (버튼 같이) 화면에 나타나는 창부품의 경우. 창부품의 이름을 안다면, nametowidget(name_of_wdg)를 사용하여 그것을 Tkinter 객체로 변환할 수 있다. 또한, wdg.master를 사용하면 창부품의 그릇을 열람할 수 있다 (이것은 창부품의 이름 말고 Tkinter 창부품을 돌려준다.).
  • tkFont.Font 객체의 경우 (Tk의 "named font"에 상응함). tkFont.Font 객체를 만들어서 창부품의 폰트를 설정하면, tkFont.Font 객체를 조작하자 마자 그 창부품의 폰트가 바뀐다. 이는 사용자-설정 같은 것에 아주 간편하다. tk named 폰트의 이름을 안다면, 그 이름 인자를 지정하고 exists=True로 지정하면 그에 기반하여 새로운 tkFont.Font 객체를 만들 수 있다. (exists=False라면, 새로운 tk named 폰트가 생성된다. 이 폰트는 tkFont.Font 객체가 사라지면 소멸되니 조심하자!).
  • 주의: getvar와 setvar 그리고 nametowidget은 어떤 Tkinter 창부품에도 호출될 수 있다. 간편하게도 any_widget.getvar(name_of_var)이 있다.

힌트

힌트 일반:

  • 스크롤바를 꾸리고 난 후에 창부품을 달자. 그러면 창이 너무 줄어들어서 모두 나타낼 수 없을 경우에도, 스크롤바가 여전히 보일 것이다.
  • 복잡하게 위치를 잡으려면, 틀을 두어 창부품을 모아두자; 꾸림자나 격자관리자에 너무 집착하는 것보다 이렇게 하는 것이 보통 더 쉽고 더 안전하다. 그러나 각 창부품에 올바로 그릇을 사용하도록 조심하자. 그렇지 않으면 혼란에 빠질 것이며, 심지어 격자관리자와 꾸림자가 서로 다툴수도 있다(무한 회돌이에 빠짐).

다음은 Tkinter에서 흔히 빠질 수 있는 몇가지 함정이다. 그리고 피하는 방법이다:

  • 역호출 함수는 반드시 반괄호 없이 지정되어야 하고 그리하여 인자가 없다. 반괄호를 지정하면, 파이썬은 그 함수를 (GUI이 설정된 대로) 그냥 한 번만 호출하고, 반환된 값이 역호출 함수로 사용된다. 이것은 초보자가 아주 흔히 빠지는 함정이다. 그 한가지 이유는 사용자가 종종 그 역호출 함수에 인자를 함게 지정하고 싶어하기 때문이다. 이를 해결하는 아주 멋진 방법은 역호출 싸개(callback shim)를 사용하는 것이다.
  • 같은 그릇 안에 꾸림자와 격자관리자 함께 절대로 사용하지 말자. 이렇게 하면 무한 회돌이에 빠진다! 창을 그리는 동안에 어플리케이션 크기가 줄면, 제일 먼저 이것을 점검하자. 또 찾기도 힘들다. 문제가 생기면, 각 창부품에 대하여 지정한 그릇을 주의깊게 살펴보자. 그릇을 잘못 지정했을 수도 있고 그릇을 지정하는 것을 깜빡했을 수도 있다 (기본은 root로 지정되어 있다).
  • 연관된 Tkinter 객체가 사라지면, 어떤 Tcl/Tk 객체들은 (창부품은 미포함) 삭제된다. 이 때문에 종종 혼란이 일어난다. 몇가지 예를 들면 다음과 같다:
    • 이미지: 이미지나 아이콘이 Tk 창부품으로부터 사라진다면, 그 이미지에 대한 Tkinter 표현에 대하여 참조점을 추적유지 하지 않았기 때문일 것이다.
    • 변수 (StringVar, 등등.): 라디오 버튼이 모두 설정이 사라지면, 그 변수가 여전히 존재하는지 점검해 보자. 변수에 관하여 내가 아는 한 그것이 가장 눈에 띄는 논란거리이다. Entry textvariable를 잃어 버리더라도, 적어도 기존의 텍스트는 그대로 있다. Trace_variable은 변수와 함수 모두에 대하여 참조점을 유지하는 것 같다. 그래서 따로 참조를 유지할 필요가 없다.
    • tkFont.Font 객체: 이것들은 tcl이 폰트에 이름붙인 Tkinter 표현이며 위젯 모듬 단위로 폰트를 구성하기에 유용하다. 나중에 그 창부품들을 다시 환경구성하고 싶다면 참조점을 유지하자. 그렇지 않으면 그냥 안전하게 tkFont.Font 객체가 알아서 하게 두어도 된다. 왜냐하면 그 창부품들이 지난 환경구성값들을 유지하고 있기 때문이다.
    • 주의: 한 창부품에 이미 삭제된 변수나 기타 항목을 질의한다면, 그 삭제된 항목의 전 이름이 반환되지, 그 항목이 삭제되었다고 가르쳐 주지 않는다. 그래서 이 문제를 디버깅하는 일은 어려울 수 있다. 한가지 시도해 볼 만한 것은 그 이름을 새로운 Tkinter 객체로 변환해 보는 것이다 (예를 들어 root.getvar(name) 또는 tkFont.Font(name, exists=True)); 이는 tcl 객체가 삭제되면 실패할 것이다.
  • Tkinter에는 반드시 주 쓰레드에서부터 접근해야 한다. (다시 말해, 더 정확하게 말하면, mainloop를 호출한 쓰레드에서부터 접근해야 한다). 이를 어기면 별별 해괴한 증상들이 야기 된다. 이 때문에 멀티-쓰레딩과 Tkinter를 조합해 쓰기가 아주 어렵다. 본인이 발견한 유일하게 안전한 방법은 폴링(polling)이다(즉, 주 회돌이에서 after를 사용하여 쓰레드가 작성한 threading Queue를 폴링하면 된다). 쓰레드가 event_create를 사용하면 주 회돌이와 안전하게 통신할 수 있을 것 같지만, 이 방법은 안전하지 않다.
  • 인자의 기본 값으로 수정가능 객체를 절대로 사용하지 말자 (리스트나 사전 같은 객체). (함수가 내부적으로 그 인자를 조작하면) 기본 값은 너무 쉽게 바뀔 수 있다. 그리하여 def foo(alist=[]):...는 앞으로 엄청난 재앙이 일어나기를 기다리는 짓이다. 이 문제를 피하려면, 기본 값에 None을 사용한 다음, 내부적으로 None을 테스트하고 그것을 []로 바꾸자 (또는 {} 기타 무엇이든).

좀 희귀한 Tkinter 함정들:

  • 변수(Variable)를 추적한 결과로 코드를 실행하면 그리고 그 코드의 결과가 또다른 변수(Variable)에 설정되면, 그 "다른 변수(Variable)"는 코드가 실행을 마칠 때까지 설정되지 않을 수도 있다. Text.search를 실행하고서 count 변수를 사용하고자 할 때 이것을 발견하였다 (이것을 버그로 보고하였지만, 혹 특징일지도 모르겠다.)

자원

  • 프레드릭 룬트(Fredrik Lundh)의 Tkinter 개론은 시작하기에 좋은 곳이다. 불행하게도, 미완성이며 아직도 그래 보인다.
  • 알렉스 마르텔리(Alex Martelli)의 "Python in a Nutshell"은 Tkinter를 간결하지만 깔끔하게 소개하고 있다. 또한 아주 훌륭한 파이썬 참조 책이다; 나의 견해로 파이썬 프로그래머라면 "Python in a Nutshell" 그리고 데이비드 비즐리(David Beazley)의 "Python Essential Reference"가 꼭 있어야 할 것이다.
  • Tkinter Folkore는 본인이 Tkinter에 관하여 좋은 문서를 찾으면서 어렵게 모아 놓은 문서이다.
  • Tcl/Tk는 Tkinter와 아주 비슷하고 (그리고 Tkinter에 관한 정보가 너무 부족하므로) Tcl/Tk 참조서를 가까이 하면 아주 도움이 될 것이다. 얻을 수 있는 자원을 모두 알지는 못한다. 그러나 내가 주로 참조하는 자원 두 가지는 다음과 같다:
  • 존 그레이스(John Grayson)이 지은 Python and Tkinter Programming은 현재로 Tkiner에 관하여 유일하게 전념한 책이다. 그러나 Tkinter를 희생하고 Pmw(Python MegaWidgets)에 많은 지면을 할애하고 있으니 주의하자. 또한, 중요한 정보가 숨어있거나 빠져 있다. 그러나 Tk로 작업을 많이 한다면 꼭 필요할 것이다. 본인은 보통 제일 먼저 이 책을 참조하고, 여전히 의문이 남아 있으면 Tcl/Tk 참조서를 본다 (위 참조).
  • Tkinter용 코드를 읽고 같은 디렉토리 안에 있는 파일들을 참조하자. 좋은 코드를 많이 발견하실 수 있고 문제를 해결할 수도 있다. (Tkinter 디렉토리를 찾으려면 Tkinter를 반입한 다음 Tkinter.__file__을 인쇄해보자).

러셀 오웬(Russell Owen) 작성. 한글판 johnsonj 2008.04.11 Last updated 2006-10-20 (트로엘스 터켈슨(Troels Therkelsen)의 제안을 포함시켜 힌트 섹션을 개정함. 자원 섹션을 개정함). 이 문서는 자유롭게 배포가 가능하지만 판매용으로는 사용할 수 없다.

'파이썬 프로그래밍' 카테고리의 다른 글

Tkinter GUI 프로그래밍  (0) 2011.04.24
Tkinter로 생각하기  (0) 2011.04.24
UltraEdit Python 설정  (0) 2009.06.28
파이썬 데몬 만들기  (0) 2009.04.07
파이썬으로 재귀하향 파서 만들기(2)  (0) 2009.03.02

+ Recent posts