νμ΄μ¬μ μ¬μ΄ λμ΄λμ λΉν΄ GUIλ₯Ό λ§λ€ λλ λ§λ§ν¨μ λλλ€.
κ°μ₯ λ§μ΄ μ¬μ©λλ GUI λΌμ΄λΈλ¬λ¦¬ μ€ νλμΈ tkinterμ pyqtλ μ½κ³ λΉ λ₯΄κ² λ°μ€ν¬ν± μ ν리μΌμ΄μ μ μ¬μ©μ μΈν°νμ΄μ€λ₯Ό ꡬνν μ μλλ‘ λ€μν μμ ―κ³Ό νλ«νΌ κ° νΈνμ±μ μ 곡νλ€.
![]() | ![]() | ![]() |
---|
κ·Έλ¬λ μ΄λ€λ‘ μλ½ν UIλ₯Ό λ§λ€κΈ°μ μλΆμ‘±μ΄λ€. κ·Έλμ λ§€λ² GUI νλ‘μ νΈλ₯Ό λ§‘μ λλ§λ€ μλ‘μ΄ GUI λΌμ΄λΈλ¬λ¦¬λ₯Ό μ°Ύμ ν€λ§€λ μ¬μ μ λ λλ€κ°, κ·Έλ₯ ν¬κΈ°ν΄λ²λ¦° μ λ λΉλ²νλ€.
κΈ΄ μ¬μ λμ, κΈ°μ‘΄μ tkinterμ κ±°μ μ μ¬ν λ°©μμΌλ‘ GUIλ₯Ό μλ½νκ² λ§λ€ μ μλ CustomTkinter
νλ‘μ νΈλ₯Ό μ°Ύκ² λμλ€. λΉκ΅μ μλ‘μ΄ λΌμ΄λΈλ¬λ¦¬μ΄μ§λ§, tkinterμ μ΅μνλ€λ©΄ 곡μ νν 리μΌμ ν΅ν΄ μμ½κ² μ΅ν μ μμ κ²μ΄λ€.
μμ§ κ³΅μ νν 리μΌμ νκ΅μ΄λ‘ λ²μν κΈμ΄ μκΈ°μ, 곡λΆνλ©΄μ μ΄λ₯Ό μ§μ λ²μν΄λ³΄μλ€.
μΆμ²:곡μ ννμ΄μ§
μ€μΉ λ°©λ²κ³Ό λ€μν μμ λ 곡μ ννμ΄μ§μμ νμΈν μ μλ€.
CustomTkinterλ Tkinterλ₯Ό κΈ°λ°μΌλ‘ ν νμ΄μ¬ λ°μ€ν¬ν UI λΌμ΄λΈλ¬λ¦¬λ‘, νλμ μ΄κ³ μμ ν 컀μ€ν°λ§μ΄μ§μ΄ κ°λ₯ν μμ ―μ μ 곡ν©λλ€. CustomTkinterλ₯Ό μ¬μ©νλ©΄ λͺ¨λ λ°μ€ν¬ν νλ«νΌ(Windows, macOS, Linux)μμ μΌκ΄λ UIλ₯Ό ꡬνν μ μμ΅λλ€.
import customtkinter
def button_callback():
print("button clicked")
app = customtkinter.CTk()
app.geometry("400x150")
button = customtkinter.CTkButton(app, text="my button", command=button_callback)
button.pack(padx=20, pady=20)
app.mainloop()
λͺ μ€μ μ½λλ§μΌλ‘λ μμ ν μλνλ νλ‘κ·Έλ¨μ λ§λ€ μ μμ΅λλ€:
CustomTkinterμ 곡μ νν λ¦¬μΌ μΉμ μΌλ‘, λΌμ΄λΈλ¬λ¦¬μ μ£Όμ κΈ°λ₯μ κ°μ‘°νλ μ΄κΈ λ° κ³ κΈ νν 리μΌμ νμΈν μ μμ΅λλ€. μ΄ νν λ¦¬μΌ μΉμ μ λΌμ΄λΈλ¬λ¦¬μ μ 체 κ°μλ₯Ό μ 곡νλ κ²μ΄ λͺ©μ μ μλλ©°, μμΌλ‘ λ λ§μ νν 리μΌμ΄ μΆκ°λ μμ μ λλ€.
그리λ(Grid) μ§μ€λ©νΈλ¦¬ μμ€ν μ μ΅μν΄μ§κ³ , νλ μκ³Ό μ€ν¬λ‘€ κ°λ₯ν νλ μμ λ§λ€κ³ , νλ μμ κΈ°λ°μΌλ‘ μ¬μ¬μ© κ°λ₯ν μ»΄ν¬λνΈλ₯Ό λ§λ€μ΄λ³΄μΈμ.
μ°μ , μ΅μ λ²μ μ CustomTkinterκ° μ€μΉλμ΄ μλμ§ νμΈνμΈμ. κ·Έλ° λ€μ, λ€μκ³Ό κ°μ κ°μ₯ κΈ°λ³Έμ μΈ νλ‘κ·Έλ¨μΌλ‘ μ€μΉκ° μ λλ‘ λμλμ§ ν μ€νΈν μ μμ΅λλ€. μ΄ νλ‘κ·Έλ¨μ λ¨μν μ°½μ λ§λλλ€:
import customtkinter
app = customtkinter.CTk()
app.mainloop()
μ΄ νλ‘κ·Έλ¨μ΄ μ μμ μΌλ‘ μλνλ€λ©΄, μ°½μ μ λͺ©κ³Ό ν¬κΈ°(geometry) λ±μ μμ±μ μ€μ νκ³ λ²νΌμ μΆκ°νκΈ° μμν μ μμ΅λλ€. λͺ¨λ μμ ―μ 첫 λ²μ§Έ λ§€κ°λ³μλ master
λ§€κ°λ³μμ΄λ©°, μ΄ κ²½μ°μλ app
μ΄ λ©λλ€. λν ν€μλ μΈμλ‘λ μ λ¬ν μ μμ΅λλ€(master=app
).
import customtkinter
def button_callback():
print("button pressed")
app = customtkinter.CTk()
app.title("my app")
app.geometry("400x150")
button = customtkinter.CTkButton(app, text="my button", command=button_callback)
button.grid(row=0, column=0, padx=20, pady=20)
app.mainloop()
μ΄ μμ μμλ μμ ―μ μμΉμ ν¨λ©μ μ€μ νκΈ° μν΄ κ·Έλ¦¬λ μ§μ€λ©νΈλ¦¬ κ΄λ¦¬μλ₯Ό μ¬μ©ν©λλ€. place
λ pack
λμ grid
μ§μ€λ©νΈλ¦¬ κ΄λ¦¬μλ₯Ό μ¬μ©νλ κ²μ΄ μ’μ΅λλ€. μ΄λ λ°μνμ΄κ³ νμ₯ κ°λ₯ν μ¬μ©μ μΈν°νμ΄μ€λ₯Ό μ½κ² λ§λ€ μ μκΈ° λλ¬Έμ
λλ€.
그리λλ μ°½ λλ νλ μμ μ΄κ³Ό νμΌλ‘ λλλ©°, λΉ μ΄μ΄λ νμ μλμΌλ‘ μΆμλμ§λ§, κ·Έ μμ λ°°μΉλ μμ ―μ ν¬κΈ°μ λ§μΆ° μ‘°μ λ©λλ€. μ΄μ μμ μμ λ²νΌμ κ°μ΄λ°λ‘ λ°°μΉνλ €λ©΄ 첫 λ²μ§Έ μ΄μ 0μ΄ μλ weight
κ°μ λΆμ¬ν΄μΌ ν©λλ€. κ·Έλ μ§ μμΌλ©΄ μ΄μ΄ λ²νΌμ ν¬κΈ°λ‘ μΆμλ©λλ€(grid_rowconfigure()
λ₯Ό μ¬μ©νμ¬ νλ μ€μ ν μ μμ΅λλ€):
app.grid_columnconfigure(0, weight=1)
μ΄μ μ΄ 0μ΄ weight=1
λ‘ μ€μ λμκΈ° λλ¬Έμ μ°½ μ 체μ κ±Έμ³ νμ₯λ©λλ€. λν, 그리λ μ
κ³Ό λ²νΌμ΄ ν¨κ» νμ₯λλλ‘ νλ €λ©΄ sticky
μΈμλ₯Ό grid
νΈμΆμ μΆκ°ν΄μΌ ν©λλ€:
button.grid(row=0, column=0, padx=20, pady=20, sticky="ew")
μ΄μ λ²νΌμ΄ λμͺ½κ³Ό μμͺ½μ μλ 그리λ μ μ κ³ μ λ©λλ€. μ°½ ν¬κΈ°λ₯Ό μ‘°μ νλ©΄ 그리λ μ κ³Ό λ²νΌ ν¬κΈ°κ° μλμΌλ‘ μ‘°μ λλ κ²μ λ³Ό μ μμ΅λλ€.
λ μ΄μμμ μ‘°κΈ λ 볡μ‘νκ² λ§λ€κΈ° μν΄ λ λ²μ§Έ νμ λ κ°μ 체ν¬λ°μ€λ₯Ό μΆκ°ν΄λ³΄κ² μ΅λλ€:
checkbox_1 = customtkinter.CTkCheckBox(app, text="checkbox 1")
checkbox_1.grid(row=1, column=0, padx=20, pady=(0, 20), sticky="w")
checkbox_2 = customtkinter.CTkCheckBox(app, text="checkbox 2")
checkbox_2.grid(row=1, column=1, padx=20, pady=(0, 20), sticky="w")
μ¬κΈ°μ pady
μΈμλ ννμ λ°μ΅λλ€. μ΄ ννμ μμͺ½μλ 0, μλμͺ½μλ 20μ ν¨λ©μ μ€μ νλ€λ λ»μ
λλ€. λν 체ν¬λ°μ€λ 그리λ μ
μ μμͺ½μλ§ κ³ μ λ©λλ€. λ²νΌμ΄ λ€μ μ°½ μ 체μ κ±Έμ³ νμ₯λλλ‘ νλ €λ©΄ columnspan=2
λ₯Ό μ€μ ν΄μΌ ν©λλ€(rowspan
μ νμ μ μ©λ©λλ€).
button.grid(row=0, column=0, padx=20, pady=20, sticky="ew", columnspan=2)
κ·Έλ¦¬κ³ μ²΄ν¬λ°μ€λ₯Ό λμΌν κ°κ²©μΌλ‘ λ°°μΉνλ €λ©΄ λ μ΄ λͺ¨λ λμΌν weight
κ°μ μ€μΌ ν©λλ€:
app.grid_columnconfigure((0, 1), weight=1)
μ΄μ μ 체 νλ‘κ·Έλ¨μ λ€μκ³Ό κ°μ΄ 보μ λλ€:
def button_callback():
print("button pressed")
app = customtkinter.CTk()
app.title("my app")
app.geometry("400x150")
app.grid_columnconfigure((0), weight=1)
button = customtkinter.CTkButton(app, text="my button", command=button_callback)
button.grid(row=0, column=0, padx=20, pady=20, sticky="ew", columnspan=2)
checkbox_1 = customtkinter.CTkCheckBox(app, text="checkbox 1")
checkbox_1.grid(row=1, column=0, padx=20, pady=(0, 20), sticky="w")
checkbox_2 = customtkinter.CTkCheckBox(app, text="checkbox 2")
checkbox_2.grid(row=1, column=1, padx=20, pady=(0, 20), sticky="w")
app.mainloop()
λ§μ§λ§μΌλ‘, μ΄ νλ‘κ·Έλ¨μ ν΄λμ€ κ΅¬μ‘°λ‘ μ¬κ΅¬μ±ν΄λ³΄κ² μ΅λλ€. CTk
μμ μμλ°μ ν΄λμ€λ CTkFrame
μ μ¬μ©νλ κ²μ΄ μ½λμ κ°λ
μ±μ λμ΄κ³ νμ₯μ±μ μ½κ² λ§λλ λ° λμμ΄ λκΈ° λλ¬Έμ κΆμ₯λ©λλ€. ν΄λμ€λ₯Ό μ¬μ©νλ©΄ μ½λλ₯Ό μ¬λ¬ νμΌλ‘ λλκΈ°λ μ¬μμ§λλ€.
μ£Όμ: μκ·λͺ¨ νλ‘κ·Έλ¨μ΄λ ν μ€νΈκ° μλλΌλ©΄, νμ
CTk
,CTkToplevel
,CTkFrame
μ λν΄ λ³λμ ν΄λμ€λ₯Ό μμ±νμΈμ. ν΄λμ€λ₯Ό μ¬μ©νμ§ μκ³ λ§μ UI μ½λλ₯Ό ν νμΌμ μμ±νλ κ²μ μ½κΈ° νλ€κ³ μ’μ§ μμ μ½λ© μ€νμΌμ λλ€.
class App(customtkinter.CTk):
def __init__(self):
super().__init__()
self.title("my app")
self.geometry("400x150")
self.grid_columnconfigure((0, 1), weight=1)
self.button = customtkinter.CTkButton(self, text="my button", command=self.button_callback)
self.button.grid(row=0, column=0, padx=20, pady=20, sticky="ew", columnspan=2)
self.checkbox_1 = customtkinter.CTkCheckBox(self, text="checkbox 1")
self.checkbox_1.grid(row=1, column=0, padx=20, pady=(0, 20), sticky="w")
self.checkbox_2 = customtkinter.CTkCheckBox(self, text="checkbox 2")
self.checkbox_2.grid(row=1, column=1, padx=20, pady=(0, 20), sticky="w")
def button_callback(self):
print("button pressed")
app = App()
app.mainloop()
μ΄μ νλ‘κ·Έλ¨μ ν΄λμ€λ‘ ꡬ쑰νλμ΄ λμ± νμ₯ κ°λ₯νκ³ , μ μ§λ³΄μνκΈ°λ μ¬μμ‘μ΅λλ€.
μΈνΈλ‘μ μ μ¬ν μμ λ‘ μμνμ¬, λ²νΌκ³Ό λͺ κ°μ 체ν¬λ°μ€κ° ν¬ν¨λ μ°½μ λ§λ€μ΄ λ΄ μλ€:
class App(customtkinter.CTk):
def __init__(self):
super().__init__()
self.title("my app")
self.geometry("400x180")
self.grid_columnconfigure(0, weight=1)
self.grid_rowconfigure((0, 1), weight=1)
self.checkbox_1 = customtkinter.CTkCheckBox(self, text="checkbox 1")
self.checkbox_1.grid(row=0, column=0, padx=10, pady=(10, 0), sticky="w")
self.checkbox_2 = customtkinter.CTkCheckBox(self, text="checkbox 2")
self.checkbox_2.grid(row=1, column=0, padx=10, pady=(10, 0), sticky="w")
self.button = customtkinter.CTkButton(self, text="my button", command=self.button_callback)
self.button.grid(row=3, column=0, padx=10, pady=10, sticky="ew")
def button_callback(self):
print("button pressed")
app = App()
app.mainloop()
λ§μ½ 2νμ 체ν¬λ°μ€λ₯Ό νλ λ μΆκ°νλ €κ³ νλ€λ©΄, λ²νΌμ ν λ²νΈλ λ³κ²½ν΄μΌ ν©λλ€. μ΄μ²λΌ λ μ΄μμ λ³κ²½μ΄ νμν κ²½μ°, μν₯μ μ€μ΄κΈ° μν΄ νλ μμ μ¬μ©νμ¬ κ΅¬μ‘°λ₯Ό μ 리ν©λλ€.
νλ μμ 0νμ, λ²νΌμ 1νμ λ°°μΉνκ³ , 0νκ³Ό 0μ΄μ΄ νμ₯λλλ‘ μ€μ ν©λλ€. νλ μμλ sticky
λ§€κ°λ³μλ₯Ό 'nsw'
λ‘ μ€μ νμ¬ μ
μμ λΆμͺ½, λ¨μͺ½, μμͺ½μΌλ‘ νμ₯λκ² ν©λλ€. μ΄μ 체ν¬λ°μ€μ master
μΈμλ self
λμ νλ μμ΄ λ©λλ€.
class App(customtkinter.CTk):
def __init__(self):
super().__init__()
self.title("my app")
self.geometry("400x180")
self.grid_columnconfigure(0, weight=1)
self.grid_rowconfigure(0, weight=1)
self.checkbox_frame = customtkinter.CTkFrame(self)
self.checkbox_frame.grid(row=0, column=0, padx=10, pady=(10, 0), sticky="nsw")
self.checkbox_1 = customtkinter.CTkCheckBox(self.checkbox_frame, text="checkbox 1")
self.checkbox_1.grid(row=0, column=0, padx=10, pady=(10, 0), sticky="w")
self.checkbox_2 = customtkinter.CTkCheckBox(self.checkbox_frame, text="checkbox 2")
self.checkbox_2.grid(row=1, column=0, padx=10, pady=(10, 0), sticky="w")
self.button = customtkinter.CTkButton(self, text="my button", command=self.button_callback)
self.button.grid(row=3, column=0, padx=10, pady=10, sticky="ew")
def button_callback(self):
print("button pressed")
κ·Έλ¦¬κ³ μ½λμ λ μ΄μμμ λ°μνκ³ , μλμμ μΈκΈλ νμ ν΄λμ€λ₯Ό μ¬μ©νλ μμΉμ λ°λ₯΄κΈ° μν΄, νλ μκ³Ό 체ν¬λ°μ€ μ½λλ₯Ό λ³λμ ν΄λμ€λ‘ μ΄λν κ²μ
λλ€. μ΄ ν΄λμ€λ CTkFrame
μ μμνλ©°, λ©μΈ App
ν΄λμ€μμ μ΄ ν΄λμ€μ μΈμ€ν΄μ€κ° μμ±λ©λλ€. __init__
λ©μλμλ master
μΈμλ§ μ λ¬λμ΄, μμ ν΄λμ€μΈ CTkFrame
μ __init__
μ μ λ¬λ μ μλλ‘ ν κ²μ
λλ€.
class MyCheckboxFrame(customtkinter.CTkFrame):
def __init__(self, master):
super().__init__(master)
self.checkbox_1 = customtkinter.CTkCheckBox(self, text="checkbox 1")
self.checkbox_1.grid(row=0, column=0, padx=10, pady=(10, 0), sticky="w")
self.checkbox_2 = customtkinter.CTkCheckBox(self, text="checkbox 2")
self.checkbox_2.grid(row=1, column=0, padx=10, pady=(10, 0), sticky="w")
class App(customtkinter.CTk):
def __init__(self):
super().__init__()
self.title("my app")
self.geometry("400x180")
self.grid_columnconfigure(0, weight=1)
self.grid_rowconfigure(0, weight=1)
self.checkbox_frame = MyCheckboxFrame(self)
self.checkbox_frame.grid(row=0, column=0, padx=10, pady=(10, 0), sticky="nsw")
self.button = customtkinter.CTkButton(self, text="my button", command=self.button_callback)
self.button.grid(row=3, column=0, padx=10, pady=10, sticky="ew")
def button_callback(self):
print("button pressed")
app = App()
app.mainloop()
μ΄μ MyCheckboxFrame
ν΄λμ€μ 체ν¬λ°μ€λ₯Ό μΆκ°ν΄λ λ²νΌμ λ μ΄μμμλ μν₯μ μ£Όμ§ μμ΅λλ€.
class MyCheckboxFrame(customtkinter.CTkFrame):
def __init__(self, master):
super().__init__(master)
self.checkbox_1 = customtkinter.CTkCheckBox(self, text="checkbox 1")
self.checkbox_1.grid(row=0, column=0, padx=10, pady=(10, 0), sticky="w")
self.checkbox_2 = customtkinter.CTkCheckBox(self, text="checkbox 2")
self.checkbox_2.grid(row=1, column=0, padx=10, pady=(10, 0), sticky="w")
self.checkbox_3 = customtkinter.CTkCheckBox(self, text="checkbox 3")
self.checkbox_3.grid(row=2, column=0, padx=10, pady=(10, 0), sticky="w")
λ¬Όλ‘ λ©μΈ App
ν΄λμ€μμ 체ν¬λ°μ€μ κ°μ μ½μ μ μλ λ°©λ²μ΄ νμν©λλ€. λ°λΌμ MyCheckboxFrame
ν΄λμ€μ get
λ©μλλ₯Ό ꡬννμ¬, 체ν¬λ 체ν¬λ°μ€μ text
μμ±μ λ¬Έμμ΄ λ¦¬μ€νΈλ‘ λ°ννλλ‘ ν κ²μ
λλ€.
class MyCheckboxFrame(customtkinter.CTkFrame):
def __init__(self, master):
super().__init__(master)
self.checkbox_1 = customtkinter.CTkCheckBox(self, text="checkbox 1")
self.checkbox_1.grid(row=0, column=0, padx=10, pady=(10, 0), sticky="w")
self.checkbox_2 = customtkinter.CTkCheckBox(self, text="checkbox 2")
self.checkbox_2.grid(row=1, column=0, padx=10, pady=(10, 0), sticky="w")
self.checkbox_3 = customtkinter.CTkCheckBox(self, text="checkbox 3")
self.checkbox_3.grid(row=2, column=0, padx=10, pady=(10, 0), sticky="w")
def get(self):
checked_checkboxes = []
if self.checkbox_1.get() == 1:
checked_checkboxes.append(self.checkbox_1.cget("text"))
if self.checkbox_2.get() == 1:
checked_checkboxes.append(self.checkbox_2.cget("text"))
if self.checkbox_3.get() == 1:
checked_checkboxes.append(self.checkbox_3.cget("text"))
return checked_checkboxes
App
ν΄λμ€μ button_callback
λ©μλμμ μ΄ λ©μλλ₯Ό μ¬μ©νμ¬ μ²΄ν¬λ 체ν¬λ°μ€ λͺ©λ‘μ μΆλ ₯ν μ μμ΅λλ€.
def button_callback(self):
print("checked checkboxes:", self.checkbox_frame.get())
μ΄μ λ²νΌμ λλ₯΄λ©΄, λ€μκ³Ό κ°μ μ νλ 체ν¬λ°μ€μ λͺ©λ‘μ΄ μΆλ ₯λλ κ²μ νμΈν μ μμ΅λλ€.
checked checkboxes: ['checkbox 1', 'checkbox 3']
νμ§λ§ νμ¬ MyCheckboxFrame
μ 체ν¬λ°μ€ κ°λ€μ μ½λμ νλμ½λ©λμ΄ μμ΅λλ€. MyCheckboxFrame
ν΄λμ€λ₯Ό λ³΄λ€ λμ μΌλ‘ μ¬μ©ν μ μλλ‘, 체ν¬λ°μ€μ text
κ°μ΄ λ λ¬Έμμ΄ λ¦¬μ€νΈλ₯Ό MyCheckboxFrame
μ μ λ¬ν κ²μ
λλ€. μ΄μ 체ν¬λ°μ€μ κ°μλ μμλ‘ μ€μ ν μ μμ΅λλ€.
class MyCheckboxFrame(customtkinter.CTkFrame):
def __init__(self, master, values):
super().__init__(master)
self.values = values
self.checkboxes = []
for i, value in enumerate(self.values):
checkbox = customtkinter.CTkCheckBox(self, text=value)
checkbox.grid(row=i, column=0, padx=10, pady=(10, 0), sticky="w")
self.checkboxes.append(checkbox)
def get(self):
checked_checkboxes = []
for checkbox in self.checkboxes:
if checkbox.get() == 1:
checked_checkboxes.append(checkbox.cget("text"))
return checked_checkboxes
체ν¬λ°μ€λ€μ for
루νμμ μμ±λμ΄ checkboxes
λΌλ 리μ€νΈμ μ μ₯λ©λλ€. get
λ©μλμμλ μ΄ λ¦¬μ€νΈλ₯Ό λ°λ³΅νμ¬ μ΄λ€ 체ν¬λ°μ€κ° μ νλμλμ§ νμΈνκ³ , ν΄λΉ text
κ°μ λ°νν μ μμ΅λλ€. μ΄μ MyCheckboxFrame
μ μΈμ€ν΄μ€λ₯Ό μμ±νλ App
ν΄λμ€μμλ κ° λ¦¬μ€νΈλ₯Ό μ λ¬ν΄μΌ ν©λλ€.
self.checkbox_frame = MyCheckboxFrame(self, values=["value 1", "value 2", "value 3"])
self.checkbox_frame.grid(row=0, column=0, padx=10, pady=(10, 0), sticky="nsw")
μ΄μ 체ν¬λ°μ€μ κ°μ λμ μΌλ‘ μ μ΄ν μ μκ² λμμΌλ―λ‘, MyCheckboxFrame
ν΄λμ€μ μΈμ€ν΄μ€λ₯Ό λ κ° μ΄μ λ§€μ° μ½κ² μμ±ν μ μμ΅λλ€. λ²νΌμλ columnspan
μ 2λ‘ μ§μ νκ³ , 1λ² μ΄μ κ°μ€μΉ 1μ μΆκ°ν΄μΌ ν©λλ€.
class App(customtkinter.CTk):
def __init__(self):
super().__init__()
self.title("my app")
self.geometry("400x180")
self.grid_columnconfigure((0, 1), weight=1)
self.grid_rowconfigure(0, weight=1)
self.checkbox_frame_1 = MyCheckboxFrame(self, values=["value 1", "value 2", "value 3"])
self.checkbox_frame_1.grid(row=0, column=0, padx=10, pady=(10, 0), sticky="nsew")
self.checkbox_frame_2 = MyCheckboxFrame(self, values=["option 1", "option 2"])
self.checkbox_frame_2.grid(row=0, column=1, padx=(0, 10), pady=(10, 0), sticky="nsew")
self.button = customtkinter.CTkButton(self, text="my button", command=self.button_callback)
self.button.grid(row=3, column=0, padx=10, pady=10, sticky="ew", columnspan=2)
def button_callback(self):
print("checkbox_frame_1:", self.checkbox_frame_1.get())
print("checkbox_frame_2:", self.checkbox_frame_2.get())
λ²νΌμ λλ μ λμ μΆλ ₯:
checkbox_frame_1: ['value 1', 'value 3']
checkbox_frame_2: ['option 2']
MyCheckboxFrame
ν΄λμ€μ νλ μμ μ λͺ© μν μ νλ λ μ΄λΈμ μΆκ°νμ¬ λμ± ν₯μμν¬ μ μμ΅λλ€.
class MyCheckboxFrame(customtkinter.CTkFrame):
def __init__(self, master, title, values):
super().__init__(master)
self.grid_columnconfigure(0, weight=1)
self.values = values
self.title = title
self.checkboxes = []
self.title = customtkinter.CTkLabel(self, text=self.title, fg_color="gray30", corner_radius=6)
self.title.grid(row=0, column=0, padx=10, pady=(10, 0), sticky="ew")
for i, value in enumerate(self.values):
checkbox = customtkinter.CTkCheckBox(self, text=value)
checkbox.grid(row=i+1, column=0, padx=10, pady=(10, 0), sticky="w")
self.checkboxes.append(checkbox)
def get(self):
checked_checkboxes = []
for checkbox in self.checkboxes:
if checkbox.get() == 1:
checked_checkboxes.append(checkbox.cget("text"))
return checked_checkboxes
μ΄μ νλ μ λ΄λΆμ 0λ² μ΄μ κ°μ€μΉ 1μ΄ μ€μ λμ΄ μμΌλ―λ‘, λ μ΄λΈμ sticky
κ°μ 'ew'
λ‘ μ§μ νμ¬ λ μ΄λΈμ΄ νλ μ μ 체μ κ±Έμ³ νμ₯λ©λλ€. CTkLabel
μλ fg_color
μ corner_radius
μΈμλ₯Ό μ λ¬νλλ°, κΈ°λ³Έμ μΌλ‘ λ μ΄λΈμ΄ 'ν¬λͺ
'μ΄λ©° corner_radius
κ°μ΄ 0μ΄κΈ° λλ¬Έμ
λλ€. λν, 첫 λ²μ§Έ νμ μ λͺ© λ μ΄λΈμ΄ μΆκ°λμκΈ° λλ¬Έμ 그리λ ν μμΉλ μ΄μ i+1
μ΄ λ©λλ€.
μ΄μ App
ν΄λμ€μμ MyCheckboxFrame
μΈμ€ν΄μ€λ₯Ό μμ±ν λ μ λͺ©μ ν΄λΉνλ title
λ§€κ°λ³μμ κ°μ μ λ¬ν΄μΌ ν©λλ€.
self.checkbox_frame_1 = MyCheckboxFrame(self, "Values", values=["value 1", "value 2", "value 3"])
self.checkbox_frame_2 = MyCheckboxFrame(self, "Options", values=["option 1", "option 2"])
μ°½μ λμ΄λ₯Ό 220pxλ‘ μ¦κ°μν€λ©΄ λ€μκ³Ό κ°μ κ²°κ³Όλ₯Ό μ»μ΅λλ€:
μ΄μ 체ν¬λ°μ€ νλ μμ μ λͺ©μ΄ μκ²Όμ΅λλ€. κ·Έλ¦¬κ³ MyCheckboxFrame
μ CTkFrame
μ μμνλ―λ‘, μλ₯Ό λ€μ΄ ν¬λͺ
ν fg_color
μ κ°μ΄ CTkFrame
μ²λΌ ꡬμ±ν μ μμ΅λλ€.
self.checkbox_frame_2.configure(fg_color="transparent")
MyCheckboxFrame
κ³Ό μ μ¬νκ², 체ν¬λ°μ€ λμ λΌλμ€ λ²νΌμΌλ‘ ꡬμ±λ MyRadiobuttonFrame
μ λ§λ€ μ μμ΅λλ€.
class MyRadiobuttonFrame(customtkinter.CTkFrame):
def __init__(self, master, title, values):
super().__init__(master)
self.grid_columnconfigure(0, weight=1)
self.values = values
self.title = title
self.radiobuttons = []
self.variable = customtkinter.StringVar(value="")
self.title = customtkinter.CTkLabel(self, text=self.title, fg_color="gray30", corner_radius=6)
self.title.grid(row=0, column=0, padx=10, pady=(10, 0), sticky="ew")
for i, value in enumerate(self.values):
radiobutton = customtkinter.CTkRadioButton(self, text=value, value=value, variable=self.variable)
radiobutton.grid(row=i + 1, column=0, padx=10, pady=(10, 0), sticky="w")
self.radiobuttons.append(radiobutton)
def get(self):
return self.variable.get()
def set(self, value):
self.variable.set(value)
κ·Έλ¦¬κ³ App
μμ MyCheckboxFrame
κ³Ό μ μ¬νκ² MyRadiobuttonFrame
μ μΈμ€ν΄μ€λ₯Ό μμ±ν©λλ€.
class App(customtkinter.CTk):
def __init__(self):
super().__init__()
self.title("my app")
self.geometry("400x220")
self.grid_columnconfigure((0, 1), weight=1)
self.grid_rowconfigure(0, weight=1)
self.checkbox_frame = MyCheckboxFrame(self, "Values", values=["value 1", "value 2", "value 3"])
self.checkbox_frame.grid(row=0, column=0, padx=10, pady=(10, 0), sticky="nsew")
self.radiobutton_frame = MyRadiobuttonFrame(self, "Options", values=["option 1", "option 2"])
self.radiobutton_frame.grid(row=0, column=1, padx=(0, 10), pady=(10, 0), sticky="nsew")
self.button = customtkinter.CTkButton(self, text="my button", command=self.button_callback)
self.button.grid(row=3, column=0, padx=10, pady=10, sticky="ew", columnspan=2)
def button_callback(self):
print("checkbox_frame:", self.checkbox_frame.get())
print("radiobutton_frame:", self.radiobutton_frame.get())
μ΄μ μ¬μ©μλ‘λΆν° μ λ ₯μ λ°μ μ μλ λ κ°μ λμ μΌλ‘ μμ±λ μλ‘ λ€λ₯Έ νλ μμ΄ μκ²Όμ΅λλ€.
μ΄μ μ±ν°μμ μ°λ¦¬λ μ£Όμ΄μ§ κ° λͺ©λ‘μ λν΄ μ²΄ν¬λ°μ€λ₯Ό μμ±νλ λ€μ νλ μμ λ§λ€μμ΅λλ€.
class MyCheckboxFrame(customtkinter.CTkFrame):
def __init__(self, master, values):
super().__init__(master)
self.values = values
self.checkboxes = []
for i, value in enumerate(self.values):
checkbox = customtkinter.CTkCheckBox(self, text=value)
checkbox.grid(row=i, column=0, padx=10, pady=(10, 0), sticky="w")
self.checkboxes.append(checkbox)
def get(self):
checked_checkboxes = []
for checkbox in self.checkboxes:
if checkbox.get() == 1:
checked_checkboxes.append(checkbox.cget("text"))
return checked_checkboxes
λ μ΄μμμ΄λ νλ©΄μ 곡κ°μ΄ λΆμ‘±νμ¬ λ λ§μ 체ν¬λ°μ€λ₯Ό νμνλ €λ©΄, μ€ν¬λ‘€ κ°λ₯ν νλ μμ μ¬μ©ν μ μμ΅λλ€. CTkScrollableFrame
μ μ€ν¬λ‘€λ°λ₯Ό μλμΌλ‘ μΆκ°νμ¬ νλ μ λ΄λΆμ μ€μ λ‘ λ€μ΄κ°λ κ²λ³΄λ€ λ λ§μ μμ ―μ μΆκ°ν μ μκ² ν΄μ€λλ€. νλ μμ λ΄λΆ μμ ―μ΄ λμ΄λλλΌλ νμ₯λμ§ μμ΅λλ€. CTkScrollableFrame
μλ μ λͺ© μ΅μ
λ μμ΄μ, label_text
μΈμλ₯Ό ν΅ν΄ μμ μμ μμ μλμΌλ‘ λ§λ κ²μ²λΌ μ λͺ© λ μ΄λΈμ λν ν
μ€νΈλ₯Ό μ λ¬ν μ μμ΅λλ€.
class MyScrollableCheckboxFrame(customtkinter.CTkScrollableFrame):
def __init__(self, master, title, values):
super().__init__(master, label_text=title)
self.grid_columnconfigure(0, weight=1)
self.values = values
self.checkboxes = []
for i, value in enumerate(self.values):
checkbox = customtkinter.CTkCheckBox(self, text=value)
checkbox.grid(row=i, column=0, padx=10, pady=(10, 0), sticky="w")
self.checkboxes.append(checkbox)
def get(self):
checked_checkboxes = []
for checkbox in self.checkboxes:
if checkbox.get() == 1:
checked_checkboxes.append(checkbox.cget("text"))
return checked_checkboxes
μ΄μ App
ν΄λμ€μμ MyScrollableCheckboxFrame
μ μΈμ€ν΄μ€λ₯Ό μμ±νκ³ λ λ§μ κ°μ μΆκ°νμ¬ μ€ν¬λ‘€λ° κΈ°λ₯μ ν
μ€νΈν μ μμ΅λλ€.
class App(customtkinter.CTk):
def __init__(self):
super().__init__()
self.title("my app")
self.geometry("400x220")
self.grid_columnconfigure(0, weight=1)
self.grid_rowconfigure(0, weight=1)
values = ["value 1", "value 2", "value 3", "value 4", "value 5", "value 6"]
self.scrollable_checkbox_frame = MyScrollableCheckboxFrame(self, title="Values", values=values)
self.scrollable_checkbox_frame.grid(row=0, column=0, padx=10, pady=(10, 0), sticky="nsew")
self.button = customtkinter.CTkButton(self, text="my button", command=self.button_callback)
self.button.grid(row=3, column=0, padx=10, pady=10, sticky="ew", columnspan=2)
def button_callback(self):
print("checkbox_frame:", self.checkbox_frame.get())
print("radiobutton_frame:", self.radiobutton_frame.get())
app = App()
app.mainloop()
μ€ν¬λ‘€ κ°λ₯ν νλ μμ λν λ λ§μ μμ λ GitHubμ λ€μ μμ νλ‘κ·Έλ¨μμ μ°Ύμ μ μμ΅λλ€: https://github.com/TomSchimansky/CustomTkinter/blob/master/examples/scrollable_frame_example.py
μ μμ ―μ λ§λ€κ³ λ 볡μ‘ν UIλ₯Ό ꡬμ±νλ λ°©λ²μ λν κ³ κΈ νν 리μΌμ λλ€.
CustomTkinterμ ꡬνλμ§ μμ κΈ°λ₯μ΄ νμν΄μ μ§μ μλ‘μ΄ μμ ―μ λ§λ€κ³ μ νλ€λ©΄, μ½κ² ν μ μμ΅λλ€. μλμμλ float κ°μ κΈ°λ°μΌλ‘ ν Spinbox
λ₯Ό μμ±νλ μμ λ₯Ό 보μ¬λλ¦¬κ² μ΅λλ€.
λ¨Όμ customtkinter.CTkFrame
μ μμνλ μλ‘μ΄ ν΄λμ€λ₯Ό μμ±ν©λλ€.
import customtkinter
class WidgetName(customtkinter.CTkFrame):
def __init__(self, *args,
width: int = 100,
height: int = 32,
**kwargs):
super().__init__(*args, width=width, height=height, **kwargs)
μ΄λ κ² νλ©΄ κΈ°λ³Έμ μΌλ‘ width
μ height
μμ±μ κΈ°λ³Έκ°μ μν΄ μ§μ λ ν¬κΈ°λ₯Ό κ°μ§ μμ ―μ΄ μμ±λ©λλ€. λν fg_color
λ corner_radius
μ κ°μ CTkFrame
μ λͺ¨λ μμ±λ μ§μν©λλ€.
float κΈ°λ°μ μ€νλ°μ€λ₯Ό κ°λ¨νκ² κ΅¬νν μμλ λ€μκ³Ό κ°μ μ μμ΅λλ€.
class FloatSpinbox(customtkinter.CTkFrame):
def __init__(self, *args,
width: int = 100,
height: int = 32,
step_size: Union[int, float] = 1,
command: Callable = None,
**kwargs):
super().__init__(*args, width=width, height=height, **kwargs)
self.step_size = step_size
self.command = command
self.configure(fg_color=("gray78", "gray28")) # set frame color
self.grid_columnconfigure((0, 2), weight=0) # buttons don't expand
self.grid_columnconfigure(1, weight=1) # entry expands
self.subtract_button = customtkinter.CTkButton(self, text="-", width=height-6, height=height-6,
command=self.subtract_button_callback)
self.subtract_button.grid(row=0, column=0, padx=(3, 0), pady=3)
self.entry = customtkinter.CTkEntry(self, width=width-(2*height), height=height-6, border_width=0)
self.entry.grid(row=0, column=1, columnspan=1, padx=3, pady=3, sticky="ew")
self.add_button = customtkinter.CTkButton(self, text="+", width=height-6, height=height-6,
command=self.add_button_callback)
self.add_button.grid(row=0, column=2, padx=(0, 3), pady=3)
# default value
self.entry.insert(0, "0.0")
def add_button_callback(self):
if self.command is not None:
self.command()
try:
value = float(self.entry.get()) + self.step_size
self.entry.delete(0, "end")
self.entry.insert(0, value)
except ValueError:
return
def subtract_button_callback(self):
if self.command is not None:
self.command()
try:
value = float(self.entry.get()) - self.step_size
self.entry.delete(0, "end")
self.entry.insert(0, value)
except ValueError:
return
def get(self) -> Union[float, None]:
try:
return float(self.entry.get())
except ValueError:
return None
def set(self, value: float):
self.entry.delete(0, "end")
self.entry.insert(0, str(float(value)))
λ¬Όλ‘ configure
λ©μλλ __init__
λ©μλμμ μμμ μ€μ ν μ μλ λ λ§μ μμ±μ μΆκ°ν μλ μμ΅λλ€.
νμ§λ§ μ ꡬνμ ν΅ν΄ μ€νλ°μ€λ₯Ό λ€μκ³Ό κ°μ΄ μ¬μ©ν μ μμ΅λλ€.
app = customtkinter.CTk()
spinbox_1 = FloatSpinbox(app, width=150, step_size=3)
spinbox_1.pack(padx=20, pady=20)
spinbox_1.set(35)
print(spinbox_1.get())
app.mainloop()
μ κ° μ°Ύλ CustomTkinter 곡μ νν λ¦¬μΌ λ²μλ³Έ μ¬κΈ° μμλ€μ. κ°μ¬ν©λλ€π
GUIλ λ§λμλκ΅°μ!! νμ€ν κΈ°μ‘΄ Tkinterλ³΄λ€ μμ κ² κ°μ΅λλ€γ γ λμ€μ λ§λ€ κΈ°νκ° μκΈ°λ©΄ λ―Όν€ κ³΅μ£Όλμ νν 리μΌμ μ°Έκ³ νκ² μ΅λλ€!!