์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐ŸŽจ ํŒŒ์ด์ฌ GUI ํ”„๋กœ๊ทธ๋ž˜๋ฐ: Tkinter ์‚ฌ์šฉ๋ฒ•

๐ŸŽจ ํŒŒ์ด์ฌ GUI ํ”„๋กœ๊ทธ๋ž˜๋ฐ: Tkinter ์‚ฌ์šฉ๋ฒ•

์นœ๊ตฌ์ฒ˜๋Ÿผ ์‰ฝ๊ณ  ์žฌ๋ฏธ์žˆ๊ฒŒ ๋ฐฐ์šฐ๋Š” GUI ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ์„ธ๊ณ„! ๐Ÿš€

์•ˆ๋…•! ๐Ÿ‘‹ ์˜ค๋Š˜์€ ํŒŒ์ด์ฌ์œผ๋กœ ๋ฉ‹์ง„ ์ฐฝ(์œˆ๋„์šฐ)์„ ๋งŒ๋“ค์–ด๋ณด๋Š” ์‹œ๊ฐ„์ด์•ผ. ์ปค๋งจ๋“œ ๋ผ์ธ์—์„œ ๋ฒ—์–ด๋‚˜ ๋ฒ„ํŠผ๋„ ๋ˆ„๋ฅด๊ณ , ํ…์ŠคํŠธ๋„ ์ž…๋ ฅ๋ฐ›๊ณ , ์ด๋ฏธ์ง€๋„ ๋ณด์—ฌ์ฃผ๋Š” ๊ทธ๋Ÿฐ ํ”„๋กœ๊ทธ๋žจ ๋ง์ด์•ผ. ๋ฐ”๋กœ **Tkinter**๋ฅผ ์‚ฌ์šฉํ•ด์„œ!

Tkinter๋Š” ํŒŒ์ด์ฌ์— ๊ธฐ๋ณธ์œผ๋กœ ๋‚ด์žฅ๋˜์–ด ์žˆ์–ด์„œ ๋ณ„๋„ ์„ค์น˜ ์—†์ด ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” GUI ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์•ผ. ๐ŸŽ ์ฒ˜์Œ GUI ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ๋ฐฐ์šฐ๋Š” ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ์ •๋ง ์ข‹์€ ์„ ํƒ์ด์ง€. ๋ณต์žกํ•˜์ง€ ์•Š์œผ๋ฉด์„œ๋„ ์‹ค์šฉ์ ์ธ ํ”„๋กœ๊ทธ๋žจ์„ ์ถฉ๋ถ„ํžˆ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ฑฐ๋“ !

Tkinter Window Button 1 Button 2 Enter your text here... Submit Cancel

๐ŸŒŸ Tkinter๊ฐ€ ๋ญ๊ธธ๋ž˜?

Tkinter๋Š” **Tk interface**์˜ ์ค„์ž„๋ง์ด์•ผ. Tk๋Š” ์›๋ž˜ Tcl์ด๋ผ๋Š” ์Šคํฌ๋ฆฝํŒ… ์–ธ์–ด์šฉ์œผ๋กœ ๋งŒ๋“ค์–ด์ง„ GUI ํˆดํ‚ท์ธ๋ฐ, ํŒŒ์ด์ฌ์—์„œ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“  ๊ฒŒ ๋ฐ”๋กœ Tkinter์ง€! ๐Ÿ“ฆ

๐Ÿ’ก Tkinter์˜ ์žฅ์ 

โœ… ํŒŒ์ด์ฌ ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ํฌํ•จ (๋ณ„๋„ ์„ค์น˜ ๋ถˆํ•„์š”)
โœ… ํฌ๋กœ์Šค ํ”Œ๋žซํผ ์ง€์› (Windows, macOS, Linux ๋ชจ๋‘ OK)
โœ… ๋ฐฐ์šฐ๊ธฐ ์‰ฌ์šด ๋ฌธ๋ฒ•๊ณผ ๊ตฌ์กฐ
โœ… ๊ฐ€๋ณ๊ณ  ๋น ๋ฅธ ์‹คํ–‰ ์†๋„
โœ… ํ’๋ถ€ํ•œ ์œ„์ ฏ(๋ฒ„ํŠผ, ๋ ˆ์ด๋ธ”, ์ž…๋ ฅ์ฐฝ ๋“ฑ) ์ œ๊ณต

๋ฌผ๋ก  ์ตœ์‹  ํŠธ๋ Œ๋””ํ•œ ๋””์ž์ธ์„ ์›ํ•œ๋‹ค๋ฉด PyQt๋‚˜ Kivy ๊ฐ™์€ ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋„ ์žˆ์–ด. ํ•˜์ง€๋งŒ ๊ฐ„๋‹จํ•œ ๋„๊ตฌ๋‚˜ ์œ ํ‹ธ๋ฆฌํ‹ฐ๋ฅผ ๋งŒ๋“ค ๋•Œ๋Š” Tkinter๊ฐ€ ์ •๋ง ์ตœ๊ณ ์•ผ! ๐Ÿ†

๐Ÿš€ ์ฒซ ๋ฒˆ์งธ Tkinter ํ”„๋กœ๊ทธ๋žจ ๋งŒ๋“ค๊ธฐ

์ž, ์ด์ œ ๋ณธ๊ฒฉ์ ์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด๋ณผ๊นŒ? ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ์ฐฝ์„ ๋„์šฐ๋Š” ๊ฒƒ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด๋ณด์ž!

import tkinter as tk

# ๋ฉ”์ธ ์œˆ๋„์šฐ ์ƒ์„ฑ
root = tk.Tk()
root.title("๋‚˜์˜ ์ฒซ GUI ํ”„๋กœ๊ทธ๋žจ")
root.geometry("400x300")

# ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰
root.mainloop()

์ด ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด 400x300 ํฌ๊ธฐ์˜ ๋นˆ ์ฐฝ์ด ํ•˜๋‚˜ ๋œฌ๋‹ค! ๐ŸŽ‰ ๊ฐ„๋‹จํ•˜์ง€? ํ•˜๋‚˜์”ฉ ๋œฏ์–ด๋ณด์ž.

๐Ÿ“Œ ์ฝ”๋“œ ๋ถ„์„

import tkinter as tk
Tkinter ๋ชจ๋“ˆ์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๊ฑฐ์•ผ. ๋ณดํ†ต tk๋ผ๋Š” ์งง์€ ์ด๋ฆ„์œผ๋กœ ์‚ฌ์šฉํ•ด. ํƒ€์ดํ•‘์ด ํŽธํ•˜๊ฑฐ๋“ !

root = tk.Tk()
๋ฉ”์ธ ์œˆ๋„์šฐ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ถ€๋ถ„์ด์•ผ. ๋ชจ๋“  GUI ์š”์†Œ๋“ค์˜ ๋ถ€๋ชจ๊ฐ€ ๋˜๋Š” ์ตœ์ƒ์œ„ ์ฐฝ์ด์ง€. ๋ณดํ†ต root๋‚˜ window๋ผ๋Š” ์ด๋ฆ„์„ ๋งŽ์ด ์จ.

root.title("...")
์ฐฝ์˜ ์ œ๋ชฉ์„ ์„ค์ •ํ•˜๋Š” ๋ฉ”์„œ๋“œ์•ผ. ์ฐฝ ์ƒ๋‹จ์— ํ‘œ์‹œ๋˜๋Š” ๊ทธ ํ…์ŠคํŠธ!

root.geometry("400x300")
์ฐฝ์˜ ํฌ๊ธฐ๋ฅผ ์„ค์ •ํ•ด. "๊ฐ€๋กœx์„ธ๋กœ" ํ˜•์‹์œผ๋กœ ํ”ฝ์…€ ๋‹จ์œ„๋กœ ์ง€์ •ํ•˜๋ฉด ๋ผ.

root.mainloop()
์ด๊ฒŒ ์ •๋ง ์ค‘์š”ํ•ด! ์ด ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜์–ด์•ผ ์ฐฝ์ด ํ™”๋ฉด์— ํ‘œ์‹œ๋˜๊ณ , ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ์„ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์ด๋ฒคํŠธ ๋ฃจํ”„๊ฐ€ ์‹œ์ž‘๋ผ. ์ด๊ฒŒ ์—†์œผ๋ฉด ์ฐฝ์ด ์ˆœ์‹๊ฐ„์— ์‚ฌ๋ผ์ ธ๋ฒ„๋ ค! ๐Ÿ˜ฑ

๐ŸŽจ ์œ„์ ฏ(Widget) ์ถ”๊ฐ€ํ•˜๊ธฐ

๋นˆ ์ฐฝ๋งŒ ์žˆ์œผ๋ฉด ๋ญํ•ด? ์ด์ œ ๋ฒ„ํŠผ, ๋ ˆ์ด๋ธ”, ์ž…๋ ฅ์ฐฝ ๊ฐ™์€ ๊ฒƒ๋“ค์„ ์ถ”๊ฐ€ํ•ด๋ณด์ž! ์ด๋Ÿฐ GUI ์š”์†Œ๋“ค์„ **์œ„์ ฏ(Widget)**์ด๋ผ๊ณ  ๋ถˆ๋Ÿฌ. ๐Ÿงฉ

๐Ÿ“ Label - ํ…์ŠคํŠธ ํ‘œ์‹œํ•˜๊ธฐ

Label์€ ํ™”๋ฉด์— ํ…์ŠคํŠธ๋‚˜ ์ด๋ฏธ์ง€๋ฅผ ํ‘œ์‹œํ•˜๋Š” ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ์œ„์ ฏ์ด์•ผ.

import tkinter as tk

root = tk.Tk()
root.title("Label ์˜ˆ์ œ")
root.geometry("400x300")

# Label ์ƒ์„ฑ
label = tk.Label(root, text="์•ˆ๋…•ํ•˜์„ธ์š”! ๐Ÿ‘‹", font=("Arial", 20))
label.pack(pady=20)

root.mainloop()

pack() ๋ฉ”์„œ๋“œ๋Š” ์œ„์ ฏ์„ ์ฐฝ์— ๋ฐฐ์น˜ํ•˜๋Š” ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜์•ผ. pady=20์€ ์œ„์•„๋ž˜๋กœ 20ํ”ฝ์…€์˜ ์—ฌ๋ฐฑ์„ ์ค€๋‹ค๋Š” ๋œป์ด์ง€!

๐Ÿ”˜ Button - ํด๋ฆญํ•  ์ˆ˜ ์žˆ๋Š” ๋ฒ„ํŠผ

๋ฒ„ํŠผ์€ ์‚ฌ์šฉ์ž๊ฐ€ ํด๋ฆญํ•ด์„œ ์–ด๋–ค ๋™์ž‘์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ์œ„์ ฏ์ด์•ผ.

import tkinter as tk

def button_click():
    print("๋ฒ„ํŠผ์ด ํด๋ฆญ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!")
    label.config(text="๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์–ด์š”! ๐ŸŽ‰")

root = tk.Tk()
root.title("Button ์˜ˆ์ œ")
root.geometry("400x300")

label = tk.Label(root, text="๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ๋ณด์„ธ์š”", font=("Arial", 16))
label.pack(pady=20)

button = tk.Button(root, text="ํด๋ฆญ!", command=button_click, 
                   bg="#7c9cbf", fg="white", font=("Arial", 14))
button.pack()

root.mainloop()

๐Ÿ’ก ํ•ต์‹ฌ ํฌ์ธํŠธ

command ๋งค๊ฐœ๋ณ€์ˆ˜์— ํ•จ์ˆ˜๋ฅผ ์ง€์ •ํ•˜๋ฉด, ๋ฒ„ํŠผ์„ ํด๋ฆญํ–ˆ์„ ๋•Œ ๊ทธ ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋ผ! ์ฃผ์˜ํ•  ์ ์€ ํ•จ์ˆ˜ ์ด๋ฆ„๋งŒ ์“ฐ๊ณ  ๊ด„ํ˜ธ ()๋Š” ๋ถ™์ด์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฑฐ์•ผ. command=button_click()์ด ์•„๋‹ˆ๋ผ command=button_click์œผ๋กœ ์จ์•ผ ํ•ด!

โœ๏ธ Entry - ํ…์ŠคํŠธ ์ž…๋ ฅ๋ฐ›๊ธฐ

