Untitled
unknown
plain_text
2 months ago
12 kB
7
Indexable
import tkinter as tk
from tkinter import messagebox
import random
# ======================================================================
# CONFIGURAÇÃO HARDCODED DAS PREFERÊNCIAS POR QUADRANTE
# A matriz é 3 linhas x 5 colunas, totalizando 15 quadrantes.
# A lista abaixo define a probabilidade de cada quadrante ser escolhido.
# A soma deve ser 1.0. Altere os valores conforme sua preferência.
# O mapeamento é feito por linha:
# indices 0-4 -> primeira linha (topo)
# indices 5-9 -> segunda linha
# indices 10-14 -> terceira linha (base)
# ======================================================================
QUADRANT_PROBS = [
0.10, 0.05, 0.05, 0.05, 0.10, # linha 0
0.05, 0.10, 0.10, 0.10, 0.05, # linha 1
0.05, 0.05, 0.05, 0.05, 0.05 # linha 2
]
# Verifica se a soma é próxima de 1
if abs(sum(QUADRANT_PROBS) - 1.0) > 1e-6:
raise ValueError("A soma das probabilidades dos quadrantes deve ser 1.0")
NUM_ROWS = 3
NUM_COLS = 5
class CircleApp:
def __init__(self, root):
self.root = root
self.root.title("Exibição de Círculos")
# Variáveis de configuração
self.period = tk.DoubleVar(value=5.0)
self.quantity = tk.IntVar(value=10)
self.min_diam = tk.IntVar(value=20)
self.max_diam = tk.IntVar(value=80)
self.bg_color = tk.StringVar(value="white")
self.circle_color = tk.StringVar(value="red")
self.show_borders = tk.BooleanVar(value=False)
self.border_color = tk.StringVar(value="black")
# Controle da animação
self.animation_running = False
self.after_id = None
self.canvas = None
self.paused = False # NOVO: estado de pausa
# Vincula a tecla 'p' (minúscula e maiúscula) ao método de pausa
root.bind('<KeyPress-p>', self.toggle_pause)
root.bind('<KeyPress-P>', self.toggle_pause)
# Construir frames
self.config_frame = tk.Frame(root)
self.anim_frame = tk.Frame(root)
self.build_config_frame()
self.build_animation_frame()
# Iniciar com o frame de configuração visível
self.config_frame.pack(fill=tk.BOTH, expand=True)
self.anim_frame.pack_forget()
# ------------------------------------------------------------------
def build_config_frame(self):
"""Constrói o painel de configuração."""
tk.Label(self.config_frame, text="CONFIGURAÇÕES", font=("Arial", 14, "bold")).pack(pady=5)
f1 = tk.Frame(self.config_frame)
f1.pack(pady=2, fill=tk.X, padx=10)
tk.Label(f1, text="Período (s):").pack(side=tk.LEFT)
tk.Entry(f1, textvariable=self.period, width=8).pack(side=tk.LEFT, padx=5)
f2 = tk.Frame(self.config_frame)
f2.pack(pady=2, fill=tk.X, padx=10)
tk.Label(f2, text="Quantidade:").pack(side=tk.LEFT)
tk.Entry(f2, textvariable=self.quantity, width=8).pack(side=tk.LEFT, padx=5)
f3 = tk.Frame(self.config_frame)
f3.pack(pady=2, fill=tk.X, padx=10)
tk.Label(f3, text="Diâmetro mín:").pack(side=tk.LEFT)
tk.Entry(f3, textvariable=self.min_diam, width=6).pack(side=tk.LEFT, padx=2)
tk.Label(f3, text="máx:").pack(side=tk.LEFT)
tk.Entry(f3, textvariable=self.max_diam, width=6).pack(side=tk.LEFT, padx=5)
f4 = tk.Frame(self.config_frame)
f4.pack(pady=2, fill=tk.X, padx=10)
tk.Label(f4, text="Cor do fundo:").pack(side=tk.LEFT)
tk.Entry(f4, textvariable=self.bg_color, width=12).pack(side=tk.LEFT, padx=5)
f5 = tk.Frame(self.config_frame)
f5.pack(pady=2, fill=tk.X, padx=10)
tk.Label(f5, text="Cor dos círculos:").pack(side=tk.LEFT)
tk.Entry(f5, textvariable=self.circle_color, width=12).pack(side=tk.LEFT, padx=5)
f6 = tk.Frame(self.config_frame)
f6.pack(pady=2, fill=tk.X, padx=10)
tk.Checkbutton(f6, text="Mostrar bordas dos quadrantes",
variable=self.show_borders).pack(side=tk.LEFT)
f7 = tk.Frame(self.config_frame)
f7.pack(pady=2, fill=tk.X, padx=10)
tk.Label(f7, text="Cor da borda:").pack(side=tk.LEFT)
tk.Entry(f7, textvariable=self.border_color, width=12).pack(side=tk.LEFT, padx=5)
tk.Button(self.config_frame, text="START", command=self.start_animation,
font=("Arial", 12, "bold"), bg="lightgreen").pack(pady=10)
# ------------------------------------------------------------------
def build_animation_frame(self):
"""Constrói o frame da animação."""
self.canvas = tk.Canvas(self.anim_frame, bg="white")
self.canvas.pack(fill=tk.BOTH, expand=True)
self.stop_button = tk.Button(self.anim_frame, text="Stop", command=self.stop_animation)
self.stop_button.pack(pady=5)
self.canvas.bind("<Configure>", self.on_canvas_resize)
# ------------------------------------------------------------------
def validate_config(self):
"""Valida os valores inseridos."""
try:
period = float(self.period.get())
if period <= 0:
raise ValueError("Período deve ser positivo.")
quantity = int(self.quantity.get())
if quantity <= 0:
raise ValueError("Quantidade deve ser um inteiro positivo.")
min_d = int(self.min_diam.get())
max_d = int(self.max_diam.get())
if min_d <= 0 or max_d <= 0:
raise ValueError("Diâmetros devem ser positivos.")
if min_d > max_d:
raise ValueError("Diâmetro mínimo não pode ser maior que o máximo.")
return True
except ValueError as e:
messagebox.showerror("Erro de validação", str(e))
return False
# ------------------------------------------------------------------
def start_animation(self):
"""Inicia a sequência de círculos."""
if not self.validate_config():
return
self.config_frame.pack_forget()
self.anim_frame.pack(fill=tk.BOTH, expand=True)
self.canvas.configure(bg=self.bg_color.get())
self.canvas.delete("all")
self.animation_running = True
self.paused = False # reseta a pausa
self.circle_count = 0
self.schedule_next_circle()
# ------------------------------------------------------------------
def stop_animation(self):
"""Para a animação e retorna ao menu."""
if self.after_id:
self.root.after_cancel(self.after_id)
self.after_id = None
self.animation_running = False
self.paused = False
self.anim_frame.pack_forget()
self.config_frame.pack(fill=tk.BOTH, expand=True)
self.stop_button.config(text="Stop", command=self.stop_animation)
# ------------------------------------------------------------------
def toggle_pause(self, event=None):
"""Alterna entre pausado e executando (tecla 'p')."""
if not self.animation_running:
return # só funciona durante a animação ativa
self.paused = not self.paused
if self.paused:
# Cancela qualquer evento futuro imediato
if self.after_id:
self.root.after_cancel(self.after_id)
self.after_id = None
# Mostra indicador de pausa no canvas
self.show_pause_indicator()
else:
# Remove indicador de pausa e retoma a exibição
self.schedule_next_circle() # desenha o próximo e agenda o seguinte
# ------------------------------------------------------------------
def show_pause_indicator(self):
"""Exibe um texto 'PAUSADO' no centro do canvas."""
w = self.canvas.winfo_width()
h = self.canvas.winfo_height()
self.canvas.create_text(w//2, h//2, text="PAUSADO",
fill="black", font=("Arial", 24, "bold"),
tags="pause_text")
# ------------------------------------------------------------------
def schedule_next_circle(self):
"""Agenda o próximo círculo, respeitando pausa e fim da animação."""
if not self.animation_running:
return
if self.paused:
# Se pausado, não faz nada; aguarda o comando de resume
return
total_circles = int(self.quantity.get())
period = float(self.period.get())
if self.circle_count >= total_circles:
self.animation_running = False
self.stop_button.config(text="Back", command=self.stop_animation)
self.canvas.create_text(
self.canvas.winfo_width() // 2,
self.canvas.winfo_height() // 2,
text="Fim da animação",
fill="black",
font=("Arial", 16, "bold")
)
return
interval_ms = int((period / total_circles) * 1000)
self.draw_circle()
self.circle_count += 1
self.after_id = self.root.after(interval_ms, self.schedule_next_circle)
# ------------------------------------------------------------------
def draw_circle(self):
"""Desenha um círculo (substitui o anterior)."""
self.canvas.delete("all")
if self.show_borders.get():
self.draw_quadrant_borders()
w = self.canvas.winfo_width()
h = self.canvas.winfo_height()
if w <= 1 or h <= 1:
return
quadrant_idx = random.choices(range(NUM_ROWS * NUM_COLS),
weights=QUADRANT_PROBS, k=1)[0]
row = quadrant_idx // NUM_COLS
col = quadrant_idx % NUM_COLS
col_width = w / NUM_COLS
row_height = h / NUM_ROWS
x0 = col * col_width
y0 = row * row_height
x1 = x0 + col_width
y1 = y0 + row_height
min_d = int(self.min_diam.get())
max_d = int(self.max_diam.get())
diameter = random.randint(min_d, max_d)
radius = diameter / 2.0
margin = radius
if col_width < diameter:
cx = (x0 + x1) / 2
else:
cx = random.uniform(x0 + margin, x1 - margin)
if row_height < diameter:
cy = (y0 + y1) / 2
else:
cy = random.uniform(y0 + margin, y1 - margin)
self.canvas.create_oval(
cx - radius, cy - radius,
cx + radius, cy + radius,
fill=self.circle_color.get(),
outline=self.circle_color.get()
)
# ------------------------------------------------------------------
def draw_quadrant_borders(self):
w = self.canvas.winfo_width()
h = self.canvas.winfo_height()
if w <= 1 or h <= 1:
return
border_col = self.border_color.get()
for i in range(1, NUM_ROWS):
y = i * (h / NUM_ROWS)
self.canvas.create_line(0, y, w, y, fill=border_col)
for j in range(1, NUM_COLS):
x = j * (w / NUM_COLS)
self.canvas.create_line(x, 0, x, h, fill=border_col)
# ------------------------------------------------------------------
def on_canvas_resize(self, event):
pass
# ======================================================================
if __name__ == "__main__":
root = tk.Tk()
root.geometry("1920x1080")
app = CircleApp(root)
root.mainloop()Editor is loading...
Leave a Comment