Difference between revisions of "트킨터"

Jump to navigation Jump to search
56,418 bytes added ,  21:42, 15 July 2021
no edit summary
 
(38 intermediate revisions by 12 users not shown)
Line 1: Line 1:
{{Template:바로가기}}
{{Template:바로 가기}}
<div style="float: right; margin-left: 12px">__TOC__</div>
<div style="float: right; margin-left: 12px">__TOC__</div>
= 개요 =
[[트킨터]]([[Tkinter]]) [[모듈]]([[module]])은 Tk GUI [[툴킷]]([[toolkit]])에 대한 [[파이썬]]([[Python]])의 표준 인터페이스이다. Tkinter는 Tk interface의 줄임말이다.


[[티케이]]([[Tk]])는 플랫폼 독립적인 [[GUI]] 라이브러리이다. 많은 [[프로그래밍 언어]]에서 [[그래픽 유저 인터페이스]](GUI)를 만들기 위한 GUI [[위젯]](widget)의 기본 요소들의 [[라이브러리]](library)를 제공하는 [[오픈 소스]] [[크로스 플랫폼]] 위젯 툴킷이다.
[[트킨터]] ([[Tkinter]]) [[패키지]]는 Tk GUI [[툴킷]]([[toolkit]])에 대한 [[파이썬]]([[Python]])의 표준 인터페이스이다. Tkinter는 Tk interface의 줄임말로 [[트킨터]] 또는 [[티케이인터]]라고 읽는다. ttk나 messagebox같은 [[모듈]]을 모아놓은 것을 Tkinter [[package]]라고 한다.
 
[[Tk]]는 플랫폼 독립적인 [[GUI]] 라이브러리이다. [[티케이]]는 많은 [[프로그래밍 언어]]에서 [[그래픽 유저 인터페이스]](GUI)를 만들기 위한 GUI [[위젯]](widget)의 기본 요소들의 [[라이브러리]](library)를 제공하는 [[오픈 소스]] [[크로스 플랫폼]] 위젯 툴킷이다.


[[Tcl]]은 [[Tool Command Language]]의 약자로 [[티클]] 또는 [[티씨엘]]이라고 읽는다. Tcl은 [[스크맆트 언어]]로 [[프로토타이핑]], 스크맆트 프로그램, GUI 및 테스팅, [[CGI]], [[IRC]] [[봇]]([[bot]])을 만드는데 사용된다.
[[Tcl]]은 [[Tool Command Language]]의 약자로 [[티클]] 또는 [[티씨엘]]이라고 읽는다. Tcl은 [[스크맆트 언어]]로 [[프로토타이핑]], 스크맆트 프로그램, GUI 및 테스팅, [[CGI]], [[IRC]] [[봇]]([[bot]])을 만드는데 사용된다.


[[Tcl]]과 [[Tk]] GUI 툴킷을 묶어서 Tcl/Tk라고 부른다.
[[Tcl]]과 [[Tk]] GUI 툴킷을 묶어서 Tcl/Tk라고 부른다.
이 [[문서]]의 [[쏠쓰 코드]] ([[source code]])는 [[우분투]] 19.10, [[파이썬]] 3.7.5에서 테스트되었다.




Line 20: Line 24:




[[리눅스 민트]]에는 python3-tk 패키지가 설치되어있지 않으므로 [[터미널]]에서
[[우분투]] 19.10에는 python3-tk 패키지가 설치되어있지 않으므로 [[터미널]] ([[terminal]])에서
  sudo apt-get install python3-tk
  sudo apt install python3-tk
하여 관련 패키지들을 설치해준다.
[[명령어]] ([[command]])를 입력하여 관련 패키지를 설치해준다.
 
 
 
[[소스 코드]] [[편집기]]로는 [[VS코디엄]] ([[VSCodium]])이나 적당히 아무거나 쓰면 된다.
 
 
우분투 19.10의 경우
python3 cal.py
와 같은 방식으로 실행시키면 된다.


= pack, grid로 부품 배열 =
== pack, grid로 부품 배열 ==
박스 띄우기
박스 띄우기


Tk()는 트킨터 객체의 생성자이다. 윈도10기준 프롬프트에서
Tk()는 트킨터 객체의 생성자이다.
  root=Tk()
  root=Tk()
하면 빈 창이 뜬다.
입력하면 빈 창이 뜬다.
 


(Tk객체).mainloop()를 하면 창에서 입력을 받아들인다.
(Tk객체).mainloop()를 하면 창에서 입력을 받아들인다.
root.mainloop()
와 같이 해주면 된다.


from tkinter import *
root=Tk()
  root.mainloop()
  root.mainloop()
와 같이 해주면 된다.
까지 최소 3줄을 [[쏠쓰 코드]] ([[source code]])에 포함해줘야 빈 창이 뜬다.




위젯(widget) 달기
위젯(widget) 달기


  bozy = 위젯명(달아줄 Tk객체, ... )
  pussy = widget_name(new_Tk_object, ... )
  bozy.pack()  
  pussy.pack()  


와 같은 방식으로 달아줄 수 있다. bozy는 임의로 붙인 명칭이다.
와 같은 방식으로 달아줄 수 있다. pussy는 임의로 붙인 명칭이다.




Line 50: Line 70:
  root = Tk()
  root = Tk()
   
   
  sister_bozy = Label(root, text = "예시")
  sister_pussy = Label(root, text = "sis pussy")
  sister_bozy.pack()
  sister_pussy.pack()


sister_bozy는 임의로 붙인 명칭이다. 그러나 = 옆의 Label은 반드시 그대로 써야한다.
sister_pussy는 임의로 붙인 명칭이다. 그러나 "Label"은 반드시 그대로 써야한다.




Line 67: Line 87:




== 레이블 1개, 입력 창 1개, 버튼 2개 ==
 
아래는 grid로 만들어본 상자이다. (기능은 없음)
완성된 [[코드]] ([[code]])는 아래와 같다.
 
from tkinter import *
root = Tk()
sister_pussy = Label(root, text = "sis pussy")
sister_pussy.pack()
root.mainloop()
 
 
=== 레이블 1개, 입력 창 1개, 버튼 2개 ===
아래는 grid로 만들어본 상자이다. (기능은 없다.)


  from tkinter import *
  from tkinter import *
  root = Tk()
  root = Tk()
   
   
  title = Label(root,text="입력")
  title = Label(root,text="Input")
  txtbox = Entry(root, width = 15)
  txtbox = Entry(root, width = 15)
  btn_1= Button(root, text = "전송", width=10)
  btn_1= Button(root, text = "Submit", width=10)
  btn_2 = Button(root, text = "취소", width=10)
  btn_2 = Button(root, text= "Cancel", width=10)
   
   
  title.grid(row=0, column=0)
  title.grid(row=0, column=0)
  txtbox.grid(row=0,column=1)
  txtbox.grid(row=0, column=1)
  btn_1.grid(row=1,column=1)
  btn_1.grid(row=1,column=1)
  btn_2.grid(row=2,column=1)
  btn_2.grid(row=2, column=1)
   
   
  root.mainloop()
  root.mainloop()
Line 94: Line 126:
  btn_2.grid(row=1,column=1)  
  btn_2.grid(row=1,column=1)  


* tkinter 처음하기 http://studioplug.tistory.com/219
* tkinter 처음하기 https://studioplug.tistory.com/219


== 레이블 2개, 입력 창 2개 ==
=== 레이블 2개, 입력 창 2개 ===
Grid라고 하는 geometry manager는 위젯을 2차원의 표에 놓습니다.
Grid라고 하는 geometry manager는 위젯을 2차원의 표에 놓습니다.
마스터위젯은 row와 column에 해당하는 숫자로 나뉘고, 완성된 표에서 각각의 '셀'(표의 한 칸)은 위젯을 잡아둡니다.
마스터위젯은 row와 column에 해당하는 숫자로 나뉘고, 완성된 표에서 각각의 '셀'(표의 한 칸)은 위젯을 잡아둡니다.
Line 147: Line 179:
위와 같이 sticky 옵션을 쓰지 않으면 위젯들이 각각의 셀(cell)에서 가운데 정렬된다. sticky 옵션은 N,S,E,W 중에 하나 이상의 값을 필요로 합니다. 레이블(label)들을 왼쪽정렬하기 위해, sticky=W를 사용합니다. N = north 북족, W = west 서쪽, E = east 동쪽, S = south 남쪽.
위와 같이 sticky 옵션을 쓰지 않으면 위젯들이 각각의 셀(cell)에서 가운데 정렬된다. sticky 옵션은 N,S,E,W 중에 하나 이상의 값을 필요로 합니다. 레이블(label)들을 왼쪽정렬하기 위해, sticky=W를 사용합니다. N = north 북족, W = west 서쪽, E = east 동쪽, S = south 남쪽.


=== 체크 박스와 그림 추가 ===
==== 체크 박스와 그림 추가 ====
  from tkinter import *
  from tkinter import *
  master = Tk()
  master = Tk()
Line 205: Line 237:


자세한 내용은 아래 링크 참조
자세한 내용은 아래 링크 참조
* tkinter grid method http://studioplug.tistory.com/220
* tkinter grid method https://studioplug.tistory.com/220
 
== 체크버튼, 콤보박스 넣기 ==
=== 레이블 안에 이미지 넣기 ===
1. Tkinter 위젯
 
앞 아티클에서 언급했듯이, Tkinter는 제한된(Limited) 핵심 위젯들만을 제공하고 있다. 아래는 Tkinter가 제공하는 주요 위젯들이다.
 
 
위젯 / 설명
 
Button 단순한 버튼
 
Label 텍스트 혹은 이미지 표시
 
CheckButton 체크박스
 
Entry 단순한 한 라인 텍스트 박스
 
ListBox 리스트 박스
 
RadioButton 옵션 버튼
 
Message Label과 비슷하게 텍스트 표시. Label과 달리 자동 래핑 기능이 있다.
 