Entry๋Š” ์‚ฌ์šฉ์ž๋กœ๋ถ€ํ„ฐ ํ•œ ์ค„์˜ ํ…์ŠคํŠธ๋ฅผ ์ž…๋ ฅ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” ์œ„์ ฏ์ด์•ผ.

import tkinter as tk

def show_input():
    user_text = entry.get()
    label.config(text=f"์ž…๋ ฅํ•œ ๋‚ด์šฉ: {user_text}")

root = tk.Tk()
root.title("Entry ์˜ˆ์ œ")
root.geometry("400x300")

label = tk.Label(root, text="์ด๋ฆ„์„ ์ž…๋ ฅํ•˜์„ธ์š”", font=("Arial", 14))
label.pack(pady=10)

entry = tk.Entry(root, width=30, font=("Arial", 12))
entry.pack(pady=10)

button = tk.Button(root, text="ํ™•์ธ", command=show_input)
button.pack(pady=10)

root.mainloop()

entry.get() ๋ฉ”์„œ๋“œ๋กœ ์ž…๋ ฅ๋œ ํ…์ŠคํŠธ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์–ด! ๐Ÿ“ฅ

๐Ÿ“ ๋ ˆ์ด์•„์›ƒ ๊ด€๋ฆฌ์ž (Layout Managers)

์œ„์ ฏ์„ ์ฐฝ์— ๋ฐฐ์น˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์—๋Š” ์„ธ ๊ฐ€์ง€๊ฐ€ ์žˆ์–ด. ๊ฐ๊ฐ ํŠน์ง•์ด ๋‹ค๋ฅด๋‹ˆ๊นŒ ์ƒํ™ฉ์— ๋งž๊ฒŒ ์„ ํƒํ•˜๋ฉด ๋ผ!

pack() Widget 1 Widget 2 Widget 3 ์ˆœ์ฐจ์  ๋ฐฐ์น˜ grid() (0,0) (0,1) (1,0) (1,1) ๊ฒฉ์ž ํ˜•ํƒœ ๋ฐฐ์น˜ (ํ–‰, ์—ด) place() x=40, y=100 x=170, y=170 x=90, y=240 ์ ˆ๋Œ€ ์ขŒํ‘œ ๋ฐฐ์น˜

1๏ธโƒฃ pack() - ์ˆœ์ฐจ์  ๋ฐฐ์น˜

๊ฐ€์žฅ ๊ฐ„๋‹จํ•œ ๋ฐฉ๋ฒ•์ด์•ผ. ์œ„์ ฏ์„ ์œ„์—์„œ ์•„๋ž˜๋กœ, ๋˜๋Š” ์™ผ์ชฝ์—์„œ ์˜ค๋ฅธ์ชฝ์œผ๋กœ ์ˆœ์ฐจ์ ์œผ๋กœ ๋ฐฐ์น˜ํ•ด.

import tkinter as tk

root = tk.Tk()
root.title("pack() ์˜ˆ์ œ")
root.geometry("300x200")

tk.Label(root, text="์ฒซ ๋ฒˆ์งธ", bg="#7c9cbf", fg="white").pack(fill=tk.X, padx=10, pady=5)
tk.Label(root, text="๋‘ ๋ฒˆ์งธ", bg="#66bb6a", fg="white").pack(fill=tk.X, padx=10, pady=5)
tk.Label(root, text="์„ธ ๋ฒˆ์งธ", bg="#ffa726", fg="white").pack(fill=tk.X, padx=10, pady=5)

root.mainloop()

์ฃผ์š” ์˜ต์…˜๋“ค:

โ€ข side: TOP(๊ธฐ๋ณธ), BOTTOM, LEFT, RIGHT - ๋ฐฐ์น˜ ๋ฐฉํ–ฅ
โ€ข fill: X, Y, BOTH - ๊ณต๊ฐ„ ์ฑ„์šฐ๊ธฐ
โ€ข expand: True/False - ๋‚จ์€ ๊ณต๊ฐ„ ํ™•์žฅ
โ€ข padx, pady: ์™ธ๋ถ€ ์—ฌ๋ฐฑ
โ€ข ipadx, ipady: ๋‚ด๋ถ€ ์—ฌ๋ฐฑ

2๏ธโƒฃ grid() - ๊ฒฉ์ž ํ˜•ํƒœ ๋ฐฐ์น˜

ํ‘œ ํ˜•ํƒœ๋กœ ์œ„์ ฏ์„ ๋ฐฐ์น˜ํ•  ๋•Œ ์ •๋ง ์œ ์šฉํ•ด! ํ–‰(row)๊ณผ ์—ด(column)์„ ์ง€์ •ํ•ด์„œ ์ •ํ™•ํ•œ ์œ„์น˜์— ๋ฐฐ์น˜ํ•  ์ˆ˜ ์žˆ์–ด.

import tkinter as tk

root = tk.Tk()
root.title("grid() ์˜ˆ์ œ")
root.geometry("400x300")

# ๊ณ„์‚ฐ๊ธฐ ๋ ˆ์ด์•„์›ƒ ์˜ˆ์ œ
tk.Entry(root, width=30).grid(row=0, column=0, columnspan=4, padx=5, pady=5)

buttons = [
    '7', '8', '9', '/',
    '4', '5', '6', '*',
    '1', '2', '3', '-',
    '0', '.', '=', '+'
]

row_val = 1
col_val = 0

for button in buttons:
    tk.Button(root, text=button, width=5, height=2).grid(row=row_val, column=col_val, padx=2, pady=2)
    col_val += 1
    if col_val > 3:
        col_val = 0
        row_val += 1

root.mainloop()

๐Ÿ’ก grid() ํŒ

โ€ข columnspan: ์—ฌ๋Ÿฌ ์—ด์„ ์ฐจ์ง€ํ•˜๊ฒŒ ๋งŒ๋“ค๊ธฐ
โ€ข rowspan: ์—ฌ๋Ÿฌ ํ–‰์„ ์ฐจ์ง€ํ•˜๊ฒŒ ๋งŒ๋“ค๊ธฐ
โ€ข sticky: N, S, E, W (๋ถ, ๋‚จ, ๋™, ์„œ) - ์…€ ๋‚ด์—์„œ ์œ„์ ฏ ์ •๋ ฌ

3๏ธโƒฃ place() - ์ ˆ๋Œ€ ์ขŒํ‘œ ๋ฐฐ์น˜

์ •ํ™•ํ•œ x, y ์ขŒํ‘œ๋ฅผ ์ง€์ •ํ•ด์„œ ๋ฐฐ์น˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด์•ผ. ํ”ฝ์…€ ๋‹จ์œ„๋กœ ์ •๋ฐ€ํ•˜๊ฒŒ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์ฐฝ ํฌ๊ธฐ๊ฐ€ ๋ณ€ํ•˜๋ฉด ๋ ˆ์ด์•„์›ƒ์ด ๊นจ์งˆ ์ˆ˜ ์žˆ์–ด์„œ ์ฃผ์˜๊ฐ€ ํ•„์š”ํ•ด! โš ๏ธ

import tkinter as tk

root = tk.Tk()
root.title("place() ์˜ˆ์ œ")
root.geometry("400x300")

tk.Label(root, text="์ ˆ๋Œ€ ์ขŒํ‘œ (50, 50)", bg="#7c9cbf", fg="white").place(x=50, y=50)
tk.Label(root, text="์ ˆ๋Œ€ ์ขŒํ‘œ (200, 150)", bg="#66bb6a", fg="white").place(x=200, y=150)
tk.Button(root, text="๋ฒ„ํŠผ", width=10).place(x=150, y=250)

root.mainloop()

โš ๏ธ ์ฃผ์˜์‚ฌํ•ญ

ํ•œ ์ปจํ…Œ์ด๋„ˆ(ํ”„๋ ˆ์ž„์ด๋‚˜ ์œˆ๋„์šฐ) ์•ˆ์—์„œ pack(), grid(), place()๋ฅผ ์„ž์–ด์„œ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ ๋ผ! ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฑฐ๋‚˜ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ์–ด. ํ•˜๋‚˜์˜ ๋ ˆ์ด์•„์›ƒ ๊ด€๋ฆฌ์ž๋งŒ ์„ ํƒํ•ด์„œ ์‚ฌ์šฉํ•˜์ž!

๐ŸŽฏ ์ฃผ์š” ์œ„์ ฏ๋“ค ์™„์ „ ์ •๋ณต

์ด์ œ Tkinter์—์„œ ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ์œ„์ ฏ๋“ค์„ ํ•˜๋‚˜์”ฉ ์‚ดํŽด๋ณด์ž! ๊ฐ ์œ„์ ฏ์˜ ํŠน์ง•๊ณผ ์‚ฌ์šฉ๋ฒ•์„ ์•Œ๋ฉด ์ •๋ง ๋‹ค์–‘ํ•œ ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด. ๐Ÿ› ๏ธ

๐Ÿ“‹ Text - ์—ฌ๋Ÿฌ ์ค„ ํ…์ŠคํŠธ ์ž…๋ ฅ

Entry๋Š” ํ•œ ์ค„๋งŒ ์ž…๋ ฅ๋ฐ›์„ ์ˆ˜ ์žˆ์ง€๋งŒ, Text ์œ„์ ฏ์€ ์—ฌ๋Ÿฌ ์ค„์˜ ํ…์ŠคํŠธ๋ฅผ ์ž…๋ ฅ๋ฐ›๊ณ  ํŽธ์ง‘ํ•  ์ˆ˜ ์žˆ์–ด. ๋ฉ”๋ชจ์žฅ ๊ฐ™์€ ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“ค ๋•Œ ํ•„์ˆ˜์•ผ!

import tkinter as tk

def save_text():
    content = text.get("1.0", tk.END)
    print("์ €์žฅ๋œ ๋‚ด์šฉ:")
    print(content)

root = tk.Tk()
root.title("Text ์œ„์ ฏ ์˜ˆ์ œ")
root.geometry("500x400")

text = tk.Text(root, width=50, height=15, font=("Arial", 11))
text.pack(padx=10, pady=10)

# ์ดˆ๊ธฐ ํ…์ŠคํŠธ ์‚ฝ์ž…
text.insert("1.0", "์—ฌ๊ธฐ์— ํ…์ŠคํŠธ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”...\n")

button = tk.Button(root, text="์ €์žฅ", command=save_text)
button.pack(pady=5)

root.mainloop()

get("1.0", tk.END)๋Š” ์ฒซ ๋ฒˆ์งธ ์ค„์˜ ์ฒซ ๋ฒˆ์งธ ๋ฌธ์ž๋ถ€ํ„ฐ ๋๊นŒ์ง€ ๋ชจ๋“  ํ…์ŠคํŠธ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค๋Š” ๋œป์ด์•ผ. Tkinter์˜ Text ์œ„์ ฏ์€ "ํ–‰.์—ด" ํ˜•์‹์œผ๋กœ ์œ„์น˜๋ฅผ ์ง€์ •ํ•ด!

โ˜‘๏ธ Checkbutton - ์ฒดํฌ๋ฐ•์Šค

์—ฌ๋Ÿฌ ์˜ต์…˜ ์ค‘์—์„œ ์—ฌ๋Ÿฌ ๊ฐœ๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ์œ„์ ฏ์ด์•ผ.

import tkinter as tk

def show_selection():
    selected = []
    if var1.get():
        selected.append("Python")
    if var2.get():
        selected.append("Java")
    if var3.get():
        selected.append("C++")
    
    result_label.config(text=f"์„ ํƒ๋œ ์–ธ์–ด: {', '.join(selected)}")

root = tk.Tk()
root.title("Checkbutton ์˜ˆ์ œ")
root.geometry("400x300")

tk.Label(root, text="์ข‹์•„ํ•˜๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๋ฅผ ์„ ํƒํ•˜์„ธ์š”:", 
         font=("Arial", 12)).pack(pady=10)

var1 = tk.BooleanVar()
var2 = tk.BooleanVar()
var3 = tk.BooleanVar()

tk.Checkbutton(root, text="Python ๐Ÿ", variable=var1, 
               font=("Arial", 11)).pack(anchor=tk.W, padx=50)
tk.Checkbutton(root, text="Java โ˜•", variable=var2, 
               font=("Arial", 11)).pack(anchor=tk.W, padx=50)
tk.Checkbutton(root, text="C++ ๐Ÿ”ง", variable=var3, 
               font=("Arial", 11)).pack(anchor=tk.W, padx=50)

