๐ŸŽฒ DiceForge ๋งŒ๋“ค๊ธฐ: Python ๋ฐ Tkinter๋ฅผ ํ™œ์šฉํ•œ ํ˜„๋Œ€์ ์ธ ์ฃผ์‚ฌ์œ„ ๊ตด๋ฆผ ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ

๋ฐœํ–‰: (2026๋…„ 1์›” 5์ผ ์˜คํ›„ 01:46 GMT+9)
6 min read
์›๋ฌธ: Dev.to

Source: Dev.to

Dice Rolling Simulator

ํ…Œ์ด๋ธ”ํƒ‘ ๊ฒŒ์ž„, ํ™•๋ฅ  ์‹คํ—˜, ํ˜น์€ ๋‹จ์ˆœํžˆ ์žฌ๋ฏธ๋ฅผ ์œ„ํ•ด ์ฃผ์‚ฌ์œ„๋ฅผ ๋น ๋ฅด๊ฒŒ ๊ตด๋ ค์•ผ ํ•  ๋•Œ, ์ง์ ‘ ์ฃผ์‚ฌ์œ„ ๊ตด๋ฆผ๊ธฐ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ ํ›Œ๋ฅญํ•œ ์ฃผ๋ง ํ”„๋กœ์ ํŠธ๊ฐ€ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฒˆ ํฌ์ŠคํŠธ์—์„œ๋Š” Python, Tkinter, ๊ทธ๋ฆฌ๊ณ  ttk ๋กœ ์ œ์ž‘๋œ ์„ธ๋ จ๋œ ์ฃผ์‚ฌ์œ„ ๊ตด๋ฆผ ์‹œ๋ฎฌ๋ ˆ์ดํ„ฐ DiceForge ๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ฃผ์š” ๊ธฐ๋Šฅ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  • ๊น”๋”ํ•˜๊ณ  ํ˜„๋Œ€์ ์ธ UI
  • ์ฃผ์‚ฌ์œ„ ๊ฐœ์ˆ˜์™€ ๋ฉด ์ˆ˜๋ฅผ ์ž์œ ๋กญ๊ฒŒ ์„ค์ • ๊ฐ€๋Šฅ
  • ์ฆ‰์‹œ ํ‘œ์‹œ๋˜๋Š” ๊ตด๋ฆผ ๊ฒฐ๊ณผ์™€ ํ•ฉ๊ณ„
  • ๋ผ์ดํŠธ & ๋‹คํฌ ๋ชจ๋“œ ์ง€์›
  • ttk.Notebook ์„ ํ™œ์šฉํ•œ ํƒญ ๊ธฐ๋ฐ˜ ๋ ˆ์ด์•„์›ƒ

๐Ÿงฐ ๊ธฐ์ˆ  ์Šคํƒ

  • Pythonโ€ฏ3 โ€“ ํ•ต์‹ฌ ๋กœ์ง
  • Tkinter โ€“ GUI ํ”„๋ ˆ์ž„์›Œํฌ (Python์— ๋‚ด์žฅ)
  • ttk / sv_ttk โ€“ ํ…Œ๋งˆ ์œ„์ ฏ ๋ฐ ํ˜„๋Œ€์  ์Šคํƒ€์ผ๋ง
  • random โ€“ ์ฃผ์‚ฌ์œ„ ๊ตด๋ฆผ ์ƒ์„ฑ

์™ธ๋ถ€ API ์—†์Œ. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—†์Œ. ๊น”๋”ํ•˜๊ณ  ๋กœ์ปฌ Python๋งŒ ์‚ฌ์šฉ.

๐Ÿง  ์•ฑ ๊ฐœ์š”

DiceForge๋Š” ๋‹จ์ผ ์ฐฝ ๋ฐ์Šคํฌํ†ฑ ์•ฑ์œผ๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ์œผ๋ฉฐ ๋‘ ๊ฐœ์˜ ์ฃผ์š” ํƒญ์ด ์žˆ์Šต๋‹ˆ๋‹ค:

  1. ๋Œ€์‹œ๋ณด๋“œ โ€“ ์†Œ๊ฐœ ํ…์ŠคํŠธ ๋ฐ ๊ธฐ๋Šฅ ๋ชฉ๋ก
  2. ์ฃผ์‚ฌ์œ„ ๊ตด๋ฆฌ๊ธฐ โ€“ ๋งˆ๋ฒ•์ด ์ผ์–ด๋‚˜๋Š” ๊ณณ