Scale 슬라이스 바
 
Scrollbar 스크롤 바
 
Text 멀티 라인 텍스트 박스로서 일부 Rich Text 기능 제공
 
Menu 메뉴 Pane
 
Menubutton 메뉴 버튼
 
Toplevel 새 윈도우를 생성할 때 사용. Tk()는 윈도우를 자동으로 생성하지만 추가로 새 윈도우 혹은 다이얼로그를 만들 경우 Toplevel를 사용한다
 
Frame 컨테이너 위젯. 다른 위젯들을 그룹화할 때 사용
 
Canvas 그래프와 점들로 그림을 그릴 수 있으며, 커스텀 위젯을 만드는데 사용될 수도 있다
 
 
2. 위젯 사용
 
위젯은 객체를 생성하여 필요한 속성들을 지정하여 사용한다. 위젯은 부모 컨테이너와 연관하여 어떤 상대적 위치에 놓이게 되는데, 앞에 설명한 Geometry Manager를 사용하여 각 위젯의 위치를 정하게 된다.
 
아래 예제는 레이블 안에 이미지를 넣고 화면에 보여주는 코드로서, MyFrame 이라는 클래스를 만들고 생성자에서 필요한 위젯들을 배치하고 있다. 우선 main() 에서는 Tk 객체 root를 만들고 title()을 사용하여 윈도우 제목을 설정하고, geometry()를 사용하여 윈도우의 크기와 좌표를 정해주었다. geometry() 안의 문자열은 윈도우 크기 및 좌표를 "가로x세로+X+Y" 형식으로 표현한다. X는 모니터의 왼쪽으로부터 몇 픽셀이나 떨어졌나, Y는 모니터의 위쪽으로부터의 거리이며, -일 경우 오른쪽과 아래쪽으로부터의 거리이다.
 
MyFrame 클래스는 Frame으로부터 상속된 파생클래스이고, 생성자에서 Label 하나를 추가하고 있다. Label은 좌표 (0,0)에 위치(place)하게 되고, 레이블 안에는 이미지를 넣고 있다. 이미지는 tkinter의 PhotoImage 클래스를 사용하고 있는데, 이 클래스는 .gif 파일 (혹은 PGM) 만을 읽을 수 있다. 다른 이미지 포맷을 사용하기 위해서는 외부 모듈을 사용해야 한다. PhotoImage() 에 이미지 파일을 적고 리턴된 객체를 레이블에 지정하면 되는데, 특히 가비지 컬렉션으로부터 삭제되는 것을 방지하기 위해 lbl.image = img 처럼 레퍼런스를 증가시켜 준다.
 
from tkinter import *
class MyFrame(Frame):
    def __init__(self, master):
        img = PhotoImage(file='[[로리]].gif')
        lbl = Label(image=img)
        lbl.image = img  # 레퍼런스 추가
        lbl.place(x=0, y=0)
def main():
    root = Tk()
    root.title('[[로린이]] [[보지]]')
    root.geometry('500x400+10+10')
    myframe = MyFrame(root)
    root.mainloop()
if __name__ == '__main__':
    main()
 
예제로 배우는 파이썬 프로그래밍 - Tkinter 위젯 https://pythonstudy.xyz/python/article/121-Tkinter-%EC%9C%84%EC%A0%AF
 
=== 체크버튼 ===
checkbutton 위젯 체크버튼
 
이번에는 윈도우에 체크버튼을 추가해 보겠습니다. 아래 코드를 보세요.
 
from tkinter import *     
from tkinter import ttk     
from tkinter import messagebox
win = Tk()                 
def clickMe():               
    messagebox.showinfo('[[유두]] 만져졌다', "누군가 만졌다!")
action = ttk.Checkbutton(win, text='내 유두를 만져줘', command = clickMe)
action.grid(column=1, row=0)
win.mainloop() 
 
앞에서 본 Button 위젯의 예제를 재활용하였습니다.
라인7에서 Button이 Checkbutton으로 변경되었죠? 이 코드를 실행하면 버튼 대신 체크버튼이 윈도우에 추가됩니다. 그외의 부분은 동일한데요. Button위젯과 마찬가지로 체크버튼을 마우스로 클릭하면 clickMe() 함수가 실행되고 그 결과 메시지 박스가 실행됩니다.
 
 
Checkbutton 위젯 추가
 
체크버튼의 경우 GPIO 출력 값을 High, Low 중에 선택할때 사용하기 좋습니다.
 
아래는 여러 개의 체크버튼 위젯을 생성하고, 그 중 어떤 버튼이 체크되었는지 확인하는 예제입니다. 간단해서 눈으로만 봐도 이해할 수 있습니다.
 
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
win = Tk()
win.title("나에게 [[삽입]]해줘!")
win.geometry('200x100+200+200')
def clickMe():
    str = <nowiki>''</nowiki>
    if cVar1.get() == 1:
        str = str + '[[입]]에 [[사정]] 당함, '
    if cVar2.get() == 1:
        str = str + '[[보지]]에 사정 당함, '
    if cVar3.get() == 1:
        str = str + '[[항문]]에 사정 당함, '
    if str == <nowiki>''</nowiki>:
        str = "nothing was checked"
    messagebox.showinfo("[[임신]] 당함", str)
cVar1 = IntVar()
c1 = ttk.Checkbutton(win, text="입", variable = cVar1)
c1.grid(column=0, row=0)
cVar2 = IntVar()
c2 = ttk.Checkbutton(win, text="보지", variable = cVar2)
#c2.deselect()
c2.grid(column=0, row=1)
cVar3 = IntVar()
c3 = ttk.Checkbutton(win, text="항문", variable = cVar3)
#c3.deselect()
c3.grid(column=0, row=2)
action=ttk.Button(win, text="나에게 사정해줘!!", command=clickMe)
action.grid(column=0, row=3)
win.mainloop()
 
라인18, 라인21, 라인25에서는 체크버튼과 연결해서 사용할 변수를 생성하였습니다.
라인19, 라인22, 라인26 에서 체크버튼 위젯을 생성하였습니다. 체크버튼 위젯을 생성할 때 'variable = 변수명' 처럼 체크버튼의 상태값을 저장할 변수를 설정해 주었습니다. 예를 들어 라인19에 variable = cVar1 이라는 코드에 따라 생성한 체크버튼의 상태값은 cVar1이라는 변수에 연동됩니다. 체크버튼에 연동된 변수들은 해당 체크버튼이 선택되면 1 값으로 선택되지 않으면 0 값으로 설정됩니다.
라인7 ~ 라인17은 clickMe() 함수입니다.
라인9에서는 라인19에서 생성한 체크박스가 선택되었는지 확인합니다. 선택된 경우는 cVar1.get() 이 1값을 가지고, 선택되지 않은 경우는 cVar1.get() 은 0 값을 가집니다.
라인23에 deselect() 라는 함수는 체크박스가 선택되지 않은 상태로 만들어 줍니다. 파이썬에서 # 로 시작하는 라인은 실행되지 않는 주석문입니다.
 
코드를 실행하면 아래와 같은 윈도우가 나타납니다.
 
 
다수의 체크박스 위젯
 
윈도우가 나타나면 기능을 테스트 해봐야죠. 체크박스 위젯 중 [[보지]]와 [[항문]]을 클릭해서 위의 그림처럼 선택합니다. 그리고, "나에게 사정해줘!!"라는 버튼을 클릭합니다.
 
선택된 체크박스를 보여주는 메시지창
 
현재 선택된 체크박스를 메시지 박스에서 알려주고 있습니다.
 
intVar()
 
위의 예제에서는 intVar() 생성자로 변수를 생성하였습니다. 이렇게 만들어진 변수는 위젯과 연결된 변수라는 의미로 생각하세요. 위젯의 값이 변하면 변수값이 변하고, 변수 값이 변해도 위젯 상태가 변하도록 연결해 줍니다.
 
TKinter chekcbutton 체크버튼 위젯 intVar https://blog.naver.com/audiendo/220789279239
 
 
=== 텍스트박스 ===
textbox 위젯
 
윈도우에서 사용자의 키보드 입력을 받기 위해서는 텍스트박스 위젯을 사용합니다. 텍스트박스 위젯의 경우도 위젯과 연결된 변수를 사용해서 입력 문자열을 처리할 수 있습니다.
 
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
win = Tk ()
win.title("[[너]]가 가장 좋아하는 [[체위]]는?")
win.geometry('500x100+200+200')
def clickMe():
    messagebox.showinfo("[[나]]에게 [[실험]]해봐!", str.get())
str = StringVar()
textbox = ttk.Entry(win, width=50, textvariable=str)
textbox.grid(column = 0 , row = 0)
action=ttk.Button(win, text="[[보지]]에 쑤셔죠!", command=clickMe)
action.grid(column=0, row=1)
win.mainloop()
 
라인9에서 텍스트위젯과 연결할 str 변수를 생성하였습니다. 이번에는 사용한 생성자는 str 타입을 처리할 수 있는 StringVar() 입니다.
라인10에서 ttk.Entry() 메소드를 호출하여 텍스트박스 위젯을 생성하였습니다. "텍스트박스 위젯"은 생성자이름이 Entry() 예요. 이때 width=20 에서 텍스트박스 너비를 20 문자크기로 설정하였습니다. 그리고 textvariable = str 에서 라인9에서 생성한 변수를 텍스트박스 위젯과 연결하였습니다. 이제부터 텍스트박스에 키보드 입력이 들어오면 그래돌 str 변수에 반영됩니다. 물론 그 반대 방향으로도 반영됩니다.
그외에 grid()나 Button() 함수 설명은 이전 포스트에 설명되어 있으므로 생략하겠습니다.
라인12에서 생성된 버튼위젯에 연결된 함수(라인 7~라인8) clickMe()가 실행되면, str.get() 메소드를 이용하여 텍스트박스 위젯에 입력된 문자열을 가져와서 메시지 박스에 보여줍니다.
 
