Skip to content

Python:tkinter

tkinter 패키지(《Tk 인터페이스》)는 Tk GUI 툴킷에 대한 표준 파이썬 인터페이스입니다. Tk와 tkinter는 대부분의 유닉스 플랫폼과 윈도우 시스템에서 사용할 수 있습니다. (Tk 자체는 파이썬 일부가 아닙니다; ActiveState에서 유지 보수됩니다.)

명령 줄에서 <codee>python -m tkinter</code>를 실행하면 간단한 Tk 인터페이스를 보여주는 창을 열어, tkinter가 시스템에 제대로 설치되었는지 알 수 있도록 하고, 설치된 Tcl/Tk 버전을 보여주기 때문에, 그 버전에 해당하는 Tcl/Tk 설명서를 읽을 수 있습니다.

Widgets

  • Button - 단순한 버튼
  • Label - 텍스트 혹은 이미지 표시
  • CheckButton - 체크박스
  • Entry - 단순한 한 라인 텍스트 박스
  • ListBox - 리스트 박스
  • RadioButton - 옵션 버튼
  • Message - Label과 비슷하게 텍스트 표시. Label과 달리 자동 래핑 기능이 있다.
  • Scale - 슬라이스 바
  • Scrollbar - 스크롤 바
  • Text - 멀티 라인 텍스트 박스로서 일부 Rich Text 기능 제공
  • Menu - 메뉴 Pane
  • Menubutton - 메뉴 버튼
  • Toplevel - 새 윈도우를 생성할 때 사용. Tk()는 윈도우를 자동으로 생성하지만 추가로 새 윈도우 혹은 다이얼로그를 만들 경우 Toplevel를 사용한다
  • Frame - 컨테이너 위젯. 다른 위젯들을 그룹화할 때 사용
  • Canvas - 그래프와 점들로 그림을 그릴 수 있으며, 커스텀 위젯을 만드는데 사용될 수도 있다

Open File Dialog

from tkinter import filedialog as fd
filename = fd.askopenfilename()

Python:tkinter with OpenCV

OpenCV를 Python:Tkinter에 그리는 방법. OpenCV:Example:Tkinter 항목 참조.

컴포넌트를 윈도우 크기에 맞춰 변하게 하기

pack 함수를 쓸 때 인자를 주의하자.

self.c=Canvas()
self.c.pack(fill="both", expand=True)

Event Object

이벤트핸들러(이벤트 콜백)는 event라는 하나의 파라미터를 갖는데, 이는 Tkinter Event Object 로서 다음과 같은 속성(attribute)들을 갖는다. 위의 #2 예제를 보면, click() 함수에서 event 파라미터를 받아들이고, 이 event의 x, y 좌표를 사용하고 있음을 알 수 있다.

  • char - 키보트 이벤트에서 발생하는 문자 하나
  • keysym - 키보트 이벤트에서 발생하는 키의 심볼명
  • num - 마우스 이벤트의 버튼 번호. 왼쪽부터 1, 2, 3
  • x, y - 위젯의 죄상단으로부터의 상대적 마우스 위치
  • x_root, y_root - 화면 죄상단으로부터의 상대적 마우스 위치
  • Key - 이벤트가 발생한 위젯

Asyncio with tkinter

import tkinter as tk
from tkinter import ttk
import asyncio


class App:
    async def exec(self):
        self.window = Window(asyncio.get_event_loop())
        await self.window.show();


class Window(tk.Tk):
    def __init__(self, loop):
        self.loop = loop
        self.root = tk.Tk()
        self.animation = "░▒▒▒▒▒"
        self.label = tk.Label(text="")
        self.label.grid(row=0, columnspan=2, padx=(8, 8), pady=(16, 0))
        self.progressbar = ttk.Progressbar(length=280)
        self.progressbar.grid(row=1, columnspan=2, padx=(8, 8), pady=(16, 0))
        button_block = tk.Button(text="Calculate Sync", width=10, command=self.calculate_sync)
        button_block.grid(row=2, column=0, sticky=tk.W, padx=8, pady=8)
        button_non_block = tk.Button(text="Calculate Async", width=10, command=lambda: self.loop.create_task(self.calculate_async()))
        button_non_block.grid(row=2, column=1, sticky=tk.W, padx=8, pady=8)

    async def show(self):
        while True:
            self.label["text"] = self.animation
            self.animation = self.animation[1:] + self.animation[0]
            self.root.update()
            await asyncio.sleep(.1)

    def calculate_sync(self):
        max = 3000000
        for i in range(1, max):
            self.progressbar["value"] = i / max * 100

    async def calculate_async(self):
        max = 3000000
        for i in range(1, max):
            self.progressbar["value"] = i / max * 100
            if i % 1000 == 0:
                await asyncio.sleep(0)

asyncio.run(App().exec())

다른 버전

# This demo is a transliteration of the below referenced demo to use the async/await syntax
#
#https://www.reddit.com/r/Python/comments/33ecpl/neat_discovery_how_to_combine_asyncio_and_tkinter/

#
# For testing purposes you may use the following command to create a test daemon:
# tail -f /var/log/messages | nc -l 5900
# Enter localhost:5900 in the entry box to connect to it.

from tkinter import *
import asyncio

async def run_tk(root, interval=0.05):
    '''
    Run a tkinter app in an asyncio event loop.
    '''
    try:
        while True:
            root.update()
            await asyncio.sleep(interval)
    except TclError as e:
        if "application has been destroyed" not in e.args[0]:
            raise

async def tclient(addr,port):
    print('tclient',addr,port)
    try:
        sock ,_= await asyncio.open_connection(host=addr,port=port)
       #print(sock)
       #f=sock.as_stream()
        while True:
               #data = yield from f.readline() 
                data = await sock.readline()
                if not data:break
                data=data.decode()
                print(data,end='\n' if data[-1]=='\r' else'')
    except:
        pass


async def main():
    root = Tk()
    entry = Entry(root)
    entry.grid()

    def spawn_ws_listener():
       addr=entry.get().split(':')
       print('spawn',addr)
       return asyncio.ensure_future( tclient( addr[0],int(addr[1]) ) )

    Button(root, text='Connect', command=spawn_ws_listener).grid()

    await run_tk(root)

if __name__ == "__main__":
    asyncio.get_event_loop().run_until_complete(main())

Troubleshooting

AttributeError: 'PhotoImage' object has no attribute '_PhotoImage__photo'

다음과 같은 에러가 나온다

AttributeError: 'PhotoImage' object has no attribute '_PhotoImage__photo'

해당하는 위치는:

from PIL.ImageTk import PhotoImage
from numpy import uint8, zeros

empty = zeros((height, width, 3), dtype=uint8)
photo = PhotoImage(empty)

다음과 같이 수정:

from PIL.Image import fromarray

photo = PhotoImage(image=fromarray(empty))

See also

Favorite site