UI๋Š” ๋ฐ˜์‘ํ˜•์ด๋ฉฐ ๊ฐ€๋…์„ฑ์ด ์ข‹๊ณ , ๊ธฐ๋ณธ Tkinter ์ฐฝ๋ณด๋‹ค ํ˜„๋Œ€์ ์ธ ์•ฑ์— ๋” ๊ฐ€๊น๊ฒŒ ๋А๊ปด์ง€๋„๋ก ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿš€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ค์ •

import tkinter as tk
import ttk
import sv_ttk

root = tk.Tk()
root.title("DiceForge - Dice Rolling Simulator")
root.geometry("900x620")
sv_ttk.set_theme("light")

sv_ttk ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๋” ๊น”๋”ํ•œ ๊ธฐ๋ณธ ํ…Œ๋งˆ๋ฅผ ์ œ๊ณตํ•˜๋ฉฐ, ์ดํ›„์— ์‚ฌ์šฉ์ž ์ •์˜ ์Šคํƒ€์ผ๋กœ ํ™•์žฅํ•ฉ๋‹ˆ๋‹ค.

๐ŸŽ› Tkinter ๋ณ€์ˆ˜๋กœ ์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ

Tkinter์˜ ๋ณ€์ˆ˜ ํด๋ž˜์Šค๋Š” ์ƒํƒœ ๊ด€๋ฆฌ๋ฅผ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋งŒ๋“ค์–ด ์ค๋‹ˆ๋‹ค:

dark_mode_var = tk.BooleanVar(value=False)
dice_count_var = tk.IntVar(value=1)
dice_sides_var = tk.IntVar(value=6)

์ด ๋ณ€์ˆ˜๋“ค์€ ์Šคํ•€๋ฐ•์Šค์™€ ์ฒดํฌ๋ฒ„ํŠผ ๊ฐ™์€ ์œ„์ ฏ๊ณผ ์ž๋™์œผ๋กœ ๋™๊ธฐํ™”๋ฉ๋‹ˆ๋‹ค.

๐ŸŒ— ๋ผ์ดํŠธ & ๋‹คํฌ ๋ชจ๋“œ ํ† ๊ธ€

๋‹คํฌ ๋ชจ๋“œ๋Š” ttk ์Šคํƒ€์ผ๊ณผ ๋ฃจํŠธ ๋ฐฐ๊ฒฝ์„ ๋™์ ์œผ๋กœ ์žฌ๊ตฌ์„ฑํ•˜์—ฌ ์ฒ˜๋ฆฌ๋ฉ๋‹ˆ๋‹ค:

def toggle_theme():
    style.theme_use("clam")
    if dark_mode_var.get():
        root.configure(bg="#2E2E2E")
        style.configure("TLabel", background="#2E2E2E", foreground="white")
    else:
        root.configure(bg="#FFFFFF")
        style.configure("TLabel", background="#FFFFFF", foreground="black")

์ด ์ ‘๊ทผ ๋ฐฉ์‹์€ ์œ„์ ฏ์„ ๋‹ค์‹œ ๋งŒ๋“ค์ง€ ์•Š๊ณ ๋„ UI์˜ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“‘ ๋…ธํŠธ๋ถ์„ ์‚ฌ์šฉํ•œ ํƒญ ๋ ˆ์ด์•„์›ƒ

์šฐ๋ฆฌ๋Š” ttk.Notebook์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ด€์‹ฌ์‚ฌ๋ฅผ ๊น”๋”ํ•˜๊ฒŒ ๋ถ„๋ฆฌํ•ฉ๋‹ˆ๋‹ค:

tabs = ttk.Notebook(root)
tabs.pack(expand=True, fill="both", padx=20, pady=20)

dashboard_tab = ttk.Frame(tabs)
roller_tab = ttk.Frame(tabs)