코드를 실행하면 아래와 같습니다.
 
 
Textbox 위젯을 추가한 윈도우
 
키보드 등으로부터 문자열을 입력받을 수 있는 텍스트박스 위젯이 생성되었습니다. 여기에 1234567 이라고 입력을 하였습니다. 그리고 'Click Me' 버튼을 클릭합니다.
 
 
Textbox 입력 문자열 출력
 
텍스트박스에 입력된 문자열을 정확히 보여주는 메시지 박스가 나타납니다. 이제 텍스트박스 위젯에 입력된 문자열을 구해오는 방법은 아시겠죠?
 
TKinter textbox 텍스트박스 위젯 https://blog.naver.com/audiendo/220791080634
 
 
=== 콤보박스 ===
combobox 위젯
 
텍스트 박스 위젯은 키보드를 이용해서 문자열을 사용자가 입력할 수 있도록 해줍니다. 하지만, 정해진 메뉴 내에서 선택을 하게 만드는 경우는 마우스만으로 조작이 가능한 콤보박스위젯을 사용하면 편리합니다. 입력할 문자열의 종류가 사전에 정해져 있는 경우 사용해야 합니다.
콤보박스는 메뉴를 가집니다. 메뉴는 리스트로 만들어 지고, 리스트를 콤보박스의 속성에 연결 시켜줌으로서 메뉴 등록을 완료할 수 있습니다.
 
아래 코드를 볼께요.


= 객체 지향 프로그래밍(클래스 사용) =
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
win = Tk ()
win.title("[[근친상간]]")
win.geometry('200x100+200+200')
def clickMe():
    messagebox.showinfo("[[임신]] 완료", str.get())
str = StringVar()
combo = ttk.Combobox(win, width=20, textvariable=str)
combo['values'] = ('[[엄마]]', '[[누나]]', '[[여동생]]', '[[딸]]')
combo.grid(column = 0 , row = 0)
combo.current(0)
action=ttk.Button(win, text="[[강간]]", command=clickMe)
action.grid(column=0, row=1)
win.mainloop()
 
라인9에서 콤보위젯과 연동할 변수 str 를 생성하였습니다.
라인10에서 ttk.Combobox() 함수로 콤보박스 위젯을 생성했습니다. 동시에 str 변수와 콤보박스 위젝을 연동하였습니다.
라인 11에서 콤보박스에 리스트를 생성하여 콤보박스 위젯의 values 속성에 할당하였습니다. 이로써 콤보박스에 메뉴가 등록되었습니다. 메뉴는 총 4 항목인데, '[[엄마]]', '[[누나]]', '[[여동생]]', '[[딸]]' 입니다.
라인13에서 콤보박스에 메뉴항목 4개 중에서 0 번째 'apple'이 선택된 상태로 만들어 주었습니다. 만일 윈도우 생성시 'pear'가 선택되어 있도록 만들고 싶으면 combo.current(3)으로 하면 됩니다.
 
그외에 앞의 포스팅에서 설명한 것들은 생략합니다.
 
코드 실행결과를 보겠습니다.
 
combo box 위젯 + button 위젯
 
콤보박스 위젯 메뉴 중에 '엄마'가 선택되어 있는 것이 보이시죠? 위젯 우측의 아래로 화살표 부분을 클릭하면 나머지 메뉴들을 볼 수 있습니다.
 
콤보박스에 등록된 문자열들
 
자~ 이중 '여동생'을 선택하겠습니다. 선택하고 '강간' 버튼을 클릭합니다.
 
콤보박스에서 선택된 문자열
 
메시지 창에 '여동생'이 선택되었음을 보여줍니다.
 
 
TKinter combobox 콤보박스 위젯
https://blog.naver.com/audiendo/220792145212
 
 
=== 버튼 클릭시 새 창 띄우기 ===
from tkinter import *
def nwindow():
    global nwin
    nwin = Toplevel()
    nwin.title("새 성노예")
    btn.config(state = 'disable')
    photo2 = PhotoImage(file = '/home/raper/사진/왕가슴 베이글녀.gif')
    lbl2 = Label(nwin, image = photo2)
    lbl2.pack()
    qbtn = Button(nwin, text = '맛을 봤으니 넌 사형', command = quit)
    qbtn.pack()
    nwin.mainloop()
def quit():
    nwin.destroy()
    btn.config(state = 'normal')
main = Tk()
main.title("옛 성노예")
main.geometry("750x650")
photo = PhotoImage(file = '/home/raper/사진/로린이.gif')
lbl = Label(main, image = photo)
lbl.pack()
btn = Button(main, text = "새로운 노예를 사러 가자", command = nwindow)
btn.pack()
main.mainloop()
 
from tkinter import *로 Tkinter 패키지를 불러온다.
 
def nwindow():로 nwindow 함수를 정의한다. () 안에 함수로 입력될 [[매개변수]]들을 [[쉼표]](,)로 구분해서 여러개 적어줄 수 있다. def __init__(self, master):와 같은 식으로 맨 앞에 self를 적어준다. 예를 들어 회원 정보를 저장하는 함수의 경우 def member(self, name, phone, address):처럼 이름(name), 폰 번호(phone), 주소(address)의 3개의 [[변수]]를 입력받아 저장할 수 있다. 입력값이 없는데 입력값이 없으면 오류가 나는 경우 () 안에 self를 적어준다. _가 2개 연속 있는 경우는 특별한 의미가 있는 것이다. __init__은 초기화하라는 것이다.
 
함수 안에 있는 pack()이나 변수 앞에 self가 붙어 self.pack()같은 형태인 경우 그 함수 내에서 쓰는 명령이나 변수라는 뜻이다.
 
nwindow 함수로 새 창을 띄운다. global nwin 하여 nwin을 전역 변수(global variable)로 설정하여 다른 함수에서도 사용할 수 있게 한다. global을 선언하지 않으면 같은 클래스(class) 안에 있더라도 다른 함수(def)에 있으면 사용 못 하는 지역 변수(local variable)이다. 전역 변수는 그 프로그램 전체에서 사용할 수 있다. global you, rape, sister, mother, daughter와 같은 식으로 쉼표(,)로 구분하여 여러개의 변수를 동시에 선언할 수 있다.
 
다른 클래스에 있는 함수는 다른 클래스의 이름이 classname이고 함수의 이름이 defname일 경우 classname.defname을 하면 사용할 수 있다.
 
Tkinter와 같이 모듈(외부의 py 파일)에 있는 클래스, 함수, 변수를 불러올 경우 우선 import로 그 모듈을 불러와야 한다. 그리고 모듈 파일의 이름이 modulename.py이고, 모듈 이름이 modulename, 클래스 이름이 classname, 함수 이름이 defname, 변수 이름이 variablename일 경우, modulename.classname, modulename.defname, modulename.variablename처럼 앞에 modulename.을 붙여주면 그 모듈의 클래스, 함수, 변수를 불러올 수 있다.
 
class MyFrame(Frame):와 같은 경우 MyFrame 클래스가 Frame 클래스를 [[상속]]했다는 의미이며 부모의 함수를 상속받았으므로 부모 클래스인 Frame의 함수를 마음대로 가져다가 쓸 수 있다. 그러나 부모인 Frame은 자식 클래스인 MyFrame의 함수를 가져다가 쓸 수 없다.
 
nwin = Toplevel()을 해서 새 창으로 띄운다. nwin = Tk()를 해도 새 창으로 뜨지만 빈 창만 뜬다.
 
nwin.title("새 성노예")에 창의 맨 위에 뜨는 창의 제목을 적어준다.
 
btn.config(state = 'disable')를 해주면 새 창을 닫지 않는 이상 새 창을 띄우는 버튼이 불활성화 되어 다시 클릭할 수 없다. 다시 클릭하려면 새 창을 닫아야 한다. 이 config를 해주지 않으면 새 창을 계속 띄울 수 있다.
 
[[리눅스]]의 경우 자신의 사용자 계정 이름이 raper일 경우 photo2 = PhotoImage(file = '/home/raper/사진/왕가슴 베이글녀.gif')와 같이 적어주면 된다. [[윈도우즈]]의 경우 photo2 = PhotoImage(file = 'D:\사진\왕가슴 베이글녀.gif')와 같이 적어주면 된다. 이미지 파일이 이 파이썬 프로그램과 같은 폴더에 있을 경우 photo2 = PhotoImage(file = '왕가슴 베이글녀.gif')만 적어줘도 된다.
 
/는 [[슬래시]]([[slash]]) 또는 [[빗금]]([[solidus]])이라고 부르며 [[유닉스]]나 [[리눅스]]에서 [[디렉터리]]를 구분할 때 사용한다. \는 [[역슬래시]]([[backslash]]) 또는 [[역사선]]([[reverse solidus]])이라고 불리며 [[윈도우즈]]에서 [[디렉터리]]를 구분할 때 사용한다. 한국어 윈도우즈에서는 역슬래시 대신 원화 기호 ₩를 사용한다. 대부분의 남한 키보드에는 역슬래시 대신에 원화 기호가 인쇄되어 있다.
 
qbtn = Button(nwin, text = '맛을 봤으니 넌 사형', command = quit)에 새 창의 닫기 버튼에 들어갈 말을 적어주면 된다.
 
btn.config(state = 'normal')이면 새 창을 닫으면 원래 있던 창의 새 창 띄우는 버튼이 다시 활성화되지만 이게 btn.config(state = 'disable')와 같으면 새 창을 닫아도 새 창을 띄우는 버튼이 불활성화된 상태 그대로 남는다.
 
