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 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)
|
|
@ -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 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.
|
@ -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")
|
Loading…
Reference in New Issue