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

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 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

Binary file not shown.

Binary file not shown.

View File

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