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:
parent
c24f3e2460
commit
9957e6f766
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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)
|
|
@ -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()
|
|
@ -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.
|
@ -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")
|
Loading…
Reference in New Issue