tabs.add(dashboard_tab, text="Dashboard")
tabs.add(roller_tab, text="Dice Roller")

๊ฐ ํƒญ์€ ์ž์ฒด Frame์ด๋ฉฐ, ๋ ˆ์ด์•„์›ƒ์„ ๋ชจ๋“ˆ์‹์œผ๋กœ ๋งŒ๋“ค๊ณ  ๋‚˜์ค‘์— ํ™•์žฅํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.

โš™๏ธ ์ฃผ์‚ฌ์œ„ ์„ค์ • ์ œ์–ด

์ฃผ์‚ฌ์œ„ ์„ค์ •์€ Spinbox ์œ„์ ฏ์„ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ์‚ฌ์šฉ์ž๊ฐ€ ์ž˜๋ชป๋œ ์œ ํ˜•์„ ์ž…๋ ฅํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค:

dice_spin = ttk.Spinbox(
    settings_card,
    from_=1,
    to=100,
    textvariable=dice_count_var
)

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ฒ€์ฆ์ด ๊ฐ„๋‹จํ•ด์ง€๊ณ  UX๊ฐ€ ์นœ์ˆ™ํ•ด์ง‘๋‹ˆ๋‹ค.

๐ŸŽฒ ์ฃผ์‚ฌ์œ„ ๊ตด๋ฆฌ๊ธฐ

์•ฑ์˜ ํ•ต์‹ฌ ๋ถ€๋ถ„์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

import random

def roll_dice():
    count = dice_count_var.get()
    sides = dice_sides_var.get()
    rolls = [random.randint(1, sides) for _ in range(count)]
    total = sum(rolls)

    # Display results (example)
    result_text = f"{count}d{sides}: " + ", ".join(map(str, rolls))
    result_text += f"\nTotal: {total}"
    result_widget.configure(state="normal")
    result_widget.delete("1.0", tk.END)
    result_widget.insert(tk.END, result_text)
    result_widget.configure(state="disabled")

๊ฒฐ๊ณผ๋Š” ์ฝ๊ธฐ ์ „์šฉ Text ์œ„์ ฏ์— ํ‘œ์‹œ๋˜๋ฉฐ, ๋‹ค์Œ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค:

  • ์ฃผ์‚ฌ์œ„ ํ‘œ๊ธฐ๋ฒ• (XdY)
  • ๊ฐœ๋ณ„ ๊ตด๋ฆผ ๊ฒฐ๊ณผ
  • ์ตœ์ข… ํ•ฉ๊ณ„

๋น ๋ฅธ ํ™•์ธ์ด๋‚˜ ๋ฐ˜๋ณต ํ…Œ์ŠคํŠธ์— ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

๐Ÿงพ ์ƒํƒœ ํ‘œ์‹œ์ค„ ํ”ผ๋“œ๋ฐฑ

๋ฏธ๋ฌ˜ํ•˜์ง€๋งŒ ์ค‘์š”ํ•œ UX ์š”์†Œ: ์ƒํƒœ ํ‘œ์‹œ์ค„.

status_var = tk.StringVar(value="Ready")
status_bar = ttk.Label(root, textvariable=status_var, anchor="w")
status_bar.pack(side="bottom", fill="x")

์ด๊ฒƒ์€ ์ฃผ์‚ฌ์œ„๋ฅผ ๊ตด๋ฆฌ๊ฑฐ๋‚˜ ํ…Œ๋งˆ๋ฅผ ์ „ํ™˜ํ•˜๋Š” ๋“ฑ์˜ ๋™์ž‘์— ์ฆ‰๊ฐ์ ์ธ ํ”ผ๋“œ๋ฐฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

โœจ Polished Styling

Custom button styling helps important actions stand out:

style.configure(
    "Action.TButton",
    font=("Segoe UI", 11, "bold"),
    background="#4CAF50"
)

Small details like this make a huge difference in perceived quality.

๐Ÿ ์ตœ์ข… ์ƒ๊ฐ