tk.Button(root, text="ํ™•์ธ", command=show_selection).pack(pady=10)

result_label = tk.Label(root, text="", font=("Arial", 11), fg="#7c9cbf")
result_label.pack(pady=10)

root.mainloop()

BooleanVar()๋Š” ์ฒดํฌ ์ƒํƒœ๋ฅผ ์ €์žฅํ•˜๋Š” ํŠน๋ณ„ํ•œ ๋ณ€์ˆ˜์•ผ. True/False ๊ฐ’์„ ๊ฐ€์ง€์ง€!

๐Ÿ”˜ Radiobutton - ๋ผ๋””์˜ค ๋ฒ„ํŠผ

์—ฌ๋Ÿฌ ์˜ต์…˜ ์ค‘์—์„œ ํ•˜๋‚˜๋งŒ ์„ ํƒํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ์œ„์ ฏ์ด์•ผ. ์ฒดํฌ๋ฐ•์Šค์™€ ๋น„์Šทํ•˜์ง€๋งŒ ๋ฐฐํƒ€์  ์„ ํƒ์ด ํ•„์š”ํ•  ๋•Œ ์‚ฌ์šฉํ•ด!

import tkinter as tk

def show_choice():
    choice = var.get()
    choices = {1: "์ดˆ๊ธ‰", 2: "์ค‘๊ธ‰", 3: "๊ณ ๊ธ‰"}
    result_label.config(text=f"์„ ํƒํ•œ ๋ ˆ๋ฒจ: {choices[choice]}")

root = tk.Tk()
root.title("Radiobutton ์˜ˆ์ œ")
root.geometry("400x300")

tk.Label(root, text="๋‹น์‹ ์˜ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ ˆ๋ฒจ์€?", 
         font=("Arial", 12, "bold")).pack(pady=10)

var = tk.IntVar()
var.set(1)  # ๊ธฐ๋ณธ๊ฐ’ ์„ค์ •

tk.Radiobutton(root, text="์ดˆ๊ธ‰ ๐ŸŒฑ", variable=var, value=1, 
               font=("Arial", 11)).pack(anchor=tk.W, padx=50)
tk.Radiobutton(root, text="์ค‘๊ธ‰ ๐ŸŒฟ", variable=var, value=2, 
               font=("Arial", 11)).pack(anchor=tk.W, padx=50)
tk.Radiobutton(root, text="๊ณ ๊ธ‰ ๐ŸŒณ", variable=var, value=3, 
               font=("Arial", 11)).pack(anchor=tk.W, padx=50)

tk.Button(root, text="ํ™•์ธ", command=show_choice).pack(pady=10)

result_label = tk.Label(root, text="", font=("Arial", 11), fg="#66bb6a")
result_label.pack(pady=10)

root.mainloop()

๊ฐ™์€ variable์„ ๊ณต์œ ํ•˜๋Š” Radiobutton๋“ค์€ ํ•˜๋‚˜์˜ ๊ทธ๋ฃน์ด ๋˜์–ด์„œ, ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•˜๋ฉด ๋‹ค๋ฅธ ๊ฒƒ๋“ค์€ ์ž๋™์œผ๋กœ ํ•ด์ œ๋ผ!

๐Ÿ“œ Listbox - ๋ชฉ๋ก ์ƒ์ž

์—ฌ๋Ÿฌ ํ•ญ๋ชฉ์„ ๋ฆฌ์ŠคํŠธ ํ˜•ํƒœ๋กœ ๋ณด์—ฌ์ฃผ๊ณ  ์„ ํƒํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ์œ„์ ฏ์ด์•ผ.

import tkinter as tk

def show_selection():
    selection = listbox.curselection()
    if selection:
        index = selection[0]
        value = listbox.get(index)
        result_label.config(text=f"์„ ํƒ๋œ ํ•ญ๋ชฉ: {value}")

root = tk.Tk()
root.title("Listbox ์˜ˆ์ œ")
root.geometry("400x350")

tk.Label(root, text="ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์„ ํƒํ•˜์„ธ์š”:", 
         font=("Arial", 12)).pack(pady=10)

listbox = tk.Listbox(root, height=8, font=("Arial", 11))
listbox.pack(padx=20, pady=10)

frameworks = ["Django", "Flask", "FastAPI", "Pyramid", "Tornado", 
              "Bottle", "CherryPy", "Web2py"]

for framework in frameworks:
    listbox.insert(tk.END, framework)

tk.Button(root, text="ํ™•์ธ", command=show_selection).pack(pady=5)

result_label = tk.Label(root, text="", font=("Arial", 11), fg="#7c9cbf")
result_label.pack(pady=10)

root.mainloop()

๐Ÿ“Š Combobox - ์ฝค๋ณด๋ฐ•์Šค (๋“œ๋กญ๋‹ค์šด)

Combobox๋Š” ๊ธฐ๋ณธ Tkinter์—๋Š” ์—†๊ณ , tkinter.ttk ๋ชจ๋“ˆ์—์„œ ์ œ๊ณตํ•˜๋Š” ์œ„์ ฏ์ด์•ผ. ๋“œ๋กญ๋‹ค์šด ๋ฉ”๋‰ด๋ฅผ ๋งŒ๋“ค ๋•Œ ์‚ฌ์šฉํ•ด!

import tkinter as tk
from tkinter import ttk

def show_selection():
    selected = combo.get()
    result_label.config(text=f"์„ ํƒ๋œ ๋„์‹œ: {selected}")

root = tk.Tk()
root.title("Combobox ์˜ˆ์ œ")
root.geometry("400x250")

tk.Label(root, text="๋„์‹œ๋ฅผ ์„ ํƒํ•˜์„ธ์š”:", 
         font=("Arial", 12)).pack(pady=10)

combo = ttk.Combobox(root, values=["์„œ์šธ", "๋ถ€์‚ฐ", "๋Œ€๊ตฌ", "์ธ์ฒœ", "๊ด‘์ฃผ", "๋Œ€์ „", "์šธ์‚ฐ"],
                     font=("Arial", 11), state="readonly")
combo.pack(pady=10)
combo.set("์„œ์šธ")  # ๊ธฐ๋ณธ๊ฐ’ ์„ค์ •

tk.Button(root, text="ํ™•์ธ", command=show_selection).pack(pady=10)

result_label = tk.Label(root, text="", font=("Arial", 11), fg="#66bb6a")
result_label.pack(pady=10)

root.mainloop()

state="readonly"๋กœ ์„ค์ •ํ•˜๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ์ž…๋ ฅํ•  ์ˆ˜ ์—†๊ณ  ๋ชฉ๋ก์—์„œ๋งŒ ์„ ํƒํ•  ์ˆ˜ ์žˆ์–ด!

๐ŸŽš๏ธ Scale - ์Šฌ๋ผ์ด๋”

๋ฒ”์œ„ ๋‚ด์—์„œ ๊ฐ’์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋Š” ์Šฌ๋ผ์ด๋” ์œ„์ ฏ์ด์•ผ. ๋ณผ๋ฅจ ์กฐ์ ˆ์ด๋‚˜ ๋ฐ๊ธฐ ์กฐ์ ˆ ๊ฐ™์€ ๊ธฐ๋Šฅ์— ๋”ฑ์ด์ง€!

import tkinter as tk

def update_value(val):
    result_label.config(text=f"ํ˜„์žฌ ๊ฐ’: {int(float(val))}")

root = tk.Tk()
root.title("Scale ์˜ˆ์ œ")
root.geometry("400x300")

tk.Label(root, text="๊ฐ’์„ ์กฐ์ ˆํ•˜์„ธ์š”:", font=("Arial", 12)).pack(pady=10)

scale = tk.Scale(root, from_=0, to=100, orient=tk.HORIZONTAL, 
                 length=300, command=update_value)
scale.set(50)  # ์ดˆ๊ธฐ๊ฐ’
scale.pack(pady=20)

result_label = tk.Label(root, text="ํ˜„์žฌ ๊ฐ’: 50", 
                       font=("Arial", 14), fg="#7c9cbf")
result_label.pack(pady=10)

root.mainloop()

๐ŸŽจ Canvas - ๊ทธ๋ฆผ ๊ทธ๋ฆฌ๊ธฐ

Canvas๋Š” ๋„ํ˜•, ์„ , ํ…์ŠคํŠธ, ์ด๋ฏธ์ง€ ๋“ฑ์„ ๊ทธ๋ฆด ์ˆ˜ ์žˆ๋Š” ๊ฐ•๋ ฅํ•œ ์œ„์ ฏ์ด์•ผ. ๊ฒŒ์ž„์ด๋‚˜ ๊ทธ๋ž˜ํ”ฝ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ค ๋•Œ ํ•„์ˆ˜!

import tkinter as tk

root = tk.Tk()
root.title("Canvas ์˜ˆ์ œ")
root.geometry("500x400")

canvas = tk.Canvas(root, width=450, height=350, bg="white")
canvas.pack(padx=10, pady=10)

# ์‚ฌ๊ฐํ˜• ๊ทธ๋ฆฌ๊ธฐ
canvas.create_rectangle(50, 50, 150, 150, fill="#7c9cbf", outline="#4a5f7f")

# ์› ๊ทธ๋ฆฌ๊ธฐ
canvas.create_oval(200, 50, 300, 150, fill="#66bb6a", outline="#4caf50")

# ์„  ๊ทธ๋ฆฌ๊ธฐ
canvas.create_line(50, 200, 300, 200, fill="#ffa726", width=3)

# ํ…์ŠคํŠธ ๊ทธ๋ฆฌ๊ธฐ
canvas.create_text(225, 250, text="Tkinter Canvas!", 
                  font=("Arial", 20, "bold"), fill="#4a5f7f")

# ๋‹ค๊ฐํ˜• ๊ทธ๋ฆฌ๊ธฐ (๋ณ„)
points = [225, 280, 240, 315, 275, 315, 245, 335, 255, 370, 
          225, 350, 195, 370, 205, 335, 175, 315, 210, 315]
canvas.create_polygon(points, fill="#ff6b6b", outline="#c92a2a")

root.mainloop()

๐ŸŽญ Frame์œผ๋กœ ๋ ˆ์ด์•„์›ƒ ๊ตฌ์„ฑํ•˜๊ธฐ

Frame์€ ๋‹ค๋ฅธ ์œ„์ ฏ๋“ค์„ ๊ทธ๋ฃนํ™”ํ•˜๋Š” ์ปจํ…Œ์ด๋„ˆ ์—ญํ• ์„ ํ•ด. ๋ณต์žกํ•œ ๋ ˆ์ด์•„์›ƒ์„ ๋งŒ๋“ค ๋•Œ ์ •๋ง ์œ ์šฉํ•ด! ๐Ÿ—๏ธ

import tkinter as tk

root = tk.Tk()
root.title("Frame ์˜ˆ์ œ")
root.geometry("500x400")

# ์ƒ๋‹จ ํ”„๋ ˆ์ž„
top_frame = tk.Frame(root, bg="#7c9cbf", height=100)
top_frame.pack(fill=tk.X, padx=10, pady=5)

tk.Label(top_frame, text="์ƒ๋‹จ ์˜์—ญ", bg="#7c9cbf", fg="white", 
         font=("Arial", 16, "bold")).pack(pady=30)

# ์ค‘๊ฐ„ ํ”„๋ ˆ์ž„ (์ขŒ์šฐ ๋ถ„ํ• )
middle_frame = tk.Frame(root)
middle_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)

left_frame = tk.Frame(middle_frame, bg="#e8f5e9", width=200)
left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 5))

tk.Label(left_frame, text="์™ผ์ชฝ ์˜์—ญ", bg="#e8f5e9", 
         font=("Arial", 12)).pack(pady=20)
tk.Button(left_frame, text="๋ฒ„ํŠผ 1").pack(pady=5)
tk.Button(left_frame, text="๋ฒ„ํŠผ 2").pack(pady=5)

right_frame = tk.Frame(middle_frame, bg="#fff3e0", width=200)
right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=(5, 0))

tk.Label(right_frame, text="์˜ค๋ฅธ์ชฝ ์˜์—ญ", bg="#fff3e0", 
         font=("Arial", 12)).pack(pady=20)
tk.Entry(right_frame, width=20).pack(pady=5)
tk.Entry(right_frame, width=20).pack(pady=5)