main.geometry("750x650")면 가로 750, 세로 650 크기의 창이 열린다. main.geometry("750x650+350+200")이면 모니터의 왼쪽으로부터 350, 위로부터 200 떨어진 위치에 창이 열리고, main.geometry("750x650-130-180")이면 모니터의 오른쪽에서 130, 아래에서 180 떨어진 위치에 창이 열린다.
 
 
(Tkinter) Image won't show up in new window
https://stackoverflow.com/questions/35924690/tkinter-image-wont-show-up-in-new-window
 
 
=== 프레임 여러개 만들기 ===
아래 예제는 고객 데이타를 입력 받는 간단한 윈도우 샘플이다. 메인 Frame 안에 4개의 자식 Frame을 사용하였고, 각각의 자식 Frame 안에 레이블, 텍스트, 버튼 등의 위젯들을 추가하였다.
 
from tkinter import *
from tkinter.ttk import *
class MyFrame(Frame):
    def __init__(self, master):
        Frame.__init__(self, master)
 
        self.master = master
        self.master.title("[[오피걸]] 고객 입력")
        self.pack(fill=BOTH, expand=True)
 
        # 성명
        frame1 = Frame(self)
        frame1.pack(fill=X)
 
        lblName = Label(frame1, text="성명", width=10)
        lblName.pack(side=LEFT, padx=10, pady=10)
 
        entryName = Entry(frame1)
        entryName.pack(fill=X, padx=10, expand=True)
 
        # 회사
        frame2 = Frame(self)
        frame2.pack(fill=X)
 
        lblComp = Label(frame2, text="회사명", width=10)
        lblComp.pack(side=LEFT, padx=10, pady=10)
 
        entryComp = Entry(frame2)
        entryComp.pack(fill=X, padx=10, expand=True)
 
        # 특징
        frame3 = Frame(self)
        frame3.pack(fill=BOTH, expand=True)
 
        lblComment = Label(frame3, text="특징", width=10)
        lblComment.pack(side=LEFT, anchor=N, padx=10, pady=10)
 
        txtComment = Text(frame3)
        txtComment.pack(fill=X, pady=10, padx=10)
 
        # 저장
        frame4 = Frame(self)
        frame4.pack(fill=X)
        btnSave = Button(frame4, text="저장")
        btnSave.pack(side=LEFT, padx=10, pady=10)
 
 
def main():
    root = Tk()
    root.geometry("600x550+100+100")
    app = MyFrame(root)
    root.mainloop()
if __name__ == '__main__':
    main()
 
예제로 배우는 파이썬 프로그래밍 - Tkinter 위젯 https://pythonstudy.xyz/python/article/121-Tkinter-%EC%9C%84%EC%A0%AF
 
 
=== 체크버튼과 입력값으로 if문 만들기 ===
from tkinter import *
from tkinter import ttk, messagebox
 
class cframe:
    def __init__(self, fr):
        self.defframe = fr
        self.fr0 = Frame(fr)
        self.fr0.pack()
        global virgin, bitch, price, rent
        virgin = IntVar()
        bitch = IntVar()
        price = IntVar()
        rent = IntVar()
        self.fr1 = Frame(self.fr0)
        self.fr1.pack(fill=X)
        imgplace = PhotoImage(file = '로리공주.gif')
        self.la1 = Label(self.fr1, image = imgplace)
        self.la1.image = imgplace
        self.la1.pack()
        self.fr2 = Frame(self.fr0)
        self.fr2.pack(fill = X)
        self.la2 = Label(self.fr2, text = "처녀막이 있다고 생각함?")
        self.la2.pack(side = LEFT)
        self.cb2_2 = Checkbutton(self.fr2, text = '걸레', variable = bitch)
        self.cb2_2.pack(side = RIGHT)
        self.cb2_1 = Checkbutton(self.fr2, text = '처녀', variable = virgin)
        self.cb2_1.pack(side = RIGHT)
        self.fr3 = Frame(self.fr0)
        self.fr3.pack(fill=X)
        self.la3 = Label(self.fr3, text = "산다면 얼마까지 낼 생각?(가격은 백만원 단위로)")
        self.la3.pack(side = LEFT)
        self.en3 = Entry(self.fr3, textvariable = price)
        self.en3.pack(side = RIGHT)
        self.fr4 = Frame(self.fr0)
        self.fr4.pack(fill=X)
        self.la4 = Label(self.fr4, text = "남한테 빌려준다면 얼마에 빌려줄래?(가격은 백만원 단위로)")
        self.la4.pack(side = LEFT)
        self.en4 = Entry(self.fr4, textvariable = rent)
        self.en4.pack(side = RIGHT)
        self.fr5 = Frame(self.fr0)
        self.fr5.pack(fill=X)
        self.bu5_1 = ttk.Button(self.fr5, text = "입찰", command=cframe.selection)
        self.bu5_1.pack(side = LEFT)
        self.bu5_2 = ttk.Button(self.fr5, text = "포기", command=cframe.cbutton)
        self.bu5_2.pack(side = RIGHT)
    def selection():
        stringv = <nowiki>''</nowiki>
        if virgin.get() == 1 and bitch.get() == 1:
            stringv = "어떻게 처녀면서 걸레지?"
        elif virgin.get() == 1:
            if price.get() < 100:
                stringv = "처녀에 이정도 미인을 1억원도 안 내고 사려고?"
                if rent.get() > 10:
                    stringv = stringv + " 1억도 안 주고 산 걸 천만원 넘게 받고 빌려주다니 개새끼네."
                else:
                    stringv = stringv + " 1억도 투자 안 했으니까 싸게라도 많이 굴리면 본전은 뽑겠지!"
            elif 100 <= price.get() <= 1000:
                stringv = "이렇게 예쁜데다 처녀 공주인데 몇억은 내야지!"
                if rent.get() < 10:
                    stringv = stringv + " 몇억 주고 산 처녀를 천만원도 안 되는 돈에 빌려주다니 제정신?"
                else:
                    stringv = stringv + ' 몇억짜리 처녀인데 천만원은 넘게 받아야 빌려주지.'
            else:
                stringv = "아무리 처녀라도 10억원 이상을 내다니 미쳤네."
        elif bitch.get() == 1:
            if price.get() > 100:
                stringv = "걸레한테 1억원을 넘게 내다니 미쳤구나!"
                if rent.get() < 1:
                    stringv = stringv + ' 아무리 걸레라도 원래 공주였는데 고작 100만원도 안 받고 빌려준다니 완전 너덜너덜해질 때까지 굴릴 생각?'
                else:
                    stringv = stringv + ' 원래 공주였는데 이정도는 받아야 빌려주지.'
            elif 100 >= price.get() >= 10:
                stringv = '걸레 몸값으로는 이게 적정가지.'
                if rent.get() < 1:
                    stringv = stringv + ' 걸레인데 창녀로 굴리면서 화대로 100만원씩이나 받을 수는 없지.'
                else:
                    stringv = stringv + ' 명색이 공주인데 화대로 백만원은 받아야 하지 않겠어?'
            else:
                stringv = "예뻐도 비처녀라면 좀..."
                if rent.get() < 0.1:
                    stringv = stringv + ' 아무리 천만원도 안 주고 산 여자라고 해도 1회 십만원도 안 받고 빌려줄수가 있냐?'
                else:
                    stringv = stringv + ' 비싼 보지가 왔어요! 한 번 쑤시는데 10만원 넘게 듭니다!'
        else:
            stringv = "처녀가 아니면서 걸레도 아니라고?"
        messagebox.showinfo("경매 결과", stringv)
    def cbutton():
        mwin.destroy()
mwin = Tk()
mwin.title('노예 시장에 매물로 나온 공주')
mwin.geometry("620x420+290+160")
cfview = cframe(mwin)
mwin.mainloop()
 
 
체크버튼과 엔트리(Entry)로 값을 입력 받은 후 그 값을 if, elif, else문에 넣어 각각의 조건에 해당하는 문장을 새 창에 출력한다. 하나의 조건에 하나의 문장을 배당하고, 2개의 값의 조합에 2개의 문장이 조합되어 출력된다.
 
 
로리공주.gif 파일을 이 파이썬 프로그램과 같은 폴더에 넣어놓거나, 이미지 파일의 위치를 절대 경로나 상대 경로로 적어주어야 한다. 파일의 이름은 바뀌어도 되나 반드시 gif 파일이어야 하며 jpg나 png 파일은 쓸 수 없다.
 
 
절대 경로는 /home/username/사진/로리공주.gif 같은 것이나 D:\사진\로리공주.gif 같은 것이고, 상대 경로는 ./사진/로리공주.gif 나 .\사진\로리공주.gif 같은 것이다. [[유닉스]]와 [[리눅스]]에서는 [[디렉터리]] 구분을 [[슬래시]](/)로 하고, [[윈도우즈]]에서는 [[역슬래시]](\)나 [[원화]] 기호(₩)로 한다. 리눅스나 윈도우즈 모두 현재 폴더는 .으로 나타내며 상위 폴더는 ..으로 나타낸다. username 폴더에 해당하는 사용자의 홈 디렉터리는 ~로 표시한다. 루트(/)나 드라이브 문자(D:)처럼 최상위 경로부터 적는 것을 절대 경로라고 하고, 중간을 생략하고 현재 디렉터리 기준으로 적는 것을 상대 경로라고 한다.
 
 
즉, 이미지 파일이 이 파이썬 프로그램이 있는 폴더의 하위 폴더인 "사진" 폴더에 있을 경우 imgplace = PhotoImage(file = './사진/로리공주.gif') 와 같은 식으로 적어주면 된다. 다른 곳에서도 이 프로그램을 수정 없이 쓰기 위해서는 절대 경로로 적는 것은 피하고, 되도록이면 상대 경로로 적어줘야 한다. 이미지 파일이 1,000개쯤 된다고 생각해봐라. 이걸 다 수정하는 노가다를 하느니 처음부터 상대 경로로 적어주는 것이 좋다. 이미지 파일 뿐만 아니라 다른 파일의 경우도 마찬가지이다. 특히 [[웹 싸이트]] 만들 때 로컬 컴퓨터에서 개발할 때랑 [[가상 전용 써버]]([[VPS]])에 업로드 할 때랑 절대 경로가 다르므로 문제가 생기는 경우가 많다. 개발할 때부터 상대 경로만 쓰면 VPS에 그대로 업로드해도 잘 작동한다.
 
 
== 객체 지향 프로그래밍(클래스 사용) ==
[[파이썬]]에서는 [[클래스]](class)를 사용하여 [[객체 지향 프로그래밍]](object-oriented programming, OOP)을 할 수 있다.
[[파이썬]]에서는 [[클래스]](class)를 사용하여 [[객체 지향 프로그래밍]](object-oriented programming, OOP)을 할 수 있다.


