Python3x GUI with Tkinter

python3を使って色々試してみたいと思い<a href="https://www.youtube.com/playlist?list=PL6gx4Cwl9DGBwibXFtPtflztSNPGuIB_d" target="_blank">このシリーズ全て</a>を参考に簡単なウィンドウを作ってみようと思う。チュートリアルの動画が全部で15個分あるので少し長いですが。

#目次
- <a href="#きほんのき">きほんのき</a>
- <a href="#オブジェクトのレイアウトをいじる">オブジェクトのレイアウトをいじる</a>
- <a href="#レイアウトにウィジェットを追加する">レイアウトにウィジェットを追加する</a>
- <a href="#より直感的にウィジェット整理">より直感的にウィジェット整理</a>
- <a href="#関数を使ってレイアウトをより便利に">関数を使ってレイアウトをより便利に</a>
- <a href="#複数のウィジェットをウィンドウに追加する">複数のウィジェットをウィンドウに追加する</a>
- <a href="#クラスを使って簡易プログラムを作る">クラスを使って簡易プログラムを作る</a>
- <a href="#ドロップダウンメニューを追加する">ドロップダウンメニューを追加する</a>
- <a href="#ツールバーを追加する">ツールバーを追加する</a>
- <a href="#ステータスバーを追加する">ステータスバーを追加する</a>
- <a href="#メッセージボックスを追加する">メッセージボックスを追加する</a>
- <a href="#シンプルな図式などを追加する">シンプルな図式などを追加する</a>
- <a href="#画像やアイコンの追加">画像やアイコンの追加</a>

##きほんのき

###GUIとは
GUIと言うとUIとかCUIとかっていう単語が出てくるかもしれない。そこら辺の違いも上手く理解していなかったのでお互いの違いも含めて調べてみた。まずGUIとはGraphical User Interfaceの略でwindowsやmacに関係なく普段自分たちがいわゆるホームスクリーンを通じて直感的に行っている操作のほとんどがGUIのおかげと言っても過言ではない。それまではCUI（Character User Interface）と呼ばれるいわゆるTerminalを通じてだけでパソコンとのコミュニケーションを図っていた。具体的には直感的な操作を得意としたGUIとは反対に位置しているのがより複雑な処理を得意としたCUIといったところでしょうか。技術的なものはぐぐってみるとよりいいと思います。

###一般的な流れ
1. フレームとなるウィンドウを作る
2. `label()`を使ってメッセージをディスプレイに送るための材料を用意
3. `pack()`で実際に`root`ウィンドウに表示するよう指示している
4. `mainloop`でウィンドウを継続的に開いている。閉じることで`loop`を`break`する

*ちなみに`tkinter`でプログラムを作る場合は`x = Tk()`と`x.mainloop()`の2つは必須。

```
from tkinter import *

root = Tk() #create a blank window by initiating TK()
theLabel = Label(root, text="this is too easy") #Label(where, text="")
theLabel.pack() #just pack it in the first place you can fit it
root.mainloop()
\# you need to continuously run the screen with GUI
\# w/out mainloop, the window will eventually disappear
\# it keeps displaying the window until user manually closes it
```

###アウトプット