# ํ•˜๋‹จ ํ”„๋ ˆ์ž„
bottom_frame = tk.Frame(root, bg="#66bb6a", height=80)
bottom_frame.pack(fill=tk.X, padx=10, pady=5)

tk.Label(bottom_frame, text="ํ•˜๋‹จ ์˜์—ญ", bg="#66bb6a", fg="white", 
         font=("Arial", 14)).pack(pady=25)

root.mainloop()

Frame์„ ์‚ฌ์šฉํ•˜๋ฉด ํ™”๋ฉด์„ ๋…ผ๋ฆฌ์ ์œผ๋กœ ๋ถ„ํ• ํ•ด์„œ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด. ๊ฐ Frame ์•ˆ์—์„œ๋Š” ๋…๋ฆฝ์ ์œผ๋กœ ๋ ˆ์ด์•„์›ƒ ๊ด€๋ฆฌ์ž๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€!

๐Ÿ’ฌ ๋ฉ”์‹œ์ง€ ๋ฐ•์Šค์™€ ๋Œ€ํ™”์ƒ์ž

์‚ฌ์šฉ์ž์—๊ฒŒ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด์—ฌ์ฃผ๊ฑฐ๋‚˜ ํ™•์ธ์„ ๋ฐ›์„ ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€ํ™”์ƒ์ž๋“ค์ด์•ผ. tkinter.messagebox ๋ชจ๋“ˆ์—์„œ ์ œ๊ณตํ•ด!

import tkinter as tk
from tkinter import messagebox

def show_info():
    messagebox.showinfo("์ •๋ณด", "์ด๊ฒƒ์€ ์ •๋ณด ๋ฉ”์‹œ์ง€์ž…๋‹ˆ๋‹ค! โ„น๏ธ")

def show_warning():
    messagebox.showwarning("๊ฒฝ๊ณ ", "์ฃผ์˜๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค! โš ๏ธ")

def show_error():
    messagebox.showerror("์˜ค๋ฅ˜", "์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค! โŒ")

def ask_question():
    result = messagebox.askquestion("์งˆ๋ฌธ", "๊ณ„์†ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?")
    if result == 'yes':
        label.config(text="Yes๋ฅผ ์„ ํƒํ–ˆ์Šต๋‹ˆ๋‹ค!")
    else:
        label.config(text="No๋ฅผ ์„ ํƒํ–ˆ์Šต๋‹ˆ๋‹ค!")

def ask_okcancel():
    result = messagebox.askokcancel("ํ™•์ธ", "์ •๋ง๋กœ ์‚ญ์ œํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?")
    if result:
        label.config(text="์‚ญ์ œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!")
    else:
        label.config(text="์ทจ์†Œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!")

def ask_yesno():
    result = messagebox.askyesno("์ €์žฅ", "๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ์ €์žฅํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?")
    if result:
        label.config(text="์ €์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!")
    else:
        label.config(text="์ €์žฅํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค!")

root = tk.Tk()
root.title("MessageBox ์˜ˆ์ œ")
root.geometry("400x450")

tk.Label(root, text="๋‹ค์–‘ํ•œ ๋ฉ”์‹œ์ง€ ๋ฐ•์Šค", 
         font=("Arial", 14, "bold")).pack(pady=10)

tk.Button(root, text="์ •๋ณด ๋ฉ”์‹œ์ง€", command=show_info, width=20).pack(pady=5)
tk.Button(root, text="๊ฒฝ๊ณ  ๋ฉ”์‹œ์ง€", command=show_warning, width=20).pack(pady=5)
tk.Button(root, text="์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€", command=show_error, width=20).pack(pady=5)
tk.Button(root, text="์งˆ๋ฌธ (Yes/No)", command=ask_question, width=20).pack(pady=5)
tk.Button(root, text="ํ™•์ธ/์ทจ์†Œ", command=ask_okcancel, width=20).pack(pady=5)
tk.Button(root, text="์˜ˆ/์•„๋‹ˆ์˜ค", command=ask_yesno, width=20).pack(pady=5)

label = tk.Label(root, text="", font=("Arial", 11), fg="#7c9cbf")
label.pack(pady=20)

root.mainloop()

๐Ÿ“Œ MessageBox ์ข…๋ฅ˜

์ •๋ณด ํ‘œ์‹œ:
โ€ข showinfo() - ์ •๋ณด ๋ฉ”์‹œ์ง€
โ€ข showwarning() - ๊ฒฝ๊ณ  ๋ฉ”์‹œ์ง€
โ€ข showerror() - ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€

์‚ฌ์šฉ์ž ์ž…๋ ฅ ๋ฐ›๊ธฐ:
โ€ข askquestion() - Yes/No ์งˆ๋ฌธ (๋ฐ˜ํ™˜๊ฐ’: 'yes' ๋˜๋Š” 'no')
โ€ข askokcancel() - OK/Cancel (๋ฐ˜ํ™˜๊ฐ’: True ๋˜๋Š” False)
โ€ข askyesno() - Yes/No (๋ฐ˜ํ™˜๊ฐ’: True ๋˜๋Š” False)
โ€ข askretrycancel() - Retry/Cancel (๋ฐ˜ํ™˜๊ฐ’: True ๋˜๋Š” False)

๐Ÿ“ ํŒŒ์ผ ๋Œ€ํ™”์ƒ์ž

ํŒŒ์ผ์„ ์—ด๊ฑฐ๋‚˜ ์ €์žฅํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€ํ™”์ƒ์ž์•ผ. tkinter.filedialog ๋ชจ๋“ˆ์—์„œ ์ œ๊ณตํ•ด!

import tkinter as tk
from tkinter import filedialog, messagebox

def open_file():
    filename = filedialog.askopenfilename(
        title="ํŒŒ์ผ ์„ ํƒ",
        filetypes=(("ํ…์ŠคํŠธ ํŒŒ์ผ", "*.txt"), ("๋ชจ๋“  ํŒŒ์ผ", "*.*"))
    )
    if filename:
        try:
            with open(filename, 'r', encoding='utf-8') as file:
                content = file.read()
                text.delete("1.0", tk.END)
                text.insert("1.0", content)
                label.config(text=f"์—ด๋ฆฐ ํŒŒ์ผ: {filename}")
        except Exception as e:
            messagebox.showerror("์˜ค๋ฅ˜", f"ํŒŒ์ผ์„ ์—ด ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {str(e)}")

def save_file():
    filename = filedialog.asksaveasfilename(
        title="ํŒŒ์ผ ์ €์žฅ",
        defaultextension=".txt",
        filetypes=(("ํ…์ŠคํŠธ ํŒŒ์ผ", "*.txt"), ("๋ชจ๋“  ํŒŒ์ผ", "*.*"))
    )
    if filename:
        try:
            content = text.get("1.0", tk.END)
            with open(filename, 'w', encoding='utf-8') as file:
                file.write(content)
            messagebox.showinfo("์„ฑ๊ณต", "ํŒŒ์ผ์ด ์ €์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!")
            label.config(text=f"์ €์žฅ๋œ ํŒŒ์ผ: {filename}")
        except Exception as e:
            messagebox.showerror("์˜ค๋ฅ˜", f"ํŒŒ์ผ์„ ์ €์žฅํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {str(e)}")

root = tk.Tk()
root.title("ํŒŒ์ผ ๋Œ€ํ™”์ƒ์ž ์˜ˆ์ œ")
root.geometry("600x450")

button_frame = tk.Frame(root)
button_frame.pack(pady=10)

tk.Button(button_frame, text="ํŒŒ์ผ ์—ด๊ธฐ ๐Ÿ“‚", command=open_file, 
          width=15).pack(side=tk.LEFT, padx=5)
tk.Button(button_frame, text="ํŒŒ์ผ ์ €์žฅ ๐Ÿ’พ", command=save_file, 
          width=15).pack(side=tk.LEFT, padx=5)

text = tk.Text(root, width=70, height=20, font=("Arial", 10))
text.pack(padx=10, pady=10)

label = tk.Label(root, text="ํŒŒ์ผ์„ ์—ด๊ฑฐ๋‚˜ ์ €์žฅํ•˜์„ธ์š”", 
                font=("Arial", 10), fg="#6b7c93")
label.pack(pady=5)

root.mainloop()

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ฐ„๋‹จํ•œ ๋ฉ”๋ชจ์žฅ ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด! ๐Ÿ“

๐ŸŽจ ์Šคํƒ€์ผ๋ง๊ณผ ํ…Œ๋งˆ

๊ธฐ๋ณธ Tkinter ์œ„์ ฏ์€ ์ข€ ํˆฌ๋ฐ•ํ•ด ๋ณด์ผ ์ˆ˜ ์žˆ์–ด. ํ•˜์ง€๋งŒ tkinter.ttk ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•˜๋ฉด ๋” ํ˜„๋Œ€์ ์ธ ์Šคํƒ€์ผ์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ์–ด!

import tkinter as tk
from tkinter import ttk

root = tk.Tk()
root.title("ttk ์Šคํƒ€์ผ ์˜ˆ์ œ")
root.geometry("500x400")

# ์Šคํƒ€์ผ ๊ฐ์ฒด ์ƒ์„ฑ
style = ttk.Style()

# ํ…Œ๋งˆ ์„ ํƒ (์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ํ…Œ๋งˆ: 'clam', 'alt', 'default', 'classic')
style.theme_use('clam')

# ์ปค์Šคํ…€ ์Šคํƒ€์ผ ์ •์˜
style.configure('Custom.TButton', 
                foreground='white',
                background='#7c9cbf',
                font=('Arial', 11, 'bold'),
                borderwidth=0)

style.map('Custom.TButton',
          background=[('active', '#5a7a99')])

tk.Label(root, text="ttk ์œ„์ ฏ ์˜ˆ์ œ", 
         font=("Arial", 16, "bold")).pack(pady=20)

# ttk ๋ฒ„ํŠผ
ttk.Button(root, text="ttk ๊ธฐ๋ณธ ๋ฒ„ํŠผ", width=20).pack(pady=5)
ttk.Button(root, text="์ปค์Šคํ…€ ์Šคํƒ€์ผ ๋ฒ„ํŠผ", style='Custom.TButton', 
           width=20).pack(pady=5)

# ttk Entry
ttk.Entry(root, width=30, font=("Arial", 11)).pack(pady=10)

# ttk Combobox
combo = ttk.Combobox(root, values=["์˜ต์…˜ 1", "์˜ต์…˜ 2", "์˜ต์…˜ 3"], 
                     width=27, state="readonly")
combo.pack(pady=10)

# ttk Progressbar
progress = ttk.Progressbar(root, length=300, mode='determinate')
progress.pack(pady=20)
progress['value'] = 70

root.mainloop()

๐Ÿ’ก ttk vs ๊ธฐ๋ณธ Tkinter

ttk์˜ ์žฅ์ :
โœ… ๋” ํ˜„๋Œ€์ ์ด๊ณ  ์„ธ๋ จ๋œ ๋””์ž์ธ
โœ… ์šด์˜์ฒด์ œ ๋„ค์ดํ‹ฐ๋ธŒ ์Šคํƒ€์ผ ์ง€์›
โœ… ํ…Œ๋งˆ ์‹œ์Šคํ…œ์œผ๋กœ ์ผ๊ด€๋œ ๋””์ž์ธ ์œ ์ง€
โœ… ์ถ”๊ฐ€ ์œ„์ ฏ ์ œ๊ณต (Treeview, Notebook ๋“ฑ)

๊ธฐ๋ณธ Tkinter์˜ ์žฅ์ :
โœ… ๋” ๋งŽ์€ ์ปค์Šคํ„ฐ๋งˆ์ด์ง• ์˜ต์…˜
โœ… ๋” ์„ธ๋ฐ€ํ•œ ์ œ์–ด ๊ฐ€๋Šฅ
โœ… ์ผ๋ถ€ ์œ„์ ฏ์€ ttk์— ์—†์Œ (Canvas, Text ๋“ฑ)

๐ŸŽฏ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌํ•˜๊ธฐ

์‚ฌ์šฉ์ž์˜ ๋งˆ์šฐ์Šค ํด๋ฆญ, ํ‚ค๋ณด๋“œ ์ž…๋ ฅ ๋“ฑ์˜ ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด์ž! ๐Ÿ–ฑ๏ธโŒจ๏ธ