Line 213: Line 747:
* Python,tkinter 입문 (Python, tkinter 간단히 사용하기 001) https://blog.naver.com/dudwo567890/130166663839
* Python,tkinter 입문 (Python, tkinter 간단히 사용하기 001) https://blog.naver.com/dudwo567890/130166663839


== 아무 것도 없는 창 ==
=== 아무 것도 없는 창 ===
  from tkinter import *
  from tkinter import *
   
   
Line 221: Line 755:
위에서 생성된 최상위창은 tkinter 애플리케이션에서 가장 높은 수준의 GUI구성요소이며, 최상위 창의 이름은 'root'로 하는것이 관례적이다.
위에서 생성된 최상위창은 tkinter 애플리케이션에서 가장 높은 수준의 GUI구성요소이며, 최상위 창의 이름은 'root'로 하는것이 관례적이다.


== packing 하기 ==
=== packing 하기 ===
아래 예제에서 tkinter 프로그래밍의 세가지 주요 개념이 나온다.
아래 예제에서 tkinter 프로그래밍의 세가지 주요 개념이 나온다.


Line 247: Line 781:
즉, 애플리케이션에 보여지도록 설정한다.
즉, 애플리케이션에 보여지도록 설정한다.


== 창 부품(위젯) 꾸리기 ==
=== 창 부품(위젯) 꾸리기 ===
창 가운데 녹색 버튼 띄우기.
창 가운데 녹색 버튼 띄우기.


Line 280: Line 814:
즉, root의 자식은 F이며, F의 자식은 button1이 되는것이다.
즉, root의 자식은 F이며, F의 자식은 button1이 되는것이다.


== 클래스 구조 ==
=== 클래스 구조 ===
왜 애플리케이션을 클래스로 구성하는가?
왜 애플리케이션을 클래스로 구성하는가?


Line 304: Line 838:
  root.mainloop()
  root.mainloop()


=== 중앙에 닫기 버튼이 있는 창 ===
==== 중앙에 닫기 버튼이 있는 창 ====
  import tkinter as tk
  import tkinter as tk
  class Application(tk.Frame):
  class Application(tk.Frame):
Line 320: Line 854:
창이 작게 뜨기 때문에 창 맨 위에 뜨는 제목(title)인 "니 [[애미]] 보지"가 보이지 않는다. 마우스로 창을 키우면 창 이름인 "니 애미 [[보지]]"가 보인다.
창이 작게 뜨기 때문에 창 맨 위에 뜨는 제목(title)인 "니 [[애미]] 보지"가 보이지 않는다. 마우스로 창을 키우면 창 이름인 "니 애미 [[보지]]"가 보인다.


== 속성 설정하기 ==
=== 속성 설정하기 ===
  from tkinter import *
  from tkinter import *
   
   
Line 359: Line 893:
또 한 가지 주목할 점은 버튼을 추가한 순서대로 차곡차곡 쌓이며 보여지는것을 알수 있다.
또 한 가지 주목할 점은 버튼을 추가한 순서대로 차곡차곡 쌓이며 보여지는것을 알수 있다.


== 정렬 ==
=== 정렬 ===
packing은 구성요소의 시각적 관계를 제어하는 방법이다.
packing은 구성요소의 시각적 관계를 제어하는 방법이다.


Line 419: Line 953:
복잡한 GUI를 다루는 방법으로 여러 동선을 사용하고 싶을땐, 그릇안에 그릇을 내포시키는 것이다.
복잡한 GUI를 다루는 방법으로 여러 동선을 사용하고 싶을땐, 그릇안에 그릇을 내포시키는 것이다.


== 사건 묶기 ==
=== 사건 묶기 ===
사건묶기(binding)이란 다음과 같은 객체들 사이의 관계 또는 연결을 정의하는 과정이다.
사건묶기(binding)이란 다음과 같은 객체들 사이의 관계 또는 연결을 정의하는 과정이다.


Line 503: Line 1,037:
이런식으로 동작하려면 myapp은 자신의 자손이 누구인지 알아야 한다. 그래서 5행에서 myapp이 그의 부모를 기억하도록 한것이다.
이런식으로 동작하려면 myapp은 자신의 자손이 누구인지 알아야 한다. 그래서 5행에서 myapp이 그의 부모를 기억하도록 한것이다.


== 초점 ==
=== 초점(focus) ===
위의 예제에서는 마우스로 클릭하면 버튼에게 일을 시킬수 있었다.
위의 예제에서는 마우스로 클릭하면 버튼에게 일을 시킬 수 있었다.


다음 프로그램에서는 마우스뿐만 아니라 키보드에도 반응시키는 방법을 다루도록 하겠다.
다음 프로그램에서는 마우스뿐만 아니라 키보드에도 반응시키는 방법을 다루도록 하겠다.


먼저, "입력초점(input focus)" 또는 그냥 단순하게 "초점(focus)"이라는 개념을 알필요가 있다.
먼저, "입력 초점(input focus)" 또는 그냥 단순하게 "초점(focus)"이라는 개념을 알필요가 있다.


"초점(focus)"은 GUI상의 창부품들에게 키보드 사건을 볼수 있도록 해준다.
"초점(focus)"은 GUI상의 창부품들에게 키보드 사건을 볼수 있도록 해준다.
Line 530: Line 1,064:
  class MyApp:
  class MyApp:
     def __init__(self,parent):
     def __init__(self,parent):
        self.myparent=Frame(parent)
         self.F=Frame(parent)
         self.F=Frame(parent)
         self.F.pack()
         self.F.pack()
Line 555: Line 1,088:
     def button2Click(self,event):
     def button2Click(self,event):
         report_event(event)
         report_event(event)
         self.myparent.destroy()
         root.destroy()
   
   
  def report_event(event):
  def report_event(event):
    print('time', event.time, 'type', event.type, 'widget', event.widget, "keysym", event.keysym, "num", event.num, "char", event.char, "x", event.x, 'y', event.y, 'x_root', event.x_root, 'y_root', event.y_root, )
     event_name={"2":"KeyPress","4":"ButtonPress"}
     event_name={"2":"KeyPress","4":"ButtonPress"}
    print()
     print("시간:",str(event.time))
     print("시간:",str(event.time))
     print("이벤트 종류 = "+str(event.type))
     print("이벤트 종류 = "+str(event.type))
Line 570: Line 1,105:
  root.mainloop()
  root.mainloop()


= 창 부품, 틀의 크기 지정 =
[[윈도우즈]]에서는 report_event에서 시간과 이벤트 종류는 화면에 뜨지만 다른 부분들은 오류가 발생하여 뜨지 않는다. [[리눅스]]에서는 정상적으로 작동한다.
Python,tkinter 크기및여백지정에 사용되는 단위(pixel,mm) https://blog.naver.com/dudwo567890/130166668382
 
 
이벤트명
 
bind() 메서드의 첫번째 파라미터로 사용하는 이벤트명은 문자열로서 <이벤트명> 과 같이 앵글 브래킷으로 묶여 있다. 다음은 자주 사용되는 이벤트명을 예시한 것이다.
 
<Button-1> 마우스 왼쪽 버튼 클릭
 
<Button-2> 마우스 중간 버튼 클릭
 
<Button-3> 마우스 오른쪽 버튼 클릭
 
<Double-Button-1> 왼쪽 버튼 더블클릭
 
<Return> Enter 키 눌려짐
 
<Key> 키가 눌려짐
 
 
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 이벤트가 발생한 위젯
 
==== 키보드 입력을 보여주기 ====
아래 예제는 Key 이벤트에 대해 keyPressed() 함수를 바인딩하고, 전달된 event.char 를 써서 눌려진 키를 프린트하는 코드이다.
 
from tkinter import *
 
def keyPressed(event):
    # 키보드 문자 하나 출력
    print(event.char)
 
root = Tk()
 
frame = Frame(root, width=100, height=100)
# Key 이벤트 바인딩
frame.bind('<Key>', keyPressed)
frame.place(x=0, y=0)
 
# 키보드 포커스를 갖게 한다
frame.focus_set()
 
root.mainloop()
 
예제로 배우는 파이썬 프로그래밍 - Tkinter 이벤트 https://pythonstudy.xyz/python/article/122-Tkinter-%EC%9D%B4%EB%B2%A4%ED%8A%B8
 
=== 명령어 묶기 ===
명령어 묶기(Command Binding)
 
앞의 프로그램에서 사건묶기를 소개했다. 사건처리자를 창부품에 묶는 방법이 한가지 더 있는데, 바로 명령어묶기(Command Binding)이다.
 
지난 프로그램에서는 "<Button-1>"을 버튼창부품에 묶었다. "<Button-1>"은 "<ButtonPress>"와 같은 사건을 의미한다.
 
또한 마우스클릭에 해당하는 사건에는 "<ButtonPress>"와 "<ButtonRelease>"가 있는데 이 두사건은 큰 차이가 있다.
 
"<ButtonPress>"는 마우스를 누르는 동작이고,
 
"<ButtonRelease>"는 마우스를 누른후 떼는 동작이다.
 
위 두가지를 구별하는 이유는 드래그앱드랍을 지원하기 위해서 이다.
 