![Screen Shot 2016-01-17 at 7.35.25 PM.png](https://qiita-image-store.s3.amazonaws.com/0/87666/19a5c17f-b382-9da9-9e80-e7aa14672cf5.png)


##オブジェクトのレイアウトをいじる

###frameという概念
`frame`とは簡単にいえば透明の四角形型のレイアウトと考えてもらえればいい。`tkinter`においてプログラムのレイアウトを考えるとき、この考え方が役に立つとか。そこで実際に`frame`という概念を頭に入れながら#2ではtopbottomrightleftを使ってみる。基本的な操作は普段通り`obejct`を作って`pack()`でディスプレイに表示させるという2セットになっている。

```
from tkinter import *

root = Tk()
topFrame = Frame(root) 
# top is set by default therefore no parameter needed. you can explicitly say it too
# create a empty container in the main screen. 
# !!!NOTE!!! its just in its program not displayed yet
topFrame.pack() # place it somewhere in the main program
bottomFrame = Frame(root)
bottomFrame.pack(side=BOTTOM) 
# specify the given location by passing a parameter

button1 = Button(topFrame, text="Button 1", fg="red")
#Button(where, text="", fg="colour(optional)")
button2 = Button(topFrame, text="Button 2", fg="blue")
button3 = Button(topFrame, text="Button 3", fg="green")
button4 = Button(bottomFrame, text="Button 4", fg="purple")

button1.pack(side=LEFT)
button2.pack(side=LEFT)
button3.pack(side=LEFT)
# places bottum on the left of each other side by side 
button4.pack(side=BOTTOM)

root.mainloop()
```

###アウトプット

![Screen Shot 2016-01-17 at 7.33.36 PM.png](https://qiita-image-store.s3.amazonaws.com/0/87666/735142dc-b12c-d386-234e-aacb2b791a8a.png)


##レイアウトにウィジェットを追加する



```
from tkinter import *

root = Tk()
one = Label(root, text="One", bg="red", fg="white")
one.pack()
two = Label(root, text="Two", bg="green", fg="black")
two.pack(fill=X) # make widget responsive
three = Label(root, text="Two", bg="blue", fg="white")
three.pack(side=LEFT, fill=Y)

root.mainloop()
```

`fill=X`で横の大きさに合わせてレスポンシブに。`fill=Y`で縦の大きさに合わせてレスポンシブになる。

###アウトプット

![Screen Shot 2016-01-17 at 7.31.52 PM.png](https://qiita-image-store.s3.amazonaws.com/0/87666/39746740-089e-02ce-567e-3b78efc1ae70.png)

##より直感的にウィジェット整理
Grid Layoutというやり方を使えばエクセルの行と列を扱う感覚でウィジェットをいじることが出来る。読んだだけでオブジェクトがどこにあるか大体分かるので便利。

やり方は非常に簡単で表示させたいものを`item.pack()`の代わりに`item.grid()`とする。`grid()`の引数は`row = x, column = x`だが`column`はデフォルトで0になっているので0でいいならば入力する必要はない。

```
from tkinter import *

root = Tk()

label_1 = Label(root, text="Name")
label_2 = Label(root, text="Password")
entry_1 = Entry(root) # Entry = input field
entry_2 = Entry(root)

label_1.grid(row=0)
label_2.grid(row=1)

entry_1.grid(row=0, column=1)
entry_2.grid(row=1, column=1)

root.mainloop()
```

###アウトプット

![Screen Shot 2016-01-19 at 1.07.49 PM.png](https://qiita-image-store.s3.amazonaws.com/0/87666/50cd3e3e-53db-ca0d-79d9-b981bb745f76.png)

###`grid()`を使って文字を揃える
もし「アウトプットで出したフォームの`Name`と`Password`の文字を右に揃えたい」なんて思った場合は`grid()`の引数を`row`と`column`に加えて`sticky`という引数を加える。`sticky`に対応する値は全て英語の東西南北の頭文字を取っている。右ならE、左ならW、上はNで下はS。

####アウトプット

![Screen Shot 2016-01-19 at 4.31.08 PM.png](https://qiita-image-store.s3.amazonaws.com/0/87666/66ca80ed-18dc-f165-44dc-09899325fef3.png)

###ウィンドウにチェックボックスを追加

`c = Checkbutton(root, text="Keep me logged in")`で追加できる。`c.grid(columnspan=2)`で表示させると綺麗に映る。`columnspan`を使えばテキストを2つのセルをくっつけて中央表示させる。

##関数を使ってレイアウトをより便利に

例えば「ウィンドウ上にボタンを作ってそれを押したら何かを起動させたい」みたいなことをしたい、とする。

```
from tkinter import *

root = Tk()

def printName():
	print("Chello my name is your mom!")

button_1 = Button(root, text="Print my name", command=printName)
# what command is bound to shoud be func to be called when the button is clicked
button_1.pack()

root.mainloop()
```

###アウトプット

![Screen Shot 2016-01-19 at 4.45.15 PM.png](https://qiita-image-store.s3.amazonaws.com/0/87666/0158147e-6214-1823-3682-2f523986b90c.png)

ボタンを押した回数分だけ`Chello my name is your mom!`がターミナル上に表示される。

###別の方法
敢えて関数内で引数といて`event`を作って`item.bind("item_name", func_name)`で呼んであげれば別のやり方でも追加できる。

```
from tkinter import *

root = Tk()

def printName(event):
	print("Chello my name is your mom!")

button_1 = Button(root, text="Print my name")
button_1.bind("<button-1>", printName)
# 1. what event, #2 what func to call when the event occurs
button_1.pack()

root.mainloop()
```

##複数のウィジェットをウィンドウに追加する

```
from tkinter import *

root = Tk()

def leftClick(event):
	print("Left")

def middleClick(event):
	print("Middle")

def rightClick(event):
	print("Right")

frame = Frame(root, width=300, height=250)
frame.bind("<Button-1>", leftClick) 
frame.bind("<Button-1>", middleClick)
frame.bind("<Button-1>", rightClick)

root.mainloop()
```

##クラスを使って簡易プログラムを作る

ボタンを押すとターミナル上にメッセージが表示され、閉じることも可能な簡易ウィンドウを作る。大まかな流れは`python3x`でクラスを作りそこに`print`と`quit`の役割を持った関数を入れるだけ。クラスは<a href="https://www.youtube.com/watch?v=POQIIKb1BZA" target="_blank">この辺</a>でサクッと学習できる。

```
from tkinter import *


# rule: whenever you make a class, you need two blank lines above it
class Buttons:
	def __init__(self, master):
		frame = Frame(master) # create a frame in the main window
		frame.pack()

		self.printButton = Button(frame, text="Print Message", command=self.printMessage)
		# command + function to call when the button is clicked
		self.printButton.pack(side=LEFT)

		self.quitButton = Button(frame, text="Quit", command=frame.quit)
		# quit breaks the loop
		self.quitButton.pack(side=LEFT)

	def printMessage(self):
		print("Wow, this actually worked!")

root = Tk()
b = Buttons(root)
root.mainloop() 
```

###アウトプット

![Screen Shot 2016-01-19 at 11.12.33 PM.png](https://qiita-image-store.s3.amazonaws.com/0/87666/a6787a94-477a-7dda-c4b4-7823467fbc3c.png)

`Print Message`を押すと押した回数分だけターミナル上に`Wow, this actually worked!`と表示されるようになっている。`Quit`を押すと`root.mainloop`を`break`するためウィンドウが閉じる。

##ドロップダウンメニューを追加する
ウィンドウを開いた時に上のウィンドウからドロップダウンメニューを出せるようにする。`html`、`css`のような感覚でパーツを足していく。

```
from tkinter import *


def doNothing():
	print("ok ok I won't...")

# root window below	
root = Tk()

menu = Menu(root)
root.config(menu=menu)
# to make sure tkinter recognizes it as menu
# parameter menu, and the name that you just defined

subMenu = Menu(menu)
menu.add_cascade(label="File", menu=subMenu)
# cascade=dropdown, label=option
subMenu.add_command(label="Now Project...", command=doNothing)
subMenu.add_command(label="New...", command=doNothing)
subMenu.add_separator() 
# a line to separates an item from one group from another
subMenu.add_command(label="Exit", command=doNothing)

editMenu = Menu(menu)
menu.add_cascade(label="Edit", menu=editMenu)
editMenu.add_command(label="Redo", command=doNothing)

root.mainloop()
```

###アウトプット

![Screen Shot 2016-01-19 at 11.37.18 PM.png](https://qiita-image-store.s3.amazonaws.com/0/87666/f15e4804-a70a-137d-8c89-04c34591930f.png)

![Screen Shot 2016-01-19 at 11.39.14 PM.png](https://qiita-image-store.s3.amazonaws.com/0/87666/643f2cb8-13d1-b996-63f6-6743c918bd85.png)

![Screen Shot 2016-01-19 at 11.39.22 PM.png](https://qiita-image-store.s3.amazonaws.com/0/87666/d23217b4-b416-54c2-9fbe-3b8fa38874cd.png)

##ツールバーを追加する
初めに`toolbar`という名の`frame`を作ってその箱にどんどん必要な物を足していく感じ。

```
from tkinter import *


def doNothing():
	print("ok ok I won't...")

# root window below	
root = Tk()

# ***** Main Menu *****

menu = Menu(root)
root.config(menu=menu)
# to make sure tkinter recognizes it as menu
# parameter menu, and the name that you just defined

subMenu = Menu(menu)
menu.add_cascade(label="File", menu=subMenu)
# cascade=dropdown, label=option
subMenu.add_command(label="Now Project...", command=doNothing)
subMenu.add_command(label="New...", command=doNothing)
subMenu.add_separator() 
# a line to separates an item from one group from another
subMenu.add_command(label="Exit", command=doNothing)

editMenu = Menu(menu)
menu.add_cascade(label="Edit", menu=editMenu)
editMenu.add_command(label="Redo", command=doNothing)

# *****Toolbar *****

toolbar = Frame(root, bg="blue")

insertButt = Button(toolbar, text="Insert Image", command=doNothing)
insertButt.pack(side=LEFT, padx=2, pady=2)
printButt = Button(toolbar, text="Print", command=doNothing)
printButt.pack(side=LEFT, padx=2, pady=2)

toolbar.pack(side=TOP, fill=X)
# side=TOP allows it to place it right underneath it
# fill makes it resposive in x direction

root.mainloop()
```

###アウトプット

![Screen Shot 2016-01-19 at 11.59.56 PM.png](https://qiita-image-store.s3.amazonaws.com/0/87666/c49aea24-654e-f4b7-eb1c-d04576a55e62.png)


##ステータスバーを追加する
あらゆるアプリケーションなどで良く見かける下の方にあるステータスバーを追加する。やり方はツールバーとそこまで変わらない。

```
# ***** Status Bar *****
status = Label(root, text="Preparing to do nothing...", bd=1, relief=SUNKEN, anchor=W)
# bd=border, relief to make it look like a status bar, want anchor to be left
status.pack(side=BOTTOM, fill=X)
```

###アウトプット

![Screen Shot 2016-01-20 at 12.09.13 AM.png](https://qiita-image-store.s3.amazonaws.com/0/87666/c5549eae-2d67-c096-3cd8-00ba0402ad81.png)

##メッセージボックスを追加する

```
from tkinter import *
import tkinter.messagebox

root = Tk()

tkinter.messagebox.showinfo('Window Title', 'Monkeys can live up to 300 years.')
# Window Title be the top bar of the window

answer = tkinter.messagebox.askquestion('Question 1', 'Do you like silly faces?')
# yes or no question ONLY

if answer == 'yes':
	print(' 8=======D~ ')

root.mainloop()
```

###アウトプット

![Screen Shot 2016-01-20 at 12.16.42 AM.png](https://qiita-image-store.s3.amazonaws.com/0/87666/e156dd30-32ea-2f09-ee22-01b6c2e18361.png)

![Screen Shot 2016-01-20 at 12.22.14 AM.png](https://qiita-image-store.s3.amazonaws.com/0/87666/8648ae88-6de9-d9a4-7dc0-95f72e5429b2.png)

##シンプルな図式などを追加する

###線を追加する

まずは `x = Canvas(where, size)`キャンバスを用意する。そこに`x.create_action`という形で材料をキャンパスの上に足していくイメージ。何を書くにしてもデフォルトは黒色ということを忘れずに。つまり`blackline = canvas.create_line(0, 0, 200, 50)`は黒になり、`redline = canvas.create_line(0, 100, 200, 50, fill=red)
`は赤になるということ。線も黒以外にしたい場合は`fill=colour`で指定してあげないといけない。

###簡単な図式を追加する

`greenBox = canvas.create_rectangle(top-left, height)`で追加可能。詳しくは[この辺](http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/create_rectangle.html)を参考に。

###アウトプット

![1Screen Shot 2016-01-20 at 3.13.48 PM.png](https://qiita-image-store.s3.amazonaws.com/0/87666/19448c90-247a-e6d4-9633-0cbd1a172efe.png)

###図式の表示、非表示

アプリケーションによっては最初から図式を表示させないでユーザーに表示させたり様々なパターンがある。そんなときも図式を`x.delete(item_to_delete)`を使うだけで非表示にさせることが可能。`x.delete(ALL)`で引数をまとめて渡すことも出来る。

##画像やアイコンの追加

最初に画像を変数に入れておき、それを`label`の引数として渡して`label.pack()`で表示させるという何とも変わった表示のさせ方。