DiceForge๋Š” ์‚ฌ๋ ค ๊นŠ์€ ๋ ˆ์ด์•„์›ƒ๊ณผ ์Šคํƒ€์ผ๋ง์œผ๋กœ Tkinter๋ฅผ ์–ผ๋งˆ๋‚˜ ๋ฉ€๋ฆฌ๊นŒ์ง€ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๋ณด์—ฌ์ฃผ๋Š” ์ข‹์€ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€:

  • ์ดˆ๋ณด์ž ์นœํ™”์ 
  • ์‰ฝ๊ฒŒ ํ™•์žฅ ๊ฐ€๋Šฅ (์ด์ /๋ถˆ์ด์  ๊ตด๋ฆผ, ํ”„๋ฆฌ์…‹, ํžˆ์Šคํ† ๋ฆฌ)
  • PyInstaller๋กœ ํŒจํ‚ค์ง•ํ•˜๊ธฐ ์œ„ํ•œ ๊ฒฌ๊ณ ํ•œ ๊ธฐ๋ฐ˜

Python GUI ๊ฐœ๋ฐœ์„ ๋ฐฐ์šฐ๊ณ  ์žˆ๋‹ค๋ฉด, ์ด ํ”„๋กœ์ ํŠธ๋Š” ์ ‘๊ทผํ•˜๊ธฐ ์‰ฌ์šฐ๋ฉด์„œ๋„ ๋‹ค๋“ฌ์–ด์ง„ ์™„์„ฑ๋„๋ฅผ ๊ฐ–์ถ˜ ์ข‹์€ ์ง€์ ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

ํ–‰๋ณตํ•œ ๊ตด๋ฆผ ๐ŸŽฒ

Back to Blog

๊ด€๋ จ ๊ธ€

๋” ๋ณด๊ธฐ ยป

Python๊ณผ Tkinter๋กœ ๊ฐ„๋‹จํ•œ ํŒŒ์ผ ํƒ์ƒ‰๊ธฐ ๋งŒ๋“ค๊ธฐ โ€“ FileMate Explorer

๐Ÿ“‚ FileMate Explorer โ€“ ๊ฐ€๋ฒผ์šด ํŒŒ์ด์ฌ ํŒŒ์ผ ๊ด€๋ฆฌ์ž. ์™„์ „ํžˆ ํŒŒ์ด์ฌ์œผ๋กœ ๋งŒ๋“  ๊ฐ€๋ฒผ์šด ํŒŒ์ผ ํƒ์ƒ‰๊ธฐ๋ฅผ ์›ํ•˜์…จ๋‚˜์š”? Tkinter ๊ธฐ๋ฐ˜ FileMate Explorer๋ฅผ ๋งŒ๋‚˜๋ณด์„ธ์š”.

๐Ÿš€ FileMate Pro: Tkinter๋ฅผ ํ™œ์šฉํ•œ Python GUI ํŒŒ์ผ ๋งค๋‹ˆ์ €

FileMate Pro โ€“ ๊ฐ„๋‹จํ•œ Tkinter ํŒŒ์ผ ๊ด€๋ฆฌ์ž Python์—์„œ GUI๋กœ ํŒŒ์ผ์„ ์ง์ ‘ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ๋ณต์žกํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. FileMate Pro๋Š” ๊ฐ€๋ณ๊ณ  ์‚ฌ์šฉ์ž ์นœํ™”์ ์ธ โ€ฆ

Tkinter๋ฅผ ์‚ฌ์šฉํ•œ 2D ๊ฒŒ์ž„ ์‹œ์ž‘ํ•˜๊ธฐ (ํŒŒํŠธ 9): ์นด์šดํ„ฐ ํ‘œ์‹œ

์นด์šดํ„ฐ ํ‘œ์‹œ ์ด ๊ธฐ์‚ฌ์—์„œ๋Š” ํ™”๋ฉด์— ๋‚จ์•„ ์žˆ๋Š” ์•…๋งˆ ์ˆ˜๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ์นด์šดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ๋จผ์ €, ์นด์šดํ„ฐ๋ผ๋Š” ๋ณ€์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด ๋‚จ์€ ์ˆ˜๋ฅผ ์ถ”์ ํ•ฉ๋‹ˆ๋‹ค.