from tkinter import *
class MyApp:
    def __init__(self, parent):
        self.myParent=parent
        self.myContainer1=Frame(parent)
        self.myContainer1.pack()
        self.button1=Button(self.myContainer1, command=self.button1Click)
        self.button1.configure(text="OK",background="green")
        self.button1.pack(side=LEFT)
        self.button1.focus_force()
        self.button2=Button(self.myContainer1, command=self.button2Click)
        self.button2.configure(text="Cancel",background="red")
        self.button2.pack(side=RIGHT)
    def button1Click(self):
        print("Button1Click event handler")
        if self.button1["background"]=="green":
            self.button1["background"]="yellow"
        else:
            self.button1["background"]="green"
    def button2Click(self):
        print("Button2Click event handler")
        self.myParent.destroy()
root=Tk()
MyApp(root)
root.mainloop()
 
실행결과를 보면 이전 예제와 크게 다르지 않지만
 
행위는 다르다.
 
 
위의 예제는 마우스버튼을 누르기만 하면 동작을 한다. 즉, ButtonPress상태에서 메시지가 출력되었다.
 
또한, 버튼에 초점을 맞춘후 Enter키를 눌렀을경우, <Return>액션에 대한 메시지가 출력되었다.
 
 
하지만 이번 예제는 버튼자체에 명령어를 묶음으로서
 
클릭(ButtonRelease)와 스페이스에 대해 함꼐 동작을 하는걸 확인할수 있다.
 
즉, 버튼자체에 명령어를 묶어주는것을 명령어 묶기 라고 할수 있다.
 
=== 사건묶기와 명령어묶기의 차이 ===
바로 위 예제에서는 Tab키를 이용하여 초점을 "OK"버튼창부품에 두고, 스페이스바를 눌러서 버튼색이 바뀌도록 할수는 있지만, 엔터키를 투르면 아무 효과도 없다.
 
그 이유는 버튼창부품에 대하여 "command"옵션에 마우스사건 인지뿐만 아니라 키보드사건에 대한 인지가 제공되기 때문이다.
 
창 부품이 기다리는 키보드사건은 "<Return>"키가 아니라 스페이스바이다.
 
명령어묶기로 사건처리자를 묶었다면 스페이스바를 누르면 동작을 하겠지만, 엔터키는 아무 효과가 없다.
 
 
따라서 명령어묶기를 사용할 생각이라면 정확하게 무엇에 묶고 싶은지 잘 이해하는것이 좋다.
 
다시 말해, 무슨 키보드/마우스 사건이 명령어를 호출하는지 정확하게 이해하는 것이 좋다는것이다.
 
 
또한 모든 창부품이 "command"옵션을 제공하는것은 아니다. 다양한 버튼창부품들(라디오버튼,체크버튼 등)은 "command"옵션이 제공된다.
 
그외 다른것들은 비슷한옵션(예를들어 "scrollcommand")를 제공하기도 한다.
 
from tkinter import *
class MyApp:
    def __init__(self, parent):
        self.myParent=parent
        self.myContainer1=Frame(parent)
        self.myContainer1.pack()
        self.button1=Button(self.myContainer1, command=self.button1Click)
        self.button1.bind("<Return>",self.button1Click_a)
        self.button1.configure(text="OK", background="green")
        self.button1.pack(side=LEFT)
        self.button1.focus_force() #실행시 기본 초점을 button1에 맞춤
       
        self.button2=Button(self.myContainer1, command=self.button2Click)
        self.button2.bind("<Return>", self.button2Click_a)
        self.button2.configure(text="Cancel", background="red")
        self.button2.pack(side=RIGHT)
    def button1Click(self):
        print("button1Click event handler")
        if self.button1["background"]=="green":
            self.button1.configure(background="yellow")
        else:
            self.button1.configure(background="green")
       
    def button2Click(self):
        print("button2Click event handler")
        self.myParent.destroy()
       
    def button1Click_a(self,event):
        print("button1Click_a event handler (a wrapper)")
        self.button1Click()
    def button2Click_a(self,event):
        print("button2Click_a event handler (a wrapper)")
        self.button2Click()
root=Tk()
MyApp(root)
root.mainloop()
 
위 예제는 button1버튼창부품에 button1Click메서드를 명령어묶기로 묶은 후
 
<Return>키에 button1Click_a메서드를 사건묶기로 묶어 주었다.
 
따라서 클릭,엔터,스페이스는 모두 같은동작을 하지만, 엔터는 button1Click_a메서드를 통하여 button1Click메서드를 호출하는 형태이다.
 
 
위 예제를 통해 명령어묶기와 사건묶기의 차이를 알수있다.
 
명령어묶기는 버튼창부품에 미리 정해져있는 사건(클릭과 스페이스)에 사건처리자를 지정해주는것이고,
 
사건묶기는 원하는 사건에 원하는 사건처리자를 연결하여 창부품에 지정하는것이라고 할수 있다.
 
=== 정보 공유하기 ===
지난 예제들에서는 사건처리자에게 실제로 일을 시키는 방법들을 알아보았다.
 
아래 예제를 통하여 사건처리자 사이에 정보를 공유하는 법에 대하여 알아보도록 하겠다.
 
 
사건처리자에게 어떠한 일을 시키고 그 결과를 다른 사건처리자와 공유하고 싶은 다양한 상황이 있다.
 
일반적인 패턴은 어플리케이션에 두 세트의 창부품이 있다는것이다. 한 세트의 창부품은 일정한 정보를 만들고 선택하고,
 
다른 세트의 창부품은 그 정보를 가지고 일을 한다.
 
 
예를 들어 한 창부품에서 사용자는 파일리스트로부터 파일을 선택하고, 다른창부품들은 고른 그 파일에 대하여 다양한 연산을 할수 있다.
 
파일열기, 삭제, 복사, 이름바꾸기 등등
 
또는 한 세트의 창부품은 어플리케이션에 다양한 환경구성을 설정하고, 또다른 세트는 (Save와 Cancel옵션을 제공하는 버튼들)디스크에 그런 설정을 저장하거나 또는 저장하지 않고 버릴수 있게끔 하거나
 
한 세트의 창부품은 실행하고자 하는 프로그램에 대하여 매개변수들을 설정하고 또다른 창부품은(Run이나 Execute같은 이름을 가진 버튼들)그런 매개변수를 가지고 프로그램을 시작시킬수 있다.
 
또는 나중에 같은 함수를 호출할떄 정보를 건네기 위하여 사건처리자 함수를 요청할 필요가 있을수 있다.
 
그냥 두가지 다른 값으로 변수를 이리저리 바꾸는 사건처리자를 생각해보자 변수에 새로 값을 할당하려면, 사건처리자는 지난번 실행될때 그 변수에 어떤 값이 할당되었는지를 기억해야 한다.
 
 
여기에서 문제는 각 사건처리자가 별도의 함수라는 것이다. 각 사건처리자는 자신만의 지역변수가 있고, 이 변수들은 다른 사건처리자함수와 공유하지 않으며, 심지어 나중에 호출되는 자신과도 공유하지 않는다. 그래서 문제는 자신의 지역변수를 공유할수 없다면, 어떻게 사건처리자 함수가 다른 사건처리자와 데이터를 공유할수 있겠는가이다.
 
이해대한 해결책은 2가지가 있다.
 
 
해결책 첫번째, 전역변수 사용하기
 
첫번째 방법으로 공유하고자 하는 변수를 전역변수로 사용하는 방법이다.
 
예를들면, 각처리자에서 myValue1과 myValue2를 바꾸거나 볼 필요가 있다면 아래와 같은 행을 배치하면 된다.
 
global myValue1, myValue2
 
그러나 전역변수를 사용하는 것은 잠재적으로 위험요소가 있다.
 
또한 일반적으로 지저분한 프로그래밍이라고 눈총을 받는다.
 
 
해결책 두번째, 실체변수 사용하기
 
좀더 깔끔한 방법으로 "실체변수"(self변수)를 사용하여 사건처리자 사이에 공유할 정보를 유지하는 것이다.
 
물론 위방법을 사용하려면 어플리케이션이 클래스로 구현되어야 한다.
 
 
아래 예제에서 아주 단순한 정보를 기억하고 공유해보도록 하겠다.
 
요청된 마지막버튼의 이름을 self.myLastButtonInvoked라는 실체변수에 저장하도록 하겠다.
 
 
아래 예제는 버튼을 3개 보여준다. 이 프로그램을 실행하고, 버튼을 아무거나 클릭하면, 그 이름과 클릭되었던 앞의 버튼 이름이 화면에 나타난다.
 
from tkinter import *
class MyApp:
    def __init__(self, parent):
        self.myLastButtonInvoked=None #어떠한 버튼의 이름도 들어있지 않다.
        self.myParent=parent
        self.myContainer1=Frame(parent)
        self.myContainer1.pack()
        self.yellowButton=Button(self.myContainer1, command=self.yellowButtonClick)
        self.yellowButton.configure(text="YELLOW", background="yellow")
        self.yellowButton.pack(side=LEFT)
       
        self.redButton=Button(self.myContainer1, command=self.redButtonClick)
        self.redButton.configure(text="RED", background="red")
        self.redButton.pack(side=LEFT)
       
        self.whiteButton=Button(self.myContainer1, command=self.whiteButtonClick)
        self.whiteButton.configure(text="WHITE", background="white")
        self.whiteButton.pack(side=LEFT)
       
    def yellowButtonClick(self):
        print("YELLOW button clicked. Previous button invoked was", self.myLastButtonInvoked)
        self.myLastButtonInvoked="YELLOW"
   
    def redButtonClick(self):
        print("RED button clicked. Previous button invoked was", self.myLastButtonInvoked)
        self.myLastButtonInvoked="RED"
    def whiteButtonClick(self):
        print("white button clicked. Previous button invoked was", self.myLastButtonInvoked)
        self.myLastButtonInvoked="WHITE"
print("\n"*100) #화면 정리
print("Start...")
root=Tk()
MyApp(root)
root.mainloop()
print("Complete...")
 
