diff --git a/src/services/__pycache__/processes_manager.cpython-313.pyc b/src/services/__pycache__/processes_manager.cpython-313.pyc new file mode 100644 index 0000000..3b63b05 Binary files /dev/null and b/src/services/__pycache__/processes_manager.cpython-313.pyc differ diff --git a/src/services/__pycache__/system_monitor.cpython-313.pyc b/src/services/__pycache__/system_monitor.cpython-313.pyc new file mode 100644 index 0000000..ce33be4 Binary files /dev/null and b/src/services/__pycache__/system_monitor.cpython-313.pyc differ diff --git a/src/services/__pycache__/tetris_game.cpython-313.pyc b/src/services/__pycache__/tetris_game.cpython-313.pyc new file mode 100644 index 0000000..23cc510 Binary files /dev/null and b/src/services/__pycache__/tetris_game.cpython-313.pyc differ diff --git a/src/services/__pycache__/threaden_task.cpython-313.pyc b/src/services/__pycache__/threaden_task.cpython-313.pyc new file mode 100644 index 0000000..eb9c2f7 Binary files /dev/null and b/src/services/__pycache__/threaden_task.cpython-313.pyc differ diff --git a/src/services/__pycache__/threads_manager.cpython-313.pyc b/src/services/__pycache__/threads_manager.cpython-313.pyc new file mode 100644 index 0000000..8162fb8 Binary files /dev/null and b/src/services/__pycache__/threads_manager.cpython-313.pyc differ diff --git a/src/services/system_monitor.py b/src/services/system_monitor.py index 8ecdd77..a0d10e9 100644 --- a/src/services/system_monitor.py +++ b/src/services/system_monitor.py @@ -1,88 +1,77 @@ -import psutil -import matplotlib.pyplot as plt -from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg -import threading -import tkinter as tk -import time - -class SystemMonitor: - def __init__(self, parent_frame): - self.parent_frame = parent_frame - self.max_data_points = 60 - self.running = True # Indicador para detener los hilos - self.metrics = { - "CPU Usage": { - "data": [], - "thread": None, - "fetch_func": psutil.cpu_percent, - "interval": 1 - }, - "RAM Usage": { - "data": [], - "thread": None, - "fetch_func": lambda: psutil.virtual_memory().percent, - "interval": 1 - } - } - self.graphs = {} - self.init_graphs() - - def init_graphs(self): - """Crea gráficos para todas las métricas y arranca sus hilos de actualización.""" - for metric, config in self.metrics.items(): - fig, ax, line = self.create_graph(metric) - self.graphs[metric] = {"figure": fig, "axis": ax, "line": line} - - # Crear y arrancar el hilo para actualizar esta métrica - thread = threading.Thread(target=self.update_metric, args=(metric,), daemon=True) - self.metrics[metric]["thread"] = thread - thread.start() - - def create_graph(self, title): - """Crea un gráfico para una métrica específica.""" - frame = tk.Frame(self.parent_frame) - frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5) - - label = tk.Label(frame, text=title, font=("Arial", 14, "bold")) - label.pack() - - fig, ax = plt.subplots(figsize=(5, 3)) - ax.set_title(title) - ax.set_xlabel("Time") - ax.set_ylabel("Usage (%)") - ax.set_ylim(0, 100) - line, = ax.plot([], [], lw=2) - - canvas = FigureCanvasTkAgg(fig, frame) - canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True) - - return fig, ax, line - - def update_metric(self, metric): - config = self.metrics[metric] - while self.running: - try: - new_data = config["fetch_func"]() - config["data"].append(new_data) - - if len(config["data"]) > self.max_data_points: - config["data"].pop(0) - - self.update_graph(metric, config["data"]) - time.sleep(config["interval"]) - except Exception as e: - print(f"Error en update_metric ({metric}): {e}") +import psutil +import matplotlib.pyplot as plt +from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg +import tkinter as tk +class SystemMonitor: + def __init__(self, parent_frame): + self.parent_frame = parent_frame + self.max_data_points = 60 + self.running = False + self.metrics = { + "CPU Usage": { + "data": [], + "fetch_func": psutil.cpu_percent, + "interval": 1 + }, + "RAM Usage": { + "data": [], + "fetch_func": lambda: psutil.virtual_memory().percent, + "interval": 1 + } + } + self.graphs = {} + self.init_graphs() - def update_graph(self, metric, data): - """Actualiza un gráfico con nuevos datos.""" - graph = self.graphs[metric] - x = list(range(len(data))) - graph["line"].set_data(x, data) - graph["axis"].set_xlim(0, len(data)) - graph["figure"].canvas.draw() + def init_graphs(self): + """Crea gráficos para todas las métricas.""" + for metric, config in self.metrics.items(): + fig, ax, line = self.create_graph(metric) + self.graphs[metric] = {"figure": fig, "axis": ax, "line": line} - def stop_threads(self): - """Detiene la ejecución de todos los hilos de monitoreo.""" - self.running = False + def create_graph(self, title): + """Crea un gráfico para una métrica específica.""" + frame = tk.Frame(self.parent_frame) + frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5) + + label = tk.Label(frame, text=title, font=("Arial", 14, "bold")) + label.pack() + + fig, ax = plt.subplots(figsize=(5, 3)) + ax.set_title(title) + ax.set_xlabel("Time") + ax.set_ylabel("Usage (%)") + ax.set_ylim(0, 100) + line, = ax.plot([], [], lw=2) + + canvas = FigureCanvasTkAgg(fig, frame) + canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True) + + return fig, ax, line + + def update_metric(self, metric): + """Actualiza los datos de una métrica específica.""" + config = self.metrics[metric] + try: + new_data = config["fetch_func"]() + config["data"].append(new_data) + + if len(config["data"]) > self.max_data_points: + config["data"].pop(0) + + self.update_graph(metric, config["data"]) + except Exception as e: + print(f"Error en update_metric ({metric}): {e}") + + def update_graph(self, metric, data): + """Actualiza un gráfico con nuevos datos.""" + graph = self.graphs[metric] + x = list(range(len(data))) + + def redraw(): + graph["line"].set_data(x, data) + graph["axis"].set_xlim(0, len(data)) + graph["figure"].canvas.draw() + + self.parent_frame.after(0, redraw) \ No newline at end of file diff --git a/src/services/threaden_task.py b/src/services/threaden_task.py new file mode 100644 index 0000000..30c88d3 --- /dev/null +++ b/src/services/threaden_task.py @@ -0,0 +1,22 @@ +import threading + +"""Clase que se encarga de manjear hilos. Permite arrancar y parar un hilo""" + +class ThreadenTask: + def __init__(self): + self.running = False + self.thread = None + + + def start(self, target, *args): + """Inicia un hilo con el objetivo especificado.""" + if not self.running: + self.running = True + self.thread = threading.Thread(target=target, args=args, daemon=True) + self.thread.start() + + def stop(self): + """Detiene el hilo""" + self.running = False + if self.thread: + self.thread.join() \ No newline at end of file diff --git a/src/services/threads_manager.py b/src/services/threads_manager.py index e3dcaa1..0035300 100644 --- a/src/services/threads_manager.py +++ b/src/services/threads_manager.py @@ -1,35 +1,86 @@ -import threading import datetime import time import requests import random +from services.threaden_task import ThreadenTask +from services.system_monitor import SystemMonitor + class ThreadsManager: + """Constructor""" def __init__(self, ui_instance): self.ui_instance = ui_instance + self.system_monitor = None + self.tasks = { + "time": ThreadenTask(), + "temperature": ThreadenTask(), + "emails":ThreadenTask(), + } + self.system_monitor_tasks = {} + + + + def set_system_monitor(self, system_monitor): + """Asigna el monitor del sistema y crea sus tareas""" + self.system_monitor = system_monitor + for metric in system_monitor.metrics.keys(): + self.system_monitor_tasks[metric] = ThreadenTask() + + def start_threads(self): - # Hilo para actualizar el reloj - threading.Thread(target=self.update_time, daemon=True).start() + """Se inician los hilos, Tiempo, Temperatura, Emails""" + self.tasks["time"].start(self.update_time) + self.tasks["temperature"].start(self.update_temperature) + self.tasks["emails"].start(self.update_emails) - # Hilo para actualizar la temperatura - threading.Thread(target=self.update_temperature, daemon=True).start() + if self.system_monitor: + for metric in self.system_monitor.metrics.keys(): + self.system_monitor_tasks[metric].start( + self.update_system_metric, + metric + ) - # Hilo para actualizar correos (simulado) - threading.Thread(target=self.update_emails, daemon=True).start() + + def stop_threads(self): + """Recorre tasks y para los hilos""" + for task in self.tasks.values(): + task.stop() + + for task in self.system_monitor_tasks.values(): + task.stop() + + if self.system_monitor: + self.system_monitor.running = False + + + + def update_system_metric(self, metric): + """Actualiza una métrica específica del monitor del sistema.""" + while self.system_monitor_tasks[metric].running: + try: + self.system_monitor.update_metric(metric) + time.sleep(self.system_monitor.metrics[metric]["interval"]) + except Exception as e: + print(f"Error updating metric {metric}: {e}") + + + def update_time(self): - while True: + while self.tasks["time"].running: current_time = datetime.datetime.now().strftime('%H:%M:%S') current_date = datetime.datetime.now().strftime('%d/%m/%Y') self.ui_instance.after(0, lambda: self.ui_instance.info_labels["hora"].configure(text=f"Hora: {current_time}")) self.ui_instance.after(0, lambda: self.ui_instance.info_labels["fecha"].configure(text=f"Fecha: {current_date}")) time.sleep(1) + + def update_temperature(self): API_KEY = "4ba2b87d7fa32934530b5b4a5a83ebf7" # Reemplaza con tu clave de OpenWeatherMap CITY = "Madrid" # Cambia por tu ciudad - while True: + while self.tasks["temperature"].running: try: temperature = self.get_real_temperature(API_KEY, CITY) if temperature is not None: @@ -41,6 +92,8 @@ class ThreadsManager: print(f"Error al obtener la temperatura: {e}") time.sleep(600) # Actualiza cada 10 minutos + + def get_real_temperature(self, api_key, city): url = f"http://api.openweathermap.org/data/2.5/weather?q={city}&appid={api_key}&units=metric" response = requests.get(url) @@ -50,13 +103,17 @@ class ThreadsManager: else: print(f"Error al obtener la temperatura: {response.status_code}") return None + + def update_emails(self): count = 0 - while True: + while self.tasks["emails"].running: count += random.randint(0, 2) # Simula la llegada de 0-2 correos self.ui_instance.after( 0, lambda: self.ui_instance.info_labels["emails"].configure(text=f"Correos sin leer: {count}") ) - time.sleep(10) # Actualiza cada 10 segundos + time.sleep(20) # Actualiza cada 10 segundos + + diff --git a/src/ui/__pycache__/__init__.cpython-313.pyc b/src/ui/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000..ca5c9ae Binary files /dev/null and b/src/ui/__pycache__/__init__.cpython-313.pyc differ diff --git a/src/ui/__pycache__/centered_window.cpython-313.pyc b/src/ui/__pycache__/centered_window.cpython-313.pyc new file mode 100644 index 0000000..3bdf8ae Binary files /dev/null and b/src/ui/__pycache__/centered_window.cpython-313.pyc differ diff --git a/src/ui/centered_window.py b/src/ui/centered_window.py index 5aca4fc..315dd4f 100644 --- a/src/ui/centered_window.py +++ b/src/ui/centered_window.py @@ -8,18 +8,19 @@ import threading from services.threads_manager import ThreadsManager from services.processes_manager import ProcessManager from services.tetris_game import TetrisGame +from services.system_monitor import SystemMonitor class CenteredWindow(ctk.CTk): def __init__(self, title="MultiApp", width_percentage=0.8, height_percentage=0.8): # Inicializacion de la clase: super().__init__() - - # Titulo de la ventana: self.title(title) + # Inicializar managers (orden es importante) self.thread_manager = ThreadsManager(self) self.process_manager = ProcessManager() + self.system_monitor = None # Obtener la resolucion de la pantalla: screen_width = self.winfo_screenwidth() @@ -38,6 +39,8 @@ class CenteredWindow(ctk.CTk): #Configura la ventana self.configure_window() + self.protocol("WM_DELETE_WINDOW", self.on_close) + def configure_window(self): # Configuracion de la ventana: self.configure(bg_color="lightgray") @@ -45,8 +48,18 @@ class CenteredWindow(ctk.CTk): self.create_right_panel() self.create_center_panel() self.create_bottom_bar() + self.thread_manager.start_threads() + + + def on_close(self): + """Maneja el cierre de la ventana""" + self.thread_manager.stop_threads() + self.destroy() + + + def create_left_panel(self): # Panel izquierdo left_panel = ctk.CTkFrame(self, width=200) @@ -70,6 +83,8 @@ class CenteredWindow(ctk.CTk): btn = ctk.CTkButton(left_panel, text=text, command=command, width=150) btn.pack(pady=5, padx=10) + + def create_center_panel(self): # Panel central con pestañas center_panel = ctk.CTkFrame(self) @@ -82,7 +97,18 @@ class CenteredWindow(ctk.CTk): for tab_name in ["Resultados Scrapping", "Navegador", "Correos", "Juego", "Sistema"]: tab = tab_view.add(tab_name) - if tab_name == "Juego": + if tab_name == "Sistema": + # Crear un frame para los gráficos del sistema + system_frame = ctk.CTkFrame(tab) + system_frame.pack(fill=ctk.BOTH, expand=True, padx=5, pady=5) + + # Inicializar SystemMonitor con el frame de la pestaña + self.system_monitor = SystemMonitor(system_frame) + + # Asignar el system_monitor al thread_manager + self.thread_manager.set_system_monitor(self.system_monitor) + + elif tab_name == "Juego": # Crear un marco intermedio para centrar game_frame = ctk.CTkFrame(tab) game_frame.pack(expand=True) @@ -109,16 +135,22 @@ class CenteredWindow(ctk.CTk): label = ctk.CTkLabel(tab, text=f"Contenido de {tab_name}", font=("Arial", 12)) label.pack(pady=10) + + def start_tetris_game(self): """Método para iniciar el juego.""" if not self.tetris_game.running: self.tetris_game.running = True self.tetris_game.update_game() + + def pause_tetris_game(self): """Método para pausar el juego.""" self.tetris_game.running = False + + def restart_tetris_game(self): """Método para reiniciar el juego.""" self.tetris_game.reset_game() @@ -153,6 +185,8 @@ class CenteredWindow(ctk.CTk): ) student_info.pack(anchor=ctk.W, padx=10) + + def create_bottom_bar(self): # Crear la barra inferior self.bottom_bar = ctk.CTkFrame(self, fg_color="lightblue", height=40) @@ -170,5 +204,7 @@ class CenteredWindow(ctk.CTk): for label in self.info_labels.values(): label.pack(side=ctk.LEFT, padx=10, pady=5) + + def dummy_action(self): print("Acción no implementada") \ No newline at end of file