๐Ÿ–ฑ๏ธ ๋งˆ์šฐ์Šค ์ด๋ฒคํŠธ

import tkinter as tk

def on_left_click(event):
    label.config(text=f"์™ผ์ชฝ ํด๋ฆญ! ์œ„์น˜: ({event.x}, {event.y})")

def on_right_click(event):
    label.config(text=f"์˜ค๋ฅธ์ชฝ ํด๋ฆญ! ์œ„์น˜: ({event.x}, {event.y})")

def on_double_click(event):
    label.config(text="๋”๋ธ” ํด๋ฆญ!")

def on_mouse_enter(event):
    button.config(bg="#5a7a99")

def on_mouse_leave(event):
    button.config(bg="#7c9cbf")

root = tk.Tk()
root.title("๋งˆ์šฐ์Šค ์ด๋ฒคํŠธ ์˜ˆ์ œ")
root.geometry("500x400")

tk.Label(root, text="๋งˆ์šฐ์Šค ์ด๋ฒคํŠธ ํ…Œ์ŠคํŠธ", 
         font=("Arial", 14, "bold")).pack(pady=20)

button = tk.Button(root, text="๋งˆ์šฐ์Šค๋ฅผ ์˜ฌ๋ ค๋ณด์„ธ์š”", 
                  bg="#7c9cbf", fg="white", font=("Arial", 12),
                  width=20, height=2)
button.pack(pady=20)

# ์ด๋ฒคํŠธ ๋ฐ”์ธ๋”ฉ
button.bind("<Button-1>", on_left_click)  # ์™ผ์ชฝ ํด๋ฆญ
button.bind("<Button-3>", on_right_click)  # ์˜ค๋ฅธ์ชฝ ํด๋ฆญ
button.bind("<Double-Button-1>", on_double_click)  # ๋”๋ธ” ํด๋ฆญ
button.bind("<Enter>", on_mouse_enter)  # ๋งˆ์šฐ์Šค ์ง„์ž…
button.bind("<Leave>", on_mouse_leave)  # ๋งˆ์šฐ์Šค ์ดํƒˆ

label = tk.Label(root, text="๋ฒ„ํŠผ์„ ํด๋ฆญํ•ด๋ณด์„ธ์š”!", 
                font=("Arial", 12), fg="#6b7c93")
label.pack(pady=20)

root.mainloop()

โŒจ๏ธ ํ‚ค๋ณด๋“œ ์ด๋ฒคํŠธ

import tkinter as tk

def on_key_press(event):
    label.config(text=f"๋ˆŒ๋ฆฐ ํ‚ค: {event.keysym} (์ฝ”๋“œ: {event.keycode})")

def on_return(event):
    text = entry.get()
    result_label.config(text=f"์ž…๋ ฅ๋œ ๋‚ด์šฉ: {text}")
    entry.delete(0, tk.END)

def on_escape(event):
    root.quit()

root = tk.Tk()
root.title("ํ‚ค๋ณด๋“œ ์ด๋ฒคํŠธ ์˜ˆ์ œ")
root.geometry("500x350")

tk.Label(root, text="ํ‚ค๋ณด๋“œ ์ด๋ฒคํŠธ ํ…Œ์ŠคํŠธ", 
         font=("Arial", 14, "bold")).pack(pady=20)

entry = tk.Entry(root, width=40, font=("Arial", 12))
entry.pack(pady=10)
entry.focus()  # ํฌ์ปค์Šค ์„ค์ •

tk.Label(root, text="Enter๋ฅผ ๋ˆ„๋ฅด๋ฉด ์ž…๋ ฅ ๋‚ด์šฉ์ด ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค\nESC๋ฅผ ๋ˆ„๋ฅด๋ฉด ํ”„๋กœ๊ทธ๋žจ์ด ์ข…๋ฃŒ๋ฉ๋‹ˆ๋‹ค", 
         font=("Arial", 10), fg="#6b7c93").pack(pady=10)

# ํ‚ค๋ณด๋“œ ์ด๋ฒคํŠธ ๋ฐ”์ธ๋”ฉ
root.bind("<Key>", on_key_press)
entry.bind("<Return>", on_return)
root.bind("<Escape>", on_escape)

label = tk.Label(root, text="ํ‚ค๋ฅผ ๋ˆŒ๋Ÿฌ๋ณด์„ธ์š”!", 
                font=("Arial", 11), fg="#7c9cbf")
label.pack(pady=10)

result_label = tk.Label(root, text="", 
                       font=("Arial", 11, "bold"), fg="#66bb6a")
result_label.pack(pady=10)

root.mainloop()

๐Ÿ“Œ ์ฃผ์š” ์ด๋ฒคํŠธ ์ข…๋ฅ˜

๋งˆ์šฐ์Šค ์ด๋ฒคํŠธ:
โ€ข <Button-1> - ์™ผ์ชฝ ๋ฒ„ํŠผ ํด๋ฆญ
โ€ข <Button-2> - ์ค‘๊ฐ„ ๋ฒ„ํŠผ ํด๋ฆญ
โ€ข <Button-3> - ์˜ค๋ฅธ์ชฝ ๋ฒ„ํŠผ ํด๋ฆญ
โ€ข <Double-Button-1> - ๋”๋ธ” ํด๋ฆญ
โ€ข <Motion> - ๋งˆ์šฐ์Šค ์ด๋™
โ€ข <Enter> - ๋งˆ์šฐ์Šค ์ง„์ž…
โ€ข <Leave> - ๋งˆ์šฐ์Šค ์ดํƒˆ

ํ‚ค๋ณด๋“œ ์ด๋ฒคํŠธ:
โ€ข <Key> - ์•„๋ฌด ํ‚ค๋‚˜ ๋ˆŒ๋ฆผ
โ€ข <Return> - Enter ํ‚ค
โ€ข <Escape> - ESC ํ‚ค
โ€ข <space> - ์ŠคํŽ˜์ด์Šค๋ฐ”
โ€ข <Control-c> - Ctrl+C
โ€ข <Alt-F4> - Alt+F4

๐ŸŽฌ ์‹ค์ „ ํ”„๋กœ์ ํŠธ: ๊ฐ„๋‹จํ•œ ๊ณ„์‚ฐ๊ธฐ ๋งŒ๋“ค๊ธฐ

์ง€๊ธˆ๊นŒ์ง€ ๋ฐฐ์šด ๋‚ด์šฉ์„ ์ข…ํ•ฉํ•ด์„œ ์‹ค์ œ๋กœ ๋™์ž‘ํ•˜๋Š” ๊ณ„์‚ฐ๊ธฐ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž! ๐Ÿงฎ

import tkinter as tk
from tkinter import messagebox

class Calculator:
    def __init__(self, root):
        self.root = root
        self.root.title("๊ณ„์‚ฐ๊ธฐ ๐Ÿงฎ")
        self.root.geometry("350x450")
        self.root.resizable(False, False)
        
        self.expression = ""
        self.input_text = tk.StringVar()
        
        self.create_widgets()
    
    def create_widgets(self):
        # ์ž…๋ ฅ ํ™”๋ฉด
        input_frame = tk.Frame(self.root, bg="#f5f7fa")
        input_frame.pack(fill=tk.BOTH, padx=10, pady=10)
        
        input_field = tk.Entry(input_frame, textvariable=self.input_text,
                              font=("Arial", 24), justify=tk.RIGHT,
                              bd=5, relief=tk.FLAT, bg="#ffffff")
        input_field.pack(fill=tk.BOTH, ipady=20)
        
        # ๋ฒ„ํŠผ ํ”„๋ ˆ์ž„
        button_frame = tk.Frame(self.root, bg="#f5f7fa")
        button_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=(0, 10))
        
        # ๋ฒ„ํŠผ ์ •์˜
        buttons = [
            ['C', 'โ†', '%', '/'],
            ['7', '8', '9', '*'],
            ['4', '5', '6', '-'],
            ['1', '2', '3', '+'],
            ['0', '.', '=']
        ]
        
        # ๋ฒ„ํŠผ ์ƒ์„ฑ
        for i, row in enumerate(buttons):
            for j, button in enumerate(row):
                if button == '=':
                    btn = tk.Button(button_frame, text=button,
                                  font=("Arial", 18, "bold"),
                                  bg="#66bb6a", fg="white",
                                  command=self.calculate)
                    btn.grid(row=i, column=j, columnspan=2, sticky="nsew", padx=2, pady=2)
                elif button == 'C':
                    btn = tk.Button(button_frame, text=button,
                                  font=("Arial", 18, "bold"),
                                  bg="#ff6b6b", fg="white",
                                  command=self.clear)
                    btn.grid(row=i, column=j, sticky="nsew", padx=2, pady=2)
                elif button == 'โ†':
                    btn = tk.Button(button_frame, text=button,
                                  font=("Arial", 18, "bold"),
                                  bg="#ffa726", fg="white",
                                  command=self.backspace)
                    btn.grid(row=i, column=j, sticky="nsew", padx=2, pady=2)
                elif button in ['/', '*', '-', '+', '%']:
                    btn = tk.Button(button_frame, text=button,
                                  font=("Arial", 18, "bold"),
                                  bg="#7c9cbf", fg="white",
                                  command=lambda x=button: self.click(x))
                    btn.grid(row=i, column=j, sticky="nsew", padx=2, pady=2)
                else:
                    btn = tk.Button(button_frame, text=button,
                                  font=("Arial", 18),
                                  bg="#e8ecf1", fg="#2c3e50",
                                  command=lambda x=button: self.click(x))
                    btn.grid(row=i, column=j, sticky="nsew", padx=2, pady=2)
        
        # ๊ทธ๋ฆฌ๋“œ ๊ฐ€์ค‘์น˜ ์„ค์ •
        for i in range(5):
            button_frame.grid_rowconfigure(i, weight=1)
        for j in range(4):
            button_frame.grid_columnconfigure(j, weight=1)
    
    def click(self, value):
        self.expression += str(value)
        self.input_text.set(self.expression)
    
    def clear(self):
        self.expression = ""
        self.input_text.set("")
    
    def backspace(self):
        self.expression = self.expression[:-1]
        self.input_text.set(self.expression)
    
    def calculate(self):
        try:
            result = str(eval(self.expression))
            self.input_text.set(result)
            self.expression = result
        except:
            messagebox.showerror("์˜ค๋ฅ˜", "์ž˜๋ชป๋œ ์ˆ˜์‹์ž…๋‹ˆ๋‹ค!")
            self.expression = ""
            self.input_text.set("")

if __name__ == "__main__":
    root = tk.Tk()
    calculator = Calculator(root)
    root.mainloop()

์ด ๊ณ„์‚ฐ๊ธฐ๋Š” ๊ฐ์ฒด์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹์œผ๋กœ ์ž‘์„ฑ๋˜์—ˆ์–ด. ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ฝ”๋“œ๋ฅผ ๋” ์ฒด๊ณ„์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์ง€! ๐ŸŽ“

๐ŸŽฏ ๊ณ„์‚ฐ๊ธฐ์˜ ์ฃผ์š” ๊ธฐ๋Šฅ

โœ… ๊ธฐ๋ณธ ์‚ฌ์น™์—ฐ์‚ฐ (+, -, *, /)
โœ… ๋‚˜๋จธ์ง€ ์—ฐ์‚ฐ (%)
โœ… ์†Œ์ˆ˜์  ์ž…๋ ฅ
โœ… ์ง€์šฐ๊ธฐ (C) ๊ธฐ๋Šฅ
โœ… ๋ฐฑ์ŠคํŽ˜์ด์Šค (โ†) ๊ธฐ๋Šฅ
โœ… ์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ

๐ŸŽจ ๋ฉ”๋‰ด๋ฐ” ๋งŒ๋“ค๊ธฐ

์ „๋ฌธ์ ์ธ ํ”„๋กœ๊ทธ๋žจ์—๋Š” ๋ฉ”๋‰ด๋ฐ”๊ฐ€ ํ•„์ˆ˜์ง€! ํŒŒ์ผ, ํŽธ์ง‘, ๋„์›€๋ง ๊ฐ™์€ ๋ฉ”๋‰ด๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž.

import tkinter as tk
from tkinter import messagebox, filedialog

def new_file():
    text.delete("1.0", tk.END)
    root.title("์ œ๋ชฉ ์—†์Œ - ๋ฉ”๋ชจ์žฅ")

