Implemented thread manager to handle threats and adjustes problem where the windows didnt open because of grpahics issue, also implemented graphics for cpu and ram usage

This commit is contained in:
Dennis Eckerskorn 2024-12-05 23:32:24 +01:00
parent c24f3e2460
commit 9957e6f766
11 changed files with 202 additions and 98 deletions

Binary file not shown.

Binary file not shown.

View File

@ -1,88 +1,77 @@
import psutil import psutil
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import threading import tkinter as tk
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}")
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): def init_graphs(self):
"""Actualiza un gráfico con nuevos datos.""" """Crea gráficos para todas las métricas."""
graph = self.graphs[metric] for metric, config in self.metrics.items():
x = list(range(len(data))) fig, ax, line = self.create_graph(metric)
graph["line"].set_data(x, data) self.graphs[metric] = {"figure": fig, "axis": ax, "line": line}
graph["axis"].set_xlim(0, len(data))
graph["figure"].canvas.draw()
def stop_threads(self): def create_graph(self, title):
"""Detiene la ejecución de todos los hilos de monitoreo.""" """Crea un gráfico para una métrica específica."""
self.running = False 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)

View File

@ -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()

View File

@ -1,35 +1,86 @@
import threading
import datetime import datetime
import time import time
import requests import requests
import random import random
from services.threaden_task import ThreadenTask
from services.system_monitor import SystemMonitor
class ThreadsManager: class ThreadsManager:
"""Constructor"""
def __init__(self, ui_instance): def __init__(self, ui_instance):
self.ui_instance = 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): def start_threads(self):
# Hilo para actualizar el reloj """Se inician los hilos, Tiempo, Temperatura, Emails"""
threading.Thread(target=self.update_time, daemon=True).start() 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 if self.system_monitor:
threading.Thread(target=self.update_temperature, daemon=True).start() 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): def update_time(self):
while True: while self.tasks["time"].running:
current_time = datetime.datetime.now().strftime('%H:%M:%S') current_time = datetime.datetime.now().strftime('%H:%M:%S')
current_date = datetime.datetime.now().strftime('%d/%m/%Y') 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["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}")) self.ui_instance.after(0, lambda: self.ui_instance.info_labels["fecha"].configure(text=f"Fecha: {current_date}"))
time.sleep(1) time.sleep(1)
def update_temperature(self): def update_temperature(self):
API_KEY = "4ba2b87d7fa32934530b5b4a5a83ebf7" # Reemplaza con tu clave de OpenWeatherMap API_KEY = "4ba2b87d7fa32934530b5b4a5a83ebf7" # Reemplaza con tu clave de OpenWeatherMap
CITY = "Madrid" # Cambia por tu ciudad CITY = "Madrid" # Cambia por tu ciudad
while True: while self.tasks["temperature"].running:
try: try:
temperature = self.get_real_temperature(API_KEY, CITY) temperature = self.get_real_temperature(API_KEY, CITY)
if temperature is not None: if temperature is not None:
@ -41,6 +92,8 @@ class ThreadsManager:
print(f"Error al obtener la temperatura: {e}") print(f"Error al obtener la temperatura: {e}")
time.sleep(600) # Actualiza cada 10 minutos time.sleep(600) # Actualiza cada 10 minutos
def get_real_temperature(self, api_key, city): 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" url = f"http://api.openweathermap.org/data/2.5/weather?q={city}&appid={api_key}&units=metric"
response = requests.get(url) response = requests.get(url)
@ -50,13 +103,17 @@ class ThreadsManager:
else: else:
print(f"Error al obtener la temperatura: {response.status_code}") print(f"Error al obtener la temperatura: {response.status_code}")
return None return None
def update_emails(self): def update_emails(self):
count = 0 count = 0
while True: while self.tasks["emails"].running:
count += random.randint(0, 2) # Simula la llegada de 0-2 correos count += random.randint(0, 2) # Simula la llegada de 0-2 correos
self.ui_instance.after( self.ui_instance.after(
0, 0,
lambda: self.ui_instance.info_labels["emails"].configure(text=f"Correos sin leer: {count}") 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

Binary file not shown.

Binary file not shown.

View File

@ -8,18 +8,19 @@ import threading
from services.threads_manager import ThreadsManager from services.threads_manager import ThreadsManager
from services.processes_manager import ProcessManager from services.processes_manager import ProcessManager
from services.tetris_game import TetrisGame from services.tetris_game import TetrisGame
from services.system_monitor import SystemMonitor
class CenteredWindow(ctk.CTk): class CenteredWindow(ctk.CTk):
def __init__(self, title="MultiApp", width_percentage=0.8, height_percentage=0.8): def __init__(self, title="MultiApp", width_percentage=0.8, height_percentage=0.8):
# Inicializacion de la clase: # Inicializacion de la clase:
super().__init__() super().__init__()
# Titulo de la ventana:
self.title(title) self.title(title)
# Inicializar managers (orden es importante)
self.thread_manager = ThreadsManager(self) self.thread_manager = ThreadsManager(self)
self.process_manager = ProcessManager() self.process_manager = ProcessManager()
self.system_monitor = None
# Obtener la resolucion de la pantalla: # Obtener la resolucion de la pantalla:
screen_width = self.winfo_screenwidth() screen_width = self.winfo_screenwidth()
@ -38,6 +39,8 @@ class CenteredWindow(ctk.CTk):
#Configura la ventana #Configura la ventana
self.configure_window() self.configure_window()
self.protocol("WM_DELETE_WINDOW", self.on_close)
def configure_window(self): def configure_window(self):
# Configuracion de la ventana: # Configuracion de la ventana:
self.configure(bg_color="lightgray") self.configure(bg_color="lightgray")
@ -45,8 +48,18 @@ class CenteredWindow(ctk.CTk):
self.create_right_panel() self.create_right_panel()
self.create_center_panel() self.create_center_panel()
self.create_bottom_bar() self.create_bottom_bar()
self.thread_manager.start_threads() 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): def create_left_panel(self):
# Panel izquierdo # Panel izquierdo
left_panel = ctk.CTkFrame(self, width=200) 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 = ctk.CTkButton(left_panel, text=text, command=command, width=150)
btn.pack(pady=5, padx=10) btn.pack(pady=5, padx=10)
def create_center_panel(self): def create_center_panel(self):
# Panel central con pestañas # Panel central con pestañas
center_panel = ctk.CTkFrame(self) center_panel = ctk.CTkFrame(self)
@ -82,7 +97,18 @@ class CenteredWindow(ctk.CTk):
for tab_name in ["Resultados Scrapping", "Navegador", "Correos", "Juego", "Sistema"]: for tab_name in ["Resultados Scrapping", "Navegador", "Correos", "Juego", "Sistema"]:
tab = tab_view.add(tab_name) 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 # Crear un marco intermedio para centrar
game_frame = ctk.CTkFrame(tab) game_frame = ctk.CTkFrame(tab)
game_frame.pack(expand=True) 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 = ctk.CTkLabel(tab, text=f"Contenido de {tab_name}", font=("Arial", 12))
label.pack(pady=10) label.pack(pady=10)
def start_tetris_game(self): def start_tetris_game(self):
"""Método para iniciar el juego.""" """Método para iniciar el juego."""
if not self.tetris_game.running: if not self.tetris_game.running:
self.tetris_game.running = True self.tetris_game.running = True
self.tetris_game.update_game() self.tetris_game.update_game()
def pause_tetris_game(self): def pause_tetris_game(self):
"""Método para pausar el juego.""" """Método para pausar el juego."""
self.tetris_game.running = False self.tetris_game.running = False
def restart_tetris_game(self): def restart_tetris_game(self):
"""Método para reiniciar el juego.""" """Método para reiniciar el juego."""
self.tetris_game.reset_game() self.tetris_game.reset_game()
@ -153,6 +185,8 @@ class CenteredWindow(ctk.CTk):
) )
student_info.pack(anchor=ctk.W, padx=10) student_info.pack(anchor=ctk.W, padx=10)
def create_bottom_bar(self): def create_bottom_bar(self):
# Crear la barra inferior # Crear la barra inferior
self.bottom_bar = ctk.CTkFrame(self, fg_color="lightblue", height=40) 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(): for label in self.info_labels.values():
label.pack(side=ctk.LEFT, padx=10, pady=5) label.pack(side=ctk.LEFT, padx=10, pady=5)
def dummy_action(self): def dummy_action(self):
print("Acción no implementada") print("Acción no implementada")