=== 명령어 묶기 더 자세히 ===
명령어묶기에 대하여 좀더 고급특징을 알아보도록 하겠다.
 
이전 예제에서 명령어묶기는 "command"옵션을 사용하여 사건처리자를 창부품에 묶었다.
 
self.button1=Button(self.myContainer1, command=self.button1Click)
 
즉, button1창부품을 클릭하거나, 스페이스바로 누르면 command옵션으로 지정한 button1Click이라는 사건처리자가 동작하는것이다.
 
button2창부품 또한 같은 방식으로 button2Click이라는 사건처리자가 동작할것이다.
 
 
하지만 만약 위와 상황이 다르다고 가정해보자,
 
버튼이 여러개이고, 그 모든 버튼은 본질적으로 같은유형의 동작을 한다고 생각해보자,
 
각각의 버튼마다 사건처리자를 만들어 주는것보단
 
단 하나의 사건처리자를 지정하고, 버튼이 서로다른 인자를 건네주게끔 동작을 한다면 코드가 훨씬 간결해질것이다.
 
 
아래 예제는 명령어묶기를 할때 사건처리자에 인자를 지정해주었다.


Python,tkinter 창부품의 크기 및 여백 https://blog.naver.com/dudwo567890/130166669154
from tkinter import *
class MyApp:
    def __init__(self, parent):
        self.myParent=parent
        self.myContainer1=Frame(parent)
        self.myContainer1.pack()
       
        button_name="OK"
        self.button1=Button(self.myContainer1, command=self.buttonHandler(button_name, 1, "Good stuff!"))
        self.button1.configure(text=button_name, background="green")
        self.button1.pack(side=LEFT)
        self.button1.focus_force #실행시 기본초점 맞추기
       
        button_name="Cancel"
        self.button2=Button(self.myContainer1, command=self.buttonHandler(button_name, 2, "Bad stuff!"))
        self.button2.configure(text=button_name,background="red")
        self.button2.pack(side=LEFT)
       
    def buttonHandler(self, arg1, arg2, arg3):
        print("buttonHandler routine received arguments : ",arg1.ljust(8), arg2, arg3)
     
    def buttonHandler_a(self, event, arg1, arg2, arg3):
        print("buttonHandler_a received event", event)
        self.buttonHandler(arg1,arg2,arg3)
 
print("\n"*100) #화면 정리
print("Start...")
root=Tk()
myapp=MyApp(root)
print("어플리케이션 실행 준비")
root.mainloop()
print("어플리케이션 실행 완료")


Python,tkinter 틀(Frame)의 테두리 및 크기 지정 https://blog.naver.com/dudwo567890/130166928290
위 예제를 실행해보면


Python,tkinter 틀의 신축성[부품이 있을때와 없을때의 차이] https://blog.naver.com/dudwo567890/130166928697
10행과 16행에서 명령어묶기로 지정한 buttonHandler사건처리자가


Python,tkinter pack() [공간 다루기] https://blog.naver.com/dudwo567890/130167237607
어플리케이션이 실행되기도 전에 먼저 수행되어 화면에 문자열을 출력하는것을 알수 있다.
 
일단 위 예제를 실행하여 명령어묶기에 함수전달방법이 달라지는것에 따라 어떤 문제점이 생겼는지만 알아보고,
 
위 예제의 문제의 해결방법을 아래예제를 통해 알아보도록 하겠다.
 
=== 역호출 함수 ===
위 예제의 문제점을 살펴보면, 함수가 어플리케이션이 실행되기도 전에 ButtonHandler사건처리자가 실행된다는것이다.
 
그 이유는 바로 명령어묶기를 했던 방법때문이다.
 
self.button1=Button(self.myContainer1, command=self.buttonHandler(button_name, 1, "Good stuff!"))
 
의도한 바는 아니지만 역호출함수로 사용할 것이 무엇인지 요구하지 않고, buttonHandler함수를 직접 호출하고 있기 때문이다.
 
명령어묶기에서 함수를 지정한 방법의 차이를 설명해보면
>command=self.buttonHandler #함수객체
>command=self.buttnHandler() #함수호출
위는 명령어묶기에 함수객체를 지정해주는 것이고,
 
아래는 명령어묶기에 함수를 호출하여 함수의 Return값을 지정한것이다.
 
따라서 아래방법에 대하여 Return값이 None이 될경우,
 
command옵션은 None값에 묶이게 된다는것이다.
 
때문에 위 예제에서 버튼을 클릭하여도 아무런 동작을 하지 않게 되는것이다.
 
 
자 이제 이 문제에 대한 해결방법을 알아보자
 
일반적으로 해결방법은 두가지이다.
 
첫번째는 파이썬에 내장된 람다(lambda)함수를 사용하는 것이다.
 
다른 하나는 함수내포기법(currying)이라고 부른다.
 
 
아래 예제를 통해 람다(lambda)함수를 통한 해결방법을 보도록 하겠다.
 
from tkinter import *
class MyApp:
    def __init__(self, parent):
        self.myParent=parent
        self.myContainer1=Frame(parent)
        self.myContainer1.pack()
       
        #----- BUTTON #1 -----
        button_name="OK"
       
        #명령어 묶기
        self.button1=Button(self.myContainer1, command=lambda arg1=button_name, arg2=1, arg3="Good stuff!" : self.buttonHandler(arg1, arg2, arg3))
       
        #사건 묶기 -- 사건을 인자로 건넴
        self.button1.bind("<Return>", lambda event, arg1=button_name, arg2=1, arg3="Good stuff!" : self.buttonHandler_a(event, arg1, arg2, arg3))
       
        self.button1.configure(text=button_name, background="green")
        self.button1.pack(side=LEFT)
        self.button1.focus_force() #실행시 기본초점 맞추기
       
        #----- BUTTON #2 -----
        button_name="Cancel"
       
        #명령어 묶기
        self.button2=Button(self.myContainer1, command=lambda arg1=button_name,arg2=2,arg3="Bad stuff!" : self.buttonHandler(arg1, arg2, arg3))
       
        #사건 묶기 -- 사건을 인자로 건네지 않음
        self.button2.bind("<Return>", lambda event, arg1=button_name, arg2=2, arg3="Bad stuff!" : self.buttonHandler(arg1, arg2, arg3))
       
        self.button2.configure(text=button_name, background="red")
        self.button2.pack(side=LEFT)
       
    def buttonHandler(self, argument1, argument2, argument3):
        print("buttonHandler routine recived arguments:", argument1.ljust(8),argument2, argument3)
       
    def buttonHandler_a(self, event, argument1, argument2, argument3):
        print("buttonHandler_a received event", event)
        self.buttonHandler(argument1, argument2, argument3)
 
print("\n"*100) #화면정리
root=Tk()
myapp=MyApp(root)
print("어플리케이션 실행 준비")
root.mainloop()
print("어플리케이션 실행 완료")
 
 
OK버튼창부품 클릭
buttonHandler routine recived arguments: OK      1 Good stuff!
 
 
OK버튼창부품 스페이스키
buttonHandler routine recived arguments: OK      1 Good stuff!
 
 
OK버튼창부품 엔터키
buttonHandler_a received event <tkinter.Event object at 0x00D56BD0>
buttonHandler routine recived arguments: OK      1 Good stuff!
 
 
Cancel버튼창부품 클릭
buttonHandler routine recived arguments: Cancel  2 Bad stuff!
 
 
Cancel버튼창부품 스페이스키
buttonHandler routine recived arguments: Cancel  2 Bad stuff!
 
 
Cancel버튼창부품 엔터키
buttonHandler routine recived arguments: Cancel  2 Bad stuff!
 
 
위에서 볼수 있듯이 명령어묶기와 사건묶기에서, 사건처리자에 인자를 전달하는 방법을
 
람다(lambda)를 이용하여 인자를 전달함으로써 함수호출이 아닌 함수객체를 전달하였다.
 
=== 함수 내포 기법(currying) ===
앞의 예제에서 인자를 사건처리자(함수)에 건네기 위해 람다를 사용한 방법을 알아보았다.
 
이번 예제에서는 함수내포기법(currying)을 사용한 방법을 알아보도록 하겠다.
 
 
함수내포기법(Curry)이란?
 
가장 단순한 의미에서, 함수내포기법은 함수를 사용하여 다른 함수를 구성하는 방법이다.
 
자세한 내용은 아래URL에서 알수 있다.
 
https://aspn.activestate.com/ASPN/Python/Cookbook/
 
https://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52549
 
 
curry를 사용하는 방법은 "curry"클래스를 프로그램에 포함시키거나, 파이썬파일에서 import하는것이다.
 
아래 예제에서는 curry코드를 직접 프로그램에 포함시키도록 하겠다.
 
아래는 예제에서 사용했던 명령어묶기 방법이다.
 
self.button1=Button(self.myContainer1, command=self.buttonHandler(button_name, 1, "Good stuff!"))
 
이걸 curry를 사용하여, 아래와 같이 다시 작성하였다.
 
self.button1=Button(self.myContainer1, command=curry(self.buttonHandler, button_name, 1, "Good stuff!"))
 
curry클래스에 사건처리자와 인자를 전달하여 생성된 함수를 command옵션에 전달한것이다.
 
 
아래 예제에서 명령어묶기를 할때 여러가지 방법이 사용되었다.
 
일단 예제를 본후 설명하도록 하겠다.
 
from tkinter import *
# ----- code for class : curry(begin) -----
class curry:
    def __init__(self, fun, *args, **kwargs):
        self.fun=fun
        self.pending=args[:]
        self.kwargs=kwargs.copy()
       
    def __call__(self, *args, **kwargs):
        if kwargs and self.kwargs:
            kw=self.kwargs.copy()
            kw.update(kwargs)
        else:
            kw=kwargs or self.kwargs
        return self.fun(*(self.pending+args), **kw)