def open_file():
    filename = filedialog.askopenfilename(
        defaultextension=".txt",
        filetypes=[("ํ…์ŠคํŠธ ํŒŒ์ผ", "*.txt"), ("๋ชจ๋“  ํŒŒ์ผ", "*.*")]
    )
    if filename:
        with open(filename, 'r', encoding='utf-8') as file:
            text.delete("1.0", tk.END)
            text.insert("1.0", file.read())
        root.title(f"{filename} - ๋ฉ”๋ชจ์žฅ")

def save_file():
    filename = filedialog.asksaveasfilename(
        defaultextension=".txt",
        filetypes=[("ํ…์ŠคํŠธ ํŒŒ์ผ", "*.txt"), ("๋ชจ๋“  ํŒŒ์ผ", "*.*")]
    )
    if filename:
        with open(filename, 'w', encoding='utf-8') as file:
            file.write(text.get("1.0", tk.END))
        root.title(f"{filename} - ๋ฉ”๋ชจ์žฅ")
        messagebox.showinfo("์ €์žฅ", "ํŒŒ์ผ์ด ์ €์žฅ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!")

def exit_app():
    if messagebox.askokcancel("์ข…๋ฃŒ", "์ •๋ง๋กœ ์ข…๋ฃŒํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?"):
        root.quit()

def about():
    messagebox.showinfo("์ •๋ณด", "๊ฐ„๋‹จํ•œ ๋ฉ”๋ชจ์žฅ ํ”„๋กœ๊ทธ๋žจ\n๋ฒ„์ „ 1.0\n\nTkinter๋กœ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค! ๐Ÿ˜Š")

root = tk.Tk()
root.title("์ œ๋ชฉ ์—†์Œ - ๋ฉ”๋ชจ์žฅ")
root.geometry("700x500")

# ๋ฉ”๋‰ด๋ฐ” ์ƒ์„ฑ
menubar = tk.Menu(root)
root.config(menu=menubar)

# ํŒŒ์ผ ๋ฉ”๋‰ด
file_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="ํŒŒ์ผ", menu=file_menu)
file_menu.add_command(label="์ƒˆ ํŒŒ์ผ", command=new_file, accelerator="Ctrl+N")
file_menu.add_command(label="์—ด๊ธฐ", command=open_file, accelerator="Ctrl+O")
file_menu.add_command(label="์ €์žฅ", command=save_file, accelerator="Ctrl+S")
file_menu.add_separator()
file_menu.add_command(label="์ข…๋ฃŒ", command=exit_app, accelerator="Ctrl+Q")

# ํŽธ์ง‘ ๋ฉ”๋‰ด
edit_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="ํŽธ์ง‘", menu=edit_menu)
edit_menu.add_command(label="์‹คํ–‰ ์ทจ์†Œ", command=lambda: text.edit_undo())
edit_menu.add_command(label="๋‹ค์‹œ ์‹คํ–‰", command=lambda: text.edit_redo())
edit_menu.add_separator()
edit_menu.add_command(label="์ž˜๋ผ๋‚ด๊ธฐ", command=lambda: text.event_generate("<<Cut>>"))
edit_menu.add_command(label="๋ณต์‚ฌ", command=lambda: text.event_generate("<<Copy>>"))
edit_menu.add_command(label="๋ถ™์—ฌ๋„ฃ๊ธฐ", command=lambda: text.event_generate("<<Paste>>"))

# ๋„์›€๋ง ๋ฉ”๋‰ด
help_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="๋„์›€๋ง", menu=help_menu)
help_menu.add_command(label="์ •๋ณด", command=about)

# ํ…์ŠคํŠธ ์œ„์ ฏ
text = tk.Text(root, font=("๋ง‘์€ ๊ณ ๋”•", 11), undo=True, wrap=tk.WORD)
text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)

# ์Šคํฌ๋กค๋ฐ”
scrollbar = tk.Scrollbar(text)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
text.config(yscrollcommand=scrollbar.set)
scrollbar.config(command=text.yview)

# ํ‚ค๋ณด๋“œ ๋‹จ์ถ•ํ‚ค ๋ฐ”์ธ๋”ฉ
root.bind('<Control-n>', lambda e: new_file())
root.bind('<Control-o>', lambda e: open_file())
root.bind('<Control-s>', lambda e: save_file())
root.bind('<Control-q>', lambda e: exit_app())

root.mainloop()

tearoff=0์€ ๋ฉ”๋‰ด๋ฅผ ๋ถ„๋ฆฌํ•  ์ˆ˜ ์—†๊ฒŒ ๋งŒ๋“œ๋Š” ์˜ต์…˜์ด์•ผ. ๊ธฐ๋ณธ๊ฐ’์€ 1์ธ๋ฐ, ๊ทธ๋Ÿฌ๋ฉด ๋ฉ”๋‰ด๋ฅผ ๋–ผ์–ด๋‚ผ ์ˆ˜ ์žˆ๋Š” ์ ์„ ์ด ์ƒ๊ฒจ!

๐Ÿ–ผ๏ธ ์ด๋ฏธ์ง€ ๋‹ค๋ฃจ๊ธฐ

Tkinter์—์„œ ์ด๋ฏธ์ง€๋ฅผ ํ‘œ์‹œํ•˜๋ ค๋ฉด PIL (Pillow) ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒŒ ์ข‹์•„. ๋‹ค์–‘ํ•œ ์ด๋ฏธ์ง€ ํฌ๋งท์„ ์ง€์›ํ•˜๊ฑฐ๋“ !

# Pillow ์„ค์น˜: pip install Pillow

import tkinter as tk
from PIL import Image, ImageTk
from tkinter import filedialog, messagebox

def load_image():
    filename = filedialog.askopenfilename(
        title="์ด๋ฏธ์ง€ ์„ ํƒ",
        filetypes=[("์ด๋ฏธ์ง€ ํŒŒ์ผ", "*.png *.jpg *.jpeg *.gif *.bmp"), 
                  ("๋ชจ๋“  ํŒŒ์ผ", "*.*")]
    )
    
    if filename:
        try:
            # ์ด๋ฏธ์ง€ ์—ด๊ธฐ
            image = Image.open(filename)
            
            # ์ด๋ฏธ์ง€ ํฌ๊ธฐ ์กฐ์ • (์ตœ๋Œ€ 500x500)
            image.thumbnail((500, 500), Image.Resampling.LANCZOS)
            
            # PhotoImage๋กœ ๋ณ€ํ™˜
            photo = ImageTk.PhotoImage(image)
            
            # Label์— ์ด๋ฏธ์ง€ ํ‘œ์‹œ
            image_label.config(image=photo)
            image_label.image = photo  # ์ฐธ์กฐ ์œ ์ง€ (์ค‘์š”!)
            
            info_label.config(text=f"ํŒŒ์ผ: {filename}\nํฌ๊ธฐ: {image.size}")
        except Exception as e:
            messagebox.showerror("์˜ค๋ฅ˜", f"์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {str(e)}")

root = tk.Tk()
root.title("์ด๋ฏธ์ง€ ๋ทฐ์–ด ๐Ÿ–ผ๏ธ")
root.geometry("600x650")

tk.Label(root, text="์ด๋ฏธ์ง€ ๋ทฐ์–ด", 
         font=("Arial", 16, "bold")).pack(pady=10)

tk.Button(root, text="์ด๋ฏธ์ง€ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ๐Ÿ“‚", command=load_image,
         font=("Arial", 12), bg="#7c9cbf", fg="white",
         width=20).pack(pady=10)

# ์ด๋ฏธ์ง€ ํ‘œ์‹œ ์˜์—ญ
image_frame = tk.Frame(root, bg="#f5f7fa", width=520, height=520)
image_frame.pack(padx=10, pady=10)
image_frame.pack_propagate(False)

image_label = tk.Label(image_frame, text="์ด๋ฏธ์ง€๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์„ธ์š”", 
                      font=("Arial", 12), bg="#f5f7fa", fg="#6b7c93")
image_label.pack(expand=True)

info_label = tk.Label(root, text="", font=("Arial", 10), fg="#6b7c93")
info_label.pack(pady=5)

root.mainloop()

โš ๏ธ ์ค‘์š”ํ•œ ์ฃผ์˜์‚ฌํ•ญ

image_label.image = photo ์ด ์ค„์ด ์ •๋ง ์ค‘์š”ํ•ด! ์ด๋ ‡๊ฒŒ ์ฐธ์กฐ๋ฅผ ์œ ์ง€ํ•˜์ง€ ์•Š์œผ๋ฉด ์ด๋ฏธ์ง€๊ฐ€ ๊ฐ€๋น„์ง€ ์ปฌ๋ ‰์…˜๋˜์–ด์„œ ํ™”๋ฉด์— ํ‘œ์‹œ๋˜์ง€ ์•Š์•„. ์ด๊ฑด Tkinter์˜ ํŠน์„ฑ์ด๋‹ˆ๊นŒ ๊ผญ ๊ธฐ์–ตํ•ด๋‘ฌ!

โฐ ํƒ€์ด๋จธ์™€ ์• ๋‹ˆ๋ฉ”์ด์…˜

after() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ผ์ • ์‹œ๊ฐ„ ํ›„์— ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์–ด. ์ด๊ฑธ ํ™œ์šฉํ•˜๋ฉด ํƒ€์ด๋จธ๋‚˜ ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์ง€!

import tkinter as tk
from datetime import datetime

class DigitalClock:
    def __init__(self, root):
        self.root = root
        self.root.title("๋””์ง€ํ„ธ ์‹œ๊ณ„ โฐ")
        self.root.geometry("400x200")
        self.root.configure(bg="#2c3e50")
        
        self.time_label = tk.Label(root, font=("Arial", 48, "bold"),
                                   bg="#2c3e50", fg="#ecf0f1")
        self.time_label.pack(expand=True)
        
        self.date_label = tk.Label(root, font=("Arial", 16),
                                   bg="#2c3e50", fg="#bdc3c7")
        self.date_label.pack()
        
        self.update_time()
    
    def update_time(self):
        now = datetime.now()
        time_string = now.strftime("%H:%M:%S")
        date_string = now.strftime("%Y๋…„ %m์›” %d์ผ %A")
        
        self.time_label.config(text=time_string)
        self.date_label.config(text=date_string)
        
        # 1000ms(1์ดˆ) ํ›„์— ๋‹ค์‹œ ํ˜ธ์ถœ
        self.root.after(1000, self.update_time)

if __name__ == "__main__":
    root = tk.Tk()
    clock = DigitalClock(root)
    root.mainloop()

๐ŸŽจ Canvas ์• ๋‹ˆ๋ฉ”์ด์…˜

import tkinter as tk
import random

class BouncingBall:
    def __init__(self, root):
        self.root = root
        self.root.title("ํŠ€๋Š” ๊ณต ์• ๋‹ˆ๋ฉ”์ด์…˜ โšฝ")
        self.root.geometry("600x500")
        
        self.canvas = tk.Canvas(root, width=600, height=450, bg="#ecf0f1")
        self.canvas.pack(pady=10)
        
        # ๊ณต ์ƒ์„ฑ
        self.ball = self.canvas.create_oval(275, 225, 325, 275, 
                                           fill="#e74c3c", outline="")
        
        # ์†๋„
        self.dx = random.choice([-5, -4, -3, 3, 4, 5])
        self.dy = random.choice([-5, -4, -3, 3, 4, 5])
        
        # ๋ฒ„ํŠผ
        tk.Button(root, text="์‹œ์ž‘/์ •์ง€", command=self.toggle,
                 font=("Arial", 12), bg="#3498db", fg="white",
                 width=15).pack(pady=5)
        
        self.running = False
        self.animate()
    
    def toggle(self):
        self.running = not self.running
    
    def animate(self):
        if self.running:
            # ํ˜„์žฌ ์œ„์น˜ ๊ฐ€์ ธ์˜ค๊ธฐ
            pos = self.canvas.coords(self.ball)
            
            # ๋ฒฝ์— ๋ถ€๋”ชํžˆ๋ฉด ๋ฐฉํ–ฅ ๋ฐ˜์ „
            if pos[0] <= 0 or pos[2] >= 600:
                self.dx = -self.dx
            if pos[1] <= 0 or pos[3] >= 450:
                self.dy = -self.dy
            
            # ๊ณต ์ด๋™
            self.canvas.move(self.ball, self.dx, self.dy)
        
        # 30ms ํ›„์— ๋‹ค์‹œ ํ˜ธ์ถœ (์•ฝ 33 FPS)
        self.root.after(30, self.animate)

if __name__ == "__main__":
    root = tk.Tk()
    app = BouncingBall(root)
    root.mainloop()

์ด๋ ‡๊ฒŒ after()๋ฅผ ์žฌ๊ท€์ ์œผ๋กœ ํ˜ธ์ถœํ•˜๋ฉด ๋ถ€๋“œ๋Ÿฌ์šด ์• ๋‹ˆ๋ฉ”์ด์…˜์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด! ๐ŸŽฌ

๐Ÿ’พ ๋ฐ์ดํ„ฐ ์ €์žฅํ•˜๊ธฐ (JSON ํ™œ์šฉ)

ํ”„๋กœ๊ทธ๋žจ์„ ์ข…๋ฃŒํ•ด๋„ ๋ฐ์ดํ„ฐ๋ฅผ ์œ ์ง€ํ•˜๋ ค๋ฉด ํŒŒ์ผ์— ์ €์žฅํ•ด์•ผ ํ•ด. JSON ํ˜•์‹์„ ์‚ฌ์šฉํ•˜๋ฉด ํŽธ๋ฆฌํ•ด!

import tkinter as tk
from tkinter import messagebox
import json
import os

class TodoApp:
    def __init__(self, root):
        self.root = root
        self.root.title("ํ•  ์ผ ๋ชฉ๋ก ๐Ÿ“")
        self.root.geometry("500x600")
        
        self.filename = "todos.json"
        self.todos = self.load_todos()
        
        self.create_widgets()
        self.refresh_list()
    
    def create_widgets(self):
        # ์ œ๋ชฉ
        tk.Label(self.root, text="ํ•  ์ผ ๋ชฉ๋ก", 
                font=("Arial", 18, "bold")).pack(pady=10)
        
        # ์ž…๋ ฅ ํ”„๋ ˆ์ž„
        input_frame = tk.Frame(self.root)
        input_frame.pack(pady=10, padx=20, fill=tk.X)
        
        self.entry = tk.Entry(input_frame, font=("Arial", 12))
        self.entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 10))
        self.entry.bind("<Return>", lambda e: self.add_todo())
        
        tk.Button(input_frame, text="์ถ”๊ฐ€", command=self.add_todo,
                 bg="#66bb6a", fg="white", font=("Arial", 11),
                 width=8).pack(side=tk.LEFT)
        
        # ๋ฆฌ์ŠคํŠธ๋ฐ•์Šค
        list_frame = tk.Frame(self.root)
        list_frame.pack(pady=10, padx=20, fill=tk.BOTH, expand=True)
        
        scrollbar = tk.Scrollbar(list_frame)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        self.listbox = tk.Listbox(list_frame, font=("Arial", 11),
                                  yscrollcommand=scrollbar.set,
                                  selectmode=tk.SINGLE)
        self.listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.config(command=self.listbox.yview)
        
        # ๋ฒ„ํŠผ ํ”„๋ ˆ์ž„
        button_frame = tk.Frame(self.root)
        button_frame.pack(pady=10)
        
        tk.Button(button_frame, text="์™„๋ฃŒ", command=self.complete_todo,
                 bg="#7c9cbf", fg="white", font=("Arial", 11),
                 width=10).pack(side=tk.LEFT, padx=5)
        
        tk.Button(button_frame, text="์‚ญ์ œ", command=self.delete_todo,
                 bg="#ff6b6b", fg="white", font=("Arial", 11),
                 width=10).pack(side=tk.LEFT, padx=5)
    
    def load_todos(self):
        if os.path.exists(self.filename):
            try:
                with open(self.filename, 'r', encoding='utf-8') as f:
                    return json.load(f)
            except:
                return []
        return []
    
    def save_todos(self):
        with open(self.filename, 'w', encoding='utf-8') as f:
            json.dump(self.todos, f, ensure_ascii=False, indent=2)
    
    def add_todo(self):
        text = self.entry.get().strip()
        if text:
            self.todos.append({"text": text, "completed": False})
            self.save_todos()
            self.refresh_list()
            self.entry.delete(0, tk.END)
        else:
            messagebox.showwarning("๊ฒฝ๊ณ ", "ํ•  ์ผ์„ ์ž…๋ ฅํ•˜์„ธ์š”!")
    
    def complete_todo(self):
        selection = self.listbox.curselection()
        if selection:
            index = selection[0]
            self.todos[index]["completed"] = not self.todos[index]["completed"]
            self.save_todos()
            self.refresh_list()
    
    def delete_todo(self):
        selection = self.listbox.curselection()
        if selection:
            if messagebox.askyesno("ํ™•์ธ", "์ •๋ง๋กœ ์‚ญ์ œํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?"):
                index = selection[0]
                del self.todos[index]
                self.save_todos()
                self.refresh_list()
    
    def refresh_list(self):
        self.listbox.delete(0, tk.END)
        for todo in self.todos:
            text = todo["text"]
            if todo["completed"]:
                text = "โœ“ " + text
            else:
                text = "โ—‹ " + text
            self.listbox.insert(tk.END, text)

if __name__ == "__main__":
    root = tk.Tk()
    app = TodoApp(root)
    root.mainloop()

์ด ํ•  ์ผ ๋ชฉ๋ก ์•ฑ์€ JSON ํŒŒ์ผ์— ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•ด์„œ ํ”„๋กœ๊ทธ๋žจ์„ ๋‹ค์‹œ ์‹คํ–‰ํ•ด๋„ ๋ฐ์ดํ„ฐ๊ฐ€ ์œ ์ง€๋ผ! ๐Ÿ’พ

๐ŸŽ“ ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ๋“ค

๐ŸชŸ Toplevel - ์ƒˆ ์ฐฝ ๋งŒ๋“ค๊ธฐ

๋ฉ”์ธ ์ฐฝ ์™ธ์— ์ถ”๊ฐ€๋กœ ์ฐฝ์„ ๋„์šฐ๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•ด!

import tkinter as tk

def open_settings():
    settings_window = tk.Toplevel(root)
    settings_window.title("์„ค์ •")
    settings_window.geometry("400x300")
    
    tk.Label(settings_window, text="์„ค์ •", 
            font=("Arial", 16, "bold")).pack(pady=20)
    
    tk.Label(settings_window, text="ํ…Œ๋งˆ:").pack(pady=5)
    theme_var = tk.StringVar(value="๋ฐ์Œ")
    tk.Radiobutton(settings_window, text="๋ฐ์Œ", 
                  variable=theme_var, value="๋ฐ์Œ").pack()
    tk.Radiobutton(settings_window, text="์–ด๋‘์›€", 
                  variable=theme_var, value="์–ด๋‘์›€").pack()
    
    tk.Button(settings_window, text="๋‹ซ๊ธฐ", 
             command=settings_window.destroy).pack(pady=20)

root = tk.Tk()
root.title("๋ฉ”์ธ ์ฐฝ")
root.geometry("400x300")

tk.Label(root, text="๋ฉ”์ธ ์ฐฝ", 
        font=("Arial", 16, "bold")).pack(pady=50)

tk.Button(root, text="์„ค์ • ์—ด๊ธฐ", command=open_settings,
         font=("Arial", 12)).pack()

root.mainloop()

๐Ÿ“‘ Notebook - ํƒญ ์ธํ„ฐํŽ˜์ด์Šค

์—ฌ๋Ÿฌ ํŽ˜์ด์ง€๋ฅผ ํƒญ์œผ๋กœ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ์–ด!

import tkinter as tk
from tkinter import ttk

root = tk.Tk()
root.title("Notebook ์˜ˆ์ œ")
root.geometry("600x400")

# Notebook ์ƒ์„ฑ
notebook = ttk.Notebook(root)
notebook.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

# ํƒญ 1
tab1 = tk.Frame(notebook, bg="#e8f5e9")
notebook.add(tab1, text="ํ™ˆ ๐Ÿ ")

tk.Label(tab1, text="ํ™ˆ ํƒญ์ž…๋‹ˆ๋‹ค", font=("Arial", 16, "bold"),
        bg="#e8f5e9").pack(pady=50)
tk.Button(tab1, text="๋ฒ„ํŠผ 1").pack()

# ํƒญ 2
tab2 = tk.Frame(notebook, bg="#fff3e0")
notebook.add(tab2, text="ํ”„๋กœํ•„ ๐Ÿ‘ค")

tk.Label(tab2, text="ํ”„๋กœํ•„ ํƒญ์ž…๋‹ˆ๋‹ค", font=("Arial", 16, "bold"),
        bg="#fff3e0").pack(pady=50)
tk.Entry(tab2, width=30).pack(pady=5)

# ํƒญ 3
tab3 = tk.Frame(notebook, bg="#e3f2fd")
notebook.add(tab3, text="์„ค์ • โš™๏ธ")

tk.Label(tab3, text="์„ค์ • ํƒญ์ž…๋‹ˆ๋‹ค", font=("Arial", 16, "bold"),
        bg="#e3f2fd").pack(pady=50)
tk.Checkbutton(tab3, text="์•Œ๋ฆผ ๋ฐ›๊ธฐ", bg="#e3f2fd").pack()

root.mainloop()

๐ŸŒณ Treeview - ํŠธ๋ฆฌ ๊ตฌ์กฐ ํ‘œ์‹œ

๊ณ„์ธต์  ๋ฐ์ดํ„ฐ๋‚˜ ํ‘œ ํ˜•ํƒœ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ํ‘œ์‹œํ•  ๋•Œ ์œ ์šฉํ•ด!

import tkinter as tk
from tkinter import ttk

root = tk.Tk()
root.title("Treeview ์˜ˆ์ œ")
root.geometry("700x400")

# Treeview ์ƒ์„ฑ
tree = ttk.Treeview(root, columns=("์ด๋ฆ„", "๋‚˜์ด", "์ง์—…"), show="tree headings")
tree.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

# ์—ด ์„ค์ •
tree.heading("#0", text="ID")
tree.heading("์ด๋ฆ„", text="์ด๋ฆ„")
tree.heading("๋‚˜์ด", text="๋‚˜์ด")
tree.heading("์ง์—…", text="์ง์—…")

tree.column("#0", width=100)
tree.column("์ด๋ฆ„", width=150)
tree.column("๋‚˜์ด", width=100)
tree.column("์ง์—…", width=200)

# ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€
tree.insert("", "end", text="001", values=("๊น€์ฒ ์ˆ˜", "30", "๊ฐœ๋ฐœ์ž"))
tree.insert("", "end", text="002", values=("์ด์˜ํฌ", "28", "๋””์ž์ด๋„ˆ"))
tree.insert("", "end", text="003", values=("๋ฐ•๋ฏผ์ˆ˜", "35", "๊ธฐํš์ž"))

# ๊ณ„์ธต ๊ตฌ์กฐ ์˜ˆ์ œ
parent = tree.insert("", "end", text="ํŒ€", values=("๊ฐœ๋ฐœํŒ€", "", ""))
tree.insert(parent, "end", text="004", values=("์ตœ์ง€ํ›ˆ", "27", "์ฃผ๋‹ˆ์–ด ๊ฐœ๋ฐœ์ž"))
tree.insert(parent, "end", text="005", values=("์ •์ˆ˜์ง„", "32", "์‹œ๋‹ˆ์–ด ๊ฐœ๋ฐœ์ž"))

root.mainloop()

๐ŸŽฏ ์‹ค๋ฌด ํŒ๊ณผ ๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค

โœจ ์ฝ”๋“œ ์ž‘์„ฑ ํŒ

1. ํด๋ž˜์Šค ๊ธฐ๋ฐ˜ ๊ตฌ์กฐ ์‚ฌ์šฉํ•˜๊ธฐ
๋ณต์žกํ•œ ํ”„๋กœ๊ทธ๋žจ์€ ํด๋ž˜์Šค๋กœ ๊ตฌ์กฐํ™”ํ•˜๋ฉด ๊ด€๋ฆฌ๊ฐ€ ํ›จ์”ฌ ์‰ฌ์›Œ์ ธ. ์œ„์ ฏ๋“ค์„ ์ธ์Šคํ„ด์Šค ๋ณ€์ˆ˜๋กœ ์ €์žฅํ•˜๊ณ , ๋ฉ”์„œ๋“œ๋กœ ๊ธฐ๋Šฅ์„ ๋ถ„๋ฆฌํ•˜์ž!