# ----- code for class : curry(end) -----
 
# ----- code for function : event_lambda(begin) -----
def event_lambda(f, *args, **kwds):
    return lambda event, f=f, args=args, kwds=kwds : f(*args, **kwds)
# ----- code for function : event_lamda(end) -----
 
class MyApp:
    def __init__(self, parent):
        self.myParent=parent
        self.myContainer1=Frame(parent)
        self.myContainer1.pack()
       
        # ----- BUTTON #1 -----
        button_name="OK"
       
        #명령어묶기 -- 함수내포기법 사용
        self.button1=Button(self.myContainer1, command=curry(self.buttonHandler, button_name, 1, "Good stuff!"))
       
        #사건묶기 -- event_lambda 함수 사용
        self.button1.bind("<Return>", event_lambda(self.buttonHandler, button_name, 1, "Good stuff!"))
     
        self.button1.configure(text=button_name, background="green")
        self.button1.pack(side=LEFT)
        self.button1.focus_force() #실행시 기본초점 맞추기
       
        # ----- BUTTON #2 -----
        button_name="Cancel"
       
        #명령어묶기 -- 함수내포기법 사용
        self.button2=Button(self.myContainer1, command=curry(self.buttonHandler, button_name, 2, "Bad stuff!"))
       
        #사건묶기 -- event_lambda 함수를 두 단계로 사용
        event_handler=event_lambda(self.buttonHandler, button_name, 2, "Bad stuff!")
        self.button2.bind("<Return>", event_handler)
       
        self.button2.configure(text=button_name, background="red")
        self.button2.pack(side=LEFT)
       
    def buttonHandler(self, argument1, argument2, argument3):
        print("buttonHandler routine received arguments:", argument1.ljust(8), argument2, argument3)
       
    def buttonHandler_a(self, event, argument1, argument2, argument3):
        print("buttonHandler_a received event", event)
        self.buttonHandler(argument1, argument2, argument3)
 
print("\n"*100) #화면정리
root=Tk()
myapp=MyApp(root)
print("어플리케이션 실행 준비")
root.mainloop()
print("어플리케이션 실행 완료")
 
위 예제를 실행해보면 각 OK버튼과 Cancel버튼에
 
클릭,엔터키,스페이스키에 대하여 같은 동작을 하는것을 알수 있다.
 
하지만 코드상으론 서로 다르게 buttonHandler함수를 호출하였다.
 
 
34행은 curry클래스를 이용하여 사건처리자객체를 생성한방법이고,
 
37행은 lambda객체를 생성하여 return해주는 event_lambda함수를 이용하여 사건묶기를 해주었고,
 
47행 역시 curry클래스를 이용하였고,
 
50행은 lambda객체를 이용하여 return해주는 값을 다시한번 event_handler이라는 변수에 집어넣은후
 
사용한 방법이다.
 
 
curry클래스와, event_lambda함수, buttonHandler함수, buttonHandler_a함수가 어떻게 동작하는지는 코드를 보면 알수 있으므로 따로 설명하지 않도록 하겠다.
 
 
lambda와 curry 그리고 event_lambda -- 어느것을 사용해야 하는가?
 
>curry와 event_lambda를 요청하는 코드는 상대적으로 직관적이며 짧고 간단하다.
 
단점은 이것들을 사용하기 위해서는 프로그램에 코드를 삽입해주어야 한다는것이다.
 
 
>대조적으로 lambda는 파이썬에 내장되어 있다. 반입하기 위해 특별히 해야 할것이 없다.
 
단점은 lambda를 사용하면 코드의 가독성이 떨어진다는 것이다.
 
 
자 선택은 사용자의 몫이다. 자기가 사용하기 편하고, 가장 친숙한것을 사용하자. 그리고 작업에 가장 적당하다고 여겨 지는것을 사용하자.
 
== GUI 계산기 만들기 ==
[[Tkinter]]를 이용한 [[그래피컬 사용자 인터페이스]] ([[GUI]]) 계산기의 [[파이썬]] ([[Python]]) [[쏘쓰 코드]] ([[source code]])이다.


= 계산기 =
https://www.daniweb.com/programming/software-development/code/467452/updated-tiny-tkinter-calculator-python


  <nowiki>''' tk_calculator_tiny2.py</nowiki>
  <nowiki>''' cal.py</nowiki>
  A updated tiny calculator using the Tkinter GUI toolkit
  A updated tiny calculator using the Tkinter GUI toolkit
  you can type in functions contained in module math
  you can type in functions contained in module math
  for instance type in  tan(pi/180)  then click  =
  for instance type in  tan(pi/180)  then click  =
  tested with Python27 and Python33  by  vegaseat  13nov2013
  tested with Python 3.7.5 on Ubuntu 19.10
  <nowiki>'''</nowiki>
  <nowiki>'''</nowiki>
# avoid integer division by Python2
from __future__ import division
  from math import *
  from math import *
  from functools import partial
  from functools import partial
Line 599: Line 1,758:
         # the root will be self
         # the root will be self
         tk.Tk.__init__(self)
         tk.Tk.__init__(self)
         self.title("Tiny TK Calculator")
         self.title("Darknet TK Calculator")
         # use width x height + x_offset + y_offset (no spaces!)
         # use width x height + x_offset + y_offset (no spaces!)
         #self.geometry("300x150+150+50")
         #self.geometry("300x150+150+50")
Line 620: Line 1,779:
             # partial takes care of function and argument
             # partial takes care of function and argument
             cmd = partial(self.calculate, b)
             cmd = partial(self.calculate, b)
             tk.Button(self, text=b, width=5, relief=rel,
             tk.Button(self, text=b, width=5, relief=rel, command=cmd).grid(row=r, column=c)
                command=cmd).grid(row=r, column=c)
             c += 1
             c += 1
             if c > 4:
             if c > 4:
Line 669: Line 1,827:
  app = MyApp()
  app = MyApp()
  app.mainloop()
  app.mainloop()
[[사칙연산]]이 가능한 [[GUI]] [[계산기]]이다. 키보드로 직접 입력하면 tan(pi/180) 등 [[사칙 연산]] 외의 계산도 가능하다.
[[우분투]] 19.10 기준으로, 파일 이름이 cal.py일 경우 [[파이썬]] 3.7.5에서는 [[터미널]]에서
sudo apt install python3-tk
python3 cal.py
[[명령어]]를 입력하면 실행된다.
http://uoxqi4lrfqztugili7zzgygibs4xstehf5hohtkpyqcoyryweypzkwid.onion/?img=361615491111.png
http://hostxvivwx3lzvfdnof2muv7q5fkcovkfa3nexlnl5zrelif2mawxkad.onion/image.php?di=631T
http://pdogfxf7k6lyqe7uhmrokpc74nk2td75m4al5t6uvfhdvvxvng3nazid.onion\/tnibabrS30.jpg
http://3b6clio4syptsnvvtzyxifqvtizyazgyowpp3v5f7dj3mzmfhyoy4iyd.onion/images/8f98719adf96e79c9647c790631c1c2e.png
=== 쏘쓰 코드 설명 ===
아래 링크는 [[쏘쓰 코드]] ([[source code]]) 출처이다.
* Updated Tiny Tkinter Calculator (Python)
Nov 13th, 2013 9:14 pm
https://www.daniweb.com/programming/software-development/code/467452/updated-tiny-tkinter-calculator-python
[[쏘스 코드]]에서 ' 나 " 3개로 싸인 부분은 [[주석]] ([[comment]])이다. 한 줄의 맨 앞에 #를 써놔도 주석이다. 자세한 설명은 [[파이썬]] 문서를 참조하라.
# avoid integer division by Python2
from __future__ import division
try:
    # Python2
    import Tkinter as tk
except ImportError:
    # Python3
    import tkinter as tk
등 [[파이썬]] 2를 위한 [[소스 코드]]는 삭제하거나 수정하였다. 왜냐하면 요즘에는 대부분의 사람들이 파이썬 3를 쓰기 때문이다.
* Python Language - Integer Division | python Tutorial
https://riptutorial.com/python/example/2797/integer-division
* Difference between tkinter and Tkinter
2013-07-24
https://stackoverflow.com/questions/17843596/difference-between-tkinter-and-tkinter
from math import *
from functools import partial
import tkinter as tk
functools에서 partial을 불러오라는 의미이다. *은 전부 불러오라는 의미이다. tkinter를 tk라는 이름으로 불러오라는 의미이다.
MyApp [[클래스]] ([[class]]) 아래에 def로 [[정의]] ([[definition]])된 3개의 [[함수]] ([[function]])가 있다. 참고로 [[선언]] ([[declaration]])은 정의와는 약간 다르다.
* C 언어 코딩 도장: 60.2 함수 선언과 정의 분리하기
https://dojang.io/mod/page/view.php?id=522
더 자새한 설명은 [[Tkinter]] 문서 참조.
== 트킨터로 게임 만들기 ==
* [파이썬 게임 프로그래밍 공부] 1. tkinter 모듈 시작하기
2017-09-01
https://alegruz.imweb.me/blog/?idx=221667&bmode=view
* [파이썬 게임 프로그래밍 공부] 2. 위젯에 간단한 오브젝트 생성하기
2017-09-01
https://alegruz.imweb.me/blog/?idx=221692&bmode=view
== 함께 보기 ==
* [[필독 사항]]
* [[다크넽]] ([[Darknet]])
* [[파이썬]] ([[Python]])
* [[파이게임]] ([[Pygame]])
* [[쏠쓰 코드]] ([[source code]], [[쏘쓰 코드]], [[쏘스 코드]], [[소스 코드]])
* [[오픈 쏠쓰]] ([[open source]], [[오픈 쏘쓰]], [[오픈 쏘스]], [[오픈 소스]])


[[Category:파이썬]]
[[Category:파이썬]]
[[Category:프로그래밍]]
[[Category:프로그래밍]]
5

edits

Navigation menu