2. ๋ ˆ์ด์•„์›ƒ ๊ด€๋ฆฌ์ž ์ผ๊ด€์„ฑ ์œ ์ง€
ํ•œ ์ปจํ…Œ์ด๋„ˆ ์•ˆ์—์„œ๋Š” ํ•˜๋‚˜์˜ ๋ ˆ์ด์•„์›ƒ ๊ด€๋ฆฌ์ž๋งŒ ์‚ฌ์šฉํ•ด. pack(), grid(), place()๋ฅผ ์„ž์–ด ์“ฐ๋ฉด ์•ˆ ๋ผ!

3. ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ๋ถ„๋ฆฌ
lambda ๋Œ€์‹  ๋ณ„๋„์˜ ํ•จ์ˆ˜๋กœ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋งŒ๋“ค๋ฉด ๋””๋ฒ„๊น…์ด ์‰ฌ์›Œ์ ธ.

4. ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ํ•„์ˆ˜
ํŒŒ์ผ ์ž…์ถœ๋ ฅ, ๋„คํŠธ์›Œํฌ ํ†ต์‹  ๋“ฑ์—๋Š” ํ•ญ์ƒ try-except๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•˜์ž!

5. ๋ฆฌ์†Œ์Šค ์ •๋ฆฌ
ํ”„๋กœ๊ทธ๋žจ ์ข…๋ฃŒ ์‹œ ์—ด๋ฆฐ ํŒŒ์ผ์ด๋‚˜ ์—ฐ๊ฒฐ์„ ์ œ๋Œ€๋กœ ๋‹ซ์•„์ฃผ์ž.

๐Ÿ’ก ์„ฑ๋Šฅ ์ตœ์ ํ™” ํŒ

โ€ข ๋ฌด๊ฑฐ์šด ์ž‘์—…์€ ์Šค๋ ˆ๋“œ๋กœ ๋ถ„๋ฆฌํ•ด์„œ GUI๊ฐ€ ๋ฉˆ์ถ”์ง€ ์•Š๊ฒŒ ํ•˜๊ธฐ
โ€ข ์ด๋ฏธ์ง€๋Š” ํ•„์š”ํ•œ ํฌ๊ธฐ๋กœ ๋ฏธ๋ฆฌ ์กฐ์ •ํ•˜๊ธฐ
โ€ข Canvas์— ๋„ˆ๋ฌด ๋งŽ์€ ๊ฐ์ฒด๋ฅผ ๊ทธ๋ฆฌ์ง€ ์•Š๊ธฐ
โ€ข after()์˜ ๊ฐ„๊ฒฉ์„ ๋„ˆ๋ฌด ์งง๊ฒŒ ์„ค์ •ํ•˜์ง€ ์•Š๊ธฐ

๐Ÿš€ ๋” ๋‚˜์•„๊ฐ€๊ธฐ

Tkinter์˜ ๊ธฐ๋ณธ์„ ๋งˆ์Šคํ„ฐํ–ˆ๋‹ค๋ฉด, ์ด์ œ ๋” ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ๋“ค์„ ํƒํ—˜ํ•ด๋ณผ ์ฐจ๋ก€์•ผ! ๐Ÿ—บ๏ธ

๐ŸŽจ ๋‹ค์Œ ๋‹จ๊ณ„ ํ•™์Šต ์ฃผ์ œ

1. ์Šค๋ ˆ๋”ฉ (Threading)
๊ธด ์ž‘์—…์„ ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ์‹คํ–‰ํ•ด์„œ GUI๊ฐ€ ๋ฉˆ์ถ”์ง€ ์•Š๊ฒŒ ๋งŒ๋“ค๊ธฐ

2. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๋™
SQLite๋‚˜ ๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์—ฐ๊ฒฐํ•ด์„œ ๋ฐ์ดํ„ฐ ๊ด€๋ฆฌํ•˜๊ธฐ

3. ๋„คํŠธ์›Œํ‚น
์†Œ์ผ“ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์œผ๋กœ ์ฑ„ํŒ… ํ”„๋กœ๊ทธ๋žจ์ด๋‚˜ ํด๋ผ์ด์–ธํŠธ-์„œ๋ฒ„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋งŒ๋“ค๊ธฐ

4. ์ปค์Šคํ…€ ์œ„์ ฏ
๊ธฐ์กด ์œ„์ ฏ์„ ์ƒ์†๋ฐ›์•„ ๋‚˜๋งŒ์˜ ์œ„์ ฏ ๋งŒ๋“ค๊ธฐ

5. ํŒจํ‚ค์ง•
PyInstaller๋กœ ์‹คํ–‰ ํŒŒ์ผ(.exe) ๋งŒ๋“ค์–ด์„œ ๋ฐฐํฌํ•˜๊ธฐ

๐ŸŽ“ ์žฌ๋Šฅ๋„ท์—์„œ ๋” ๋ฐฐ์šฐ๊ธฐ

Tkinter๋ฅผ ๋ฐฐ์šฐ๋ฉด์„œ ๋ง‰ํžˆ๋Š” ๋ถ€๋ถ„์ด ์žˆ๊ฑฐ๋‚˜, ๋” ์ „๋ฌธ์ ์ธ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์žฌ๋Šฅ๋„ท(https://www.jaenung.net)์„ ํ™œ์šฉํ•ด๋ณด๋Š” ๊ฒƒ๋„ ์ข‹์•„! ๐Ÿ‘จโ€๐Ÿซ

์žฌ๋Šฅ๋„ท์—๋Š” ํŒŒ์ด์ฌ GUI ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์ „๋ฌธ๊ฐ€๋“ค์ด ๋งŽ์ด ์žˆ์–ด์„œ, 1:1 ๊ณผ์™ธ๋‚˜ ํ”„๋กœ์ ํŠธ ๋ฉ˜ํ† ๋ง์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์–ด. ์‹ค๋ฌด์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ณ ๊ธ‰ ๊ธฐ๋ฒ•์ด๋‚˜ ๋””์ž์ธ ํŒจํ„ด์„ ๋ฐฐ์šฐ๊ณ  ์‹ถ๋‹ค๋ฉด ์ „๋ฌธ๊ฐ€์˜ ๋„์›€์„ ๋ฐ›๋Š” ๊ฒŒ ํ›จ์”ฌ ๋น ๋ฅด์ง€!

๋˜ํ•œ ์ž์‹ ์ด Tkinter์— ๋Šฅ์ˆ™ํ•ด์กŒ๋‹ค๋ฉด, ์žฌ๋Šฅ๋„ท์—์„œ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ๊ฐ€๋ฅด์ณ์ฃผ๋ฉด์„œ ์ˆ˜์ต๋„ ์ฐฝ์ถœํ•  ์ˆ˜ ์žˆ์–ด. ์ง€์‹์„ ๋‚˜๋ˆ„๋Š” ๊ฒƒ๋„ ์ •๋ง ๋ณด๋žŒ์ฐฌ ์ผ์ด๊ฑฐ๋“ ! ๐ŸŒŸ

๐ŸŽฌ ๋งˆ๋ฌด๋ฆฌํ•˜๋ฉฐ

์ž, ์—ฌ๊ธฐ๊นŒ์ง€ Tkinter์˜ ๊ธฐ๋ณธ๋ถ€ํ„ฐ ์‹ค์ „ ํ”„๋กœ์ ํŠธ๊นŒ์ง€ ํ•จ๊ป˜ ์‚ดํŽด๋ดค์–ด! ๐ŸŽ‰

์ฒ˜์Œ์—๋Š” ๋ณต์žกํ•ด ๋ณด์ผ ์ˆ˜ ์žˆ์ง€๋งŒ, ํ•˜๋‚˜์”ฉ ๋”ฐ๋ผ ํ•˜๋‹ค ๋ณด๋ฉด ์–ด๋А์ƒˆ ๋ฉ‹์ง„ GUI ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ฒŒ ๋  ๊ฑฐ์•ผ. ์ค‘์š”ํ•œ ๊ฑด **์ง์ ‘ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด๋ณด๋Š” ๊ฒƒ**์ด์•ผ! ๐Ÿ“

Happy Coding! ๐ŸŽจ ๐Ÿš€ ๐Ÿ’ก Keep Learning, Keep Building!

๐ŸŽฏ ํ•ต์‹ฌ ์š”์•ฝ

โœ… Tkinter๋Š” ํŒŒ์ด์ฌ ํ‘œ์ค€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ GUI ํˆดํ‚ท
โœ… ์œ„์ ฏ(Widget)์œผ๋กœ ๋‹ค์–‘ํ•œ UI ์š”์†Œ ๊ตฌ์„ฑ
โœ… pack(), grid(), place()๋กœ ๋ ˆ์ด์•„์›ƒ ๊ด€๋ฆฌ
โœ… ์ด๋ฒคํŠธ ๋ฐ”์ธ๋”ฉ์œผ๋กœ ์‚ฌ์šฉ์ž ์ƒํ˜ธ์ž‘์šฉ ์ฒ˜๋ฆฌ
โœ… ํด๋ž˜์Šค ๊ธฐ๋ฐ˜ ๊ตฌ์กฐ๋กœ ์ฒด๊ณ„์ ์ธ ์ฝ”๋“œ ์ž‘์„ฑ
โœ… ttk ๋ชจ๋“ˆ๋กœ ๋” ํ˜„๋Œ€์ ์ธ ๋””์ž์ธ ๊ตฌํ˜„
โœ… ์‹ค์ „ ํ”„๋กœ์ ํŠธ๋กœ ์‹ค๋ ฅ ํ–ฅ์ƒ

์ด์ œ ๋‹น์‹ ๋„ Tkinter ๋งˆ์Šคํ„ฐ๊ฐ€ ๋  ์ค€๋น„๊ฐ€ ๋˜์—ˆ์–ด! ๐Ÿ’ช ์ž‘์€ ํ”„๋กœ์ ํŠธ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด์„œ ์ ์  ๋ณต์žกํ•œ ํ”„๋กœ๊ทธ๋žจ์œผ๋กœ ๋‚˜์•„๊ฐ€๋ณด์ž. ์‹คํŒจ๋ฅผ ๋‘๋ ค์›Œํ•˜์ง€ ๋ง๊ณ , ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ์นœ๊ตฌ์ฒ˜๋Ÿผ ๋Œ€ํ•˜๋ฉด์„œ ๋ฐฐ์›Œ๋‚˜๊ฐ€๋ฉด ๋ผ!

๊ถ๊ธˆํ•œ ์ ์ด ์žˆ๊ฑฐ๋‚˜ ๋ง‰ํžˆ๋Š” ๋ถ€๋ถ„์ด ์žˆ๋‹ค๋ฉด ๊ณต์‹ ๋ฌธ์„œ(https://docs.python.org/3/library/tkinter.html)๋ฅผ ์ฐธ๊ณ ํ•˜๊ฑฐ๋‚˜, ์ปค๋ฎค๋‹ˆํ‹ฐ์— ์งˆ๋ฌธํ•ด๋ณด์ž. ๊ทธ๋ฆฌ๊ณ  ์žฌ๋Šฅ๋„ท์—์„œ ์ „๋ฌธ๊ฐ€์˜ ๋„์›€์„ ๋ฐ›๋Š” ๊ฒƒ๋„ ์žŠ์ง€ ๋ง๊ณ ! ๐Ÿ˜Š

์ž, ์ด์ œ ๋‹น์‹ ์˜ ์ฐฝ์˜๋ ฅ์„ ๋ฐœํœ˜ํ•ด์„œ ๋ฉ‹์ง„ ํ”„๋กœ๊ทธ๋žจ์„ ๋งŒ๋“ค์–ด๋ณด์ž! ํ™”์ดํŒ…! ๐ŸŽ‰๐Ÿš€

Happy Tkinter Programming! ๐Ÿโœจ

๋Œ“๊ธ€ ์ž‘์„ฑ

์ด ๊ธ€์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ƒ๊ฐ์„ ๋“ค๋ ค์ฃผ์„ธ์š”

๋Œ“๊ธ€ 0
๋Œ“๊ธ€์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘์ž…๋‹ˆ๋‹ค.

์•„์ง ๋Œ“๊ธ€์ด ์—†์Šต๋‹ˆ๋‹ค.