找回密码
 立即注册
搜索
查看: 65|回复: 0

开源,盒子资源占用监控,python源码

[复制链接]

1

主题

0

回帖

2890

积分

魔云会员

积分
2890
发表于 前天 13:08 | 显示全部楼层 |阅读模式
本帖最后由 angenet 于 2025-3-10 13:13 编辑

001.png

002.png

非常简单的一个小工具,需要先在盒子中安装魔云腾超级SDK才能使用,自己在源码里修改IP地址即可,可以设置透明度,点击单行,会显示详细信息
代码如下:
  1. # 作者微信:ybjiaxu
  2. import tkinter as tk
  3. from tkinter import ttk
  4. import requests
  5. import threading
  6. from queue import Queue
  7. from datetime import datetime

  8. class FloatingMonitor:
  9.     def __init__(self, master):
  10.         self.master = master
  11.         # 窗口属性设置
  12.         master.overrideredirect(True)       # 隐藏标题栏
  13.         master.attributes('-topmost', True)  # 窗口置顶
  14.         master.attributes('-alpha', 0.9)    # 默认透明度90%
  15.         
  16.         # 初始化拖动变量
  17.         self._drag_data = {"x": 0, "y": 0, "dragging": False}
  18.         
  19.         # 设备配置
  20.         self.devices = {
  21.             "192.168.2.10": "http://192.168.2.10:83/systeminfo",
  22.             "192.168.2.11": "http://192.168.2.11:83/systeminfo",
  23.             "192.168.2.12": "http://192.168.2.12:83/systeminfo"
  24.         }
  25.         
  26.         # 创建UI组件
  27.         self.create_widgets()
  28.         self.create_context_menu()
  29.         
  30.         # 绑定全局事件
  31.         self.bind_global_events()
  32.         
  33.         # 启动数据线程
  34.         self.queue = Queue()
  35.         self.start_data_threads()
  36.         self.process_queue()

  37.         # 初始窗口位置
  38.         self.master.geometry("+20+20")

  39.     def create_widgets(self):
  40.         # 主容器
  41.         self.main_frame = ttk.Frame(self.master)
  42.         self.main_frame.pack(padx=5, pady=5)
  43.         
  44.         # 设备信息显示
  45.         self.device_frames = {}
  46.         for ip in self.devices:
  47.             frame = ttk.Frame(self.main_frame)
  48.             frame.pack(fill=tk.X, pady=2)
  49.             
  50.             # 点击区域(保留原有功能)
  51.             click_area = ttk.Label(frame, cursor="hand2")
  52.             click_area.pack(fill=tk.X)
  53.             click_area.bind("<Button-1>", lambda e, ip=ip: self.toggle_details(ip))
  54.             
  55.             # 基础信息
  56.             labels = {
  57.                 'ip': ttk.Label(click_area, text=ip, width=15),
  58.                 'cpu': ttk.Label(click_area, text="CPU: --%"),
  59.                 'temp': ttk.Label(click_area, text="温度: --℃"),
  60.                 'mem': ttk.Label(click_area, text="内存: --%")
  61.             }
  62.             labels['ip'].pack(side=tk.LEFT)
  63.             labels['cpu'].pack(side=tk.LEFT, padx=5)
  64.             labels['temp'].pack(side=tk.LEFT, padx=5)
  65.             labels['mem'].pack(side=tk.LEFT, padx=5)
  66.             
  67.             # 详细信息(初始隐藏)
  68.             detail_frame = ttk.Frame(frame)
  69.             detail_labels = {
  70.                 'disk': ttk.Label(detail_frame, text="磁盘: --% (--GB)"),
  71.                 'swap': ttk.Label(detail_frame, text="交换分区: --"),
  72.                 'update': ttk.Label(detail_frame, text="最后更新: --")
  73.             }
  74.             for label in detail_labels.values():
  75.                 label.pack(anchor=tk.W)
  76.             
  77.             self.device_frames[ip] = {
  78.                 'frame': frame,
  79.                 'detail_frame': detail_frame,
  80.                 'labels': labels,
  81.                 'detail_labels': detail_labels,
  82.                 'expanded': False
  83.             }
  84.             detail_frame.pack_forget()

  85.     def bind_global_events(self):
  86.         """绑定全局事件到所有组件"""
  87.         # 绑定拖动事件到主窗口
  88.         self.master.bind("<ButtonPress-1>", self.start_drag)
  89.         self.master.bind("<B1-Motion>", self.on_drag)
  90.         self.master.bind("<ButtonRelease-1>", self.stop_drag)
  91.         
  92.         # 绑定右键菜单到主窗口
  93.         self.master.bind("<Button-3>", self.show_context_menu)
  94.         
  95.         # 阻止事件冒泡到子组件
  96.         for child in self.main_frame.winfo_children():
  97.             child.bind("<Button-1>", lambda e: "break")  # 阻止子组件响应拖动
  98.             child.bind("<B1-Motion>", lambda e: "break")
  99.             child.bind("<ButtonRelease-1>", lambda e: "break")

  100.     def create_context_menu(self):
  101.         # 右键菜单
  102.         self.context_menu = tk.Menu(self.master, tearoff=0)
  103.         self.context_menu.add_command(label="透明度+", command=lambda: self.adjust_opacity(0.1))
  104.         self.context_menu.add_command(label="透明度-", command=lambda: self.adjust_opacity(-0.1))
  105.         self.context_menu.add_separator()
  106.         self.context_menu.add_command(label="退出", command=self.quit_app)

  107.     def adjust_opacity(self, delta):
  108.         current = self.master.attributes('-alpha')
  109.         new_alpha = max(0.3, min(1.0, current + delta))
  110.         self.master.attributes('-alpha', new_alpha)

  111.     def start_drag(self, event):
  112.         """开始拖动"""
  113.         self._drag_data["dragging"] = True
  114.         self._drag_data["x"] = event.x_root
  115.         self._drag_data["y"] = event.y_root

  116.     def on_drag(self, event):
  117.         """处理拖动"""
  118.         if self._drag_data["dragging"]:
  119.             delta_x = event.x_root - self._drag_data["x"]
  120.             delta_y = event.y_root - self._drag_data["y"]
  121.             x = self.master.winfo_x() + delta_x
  122.             y = self.master.winfo_y() + delta_y
  123.             self.master.geometry(f"+{x}+{y}")
  124.             self._drag_data["x"] = event.x_root
  125.             self._drag_data["y"] = event.y_root

  126.     def stop_drag(self, event):
  127.         """停止拖动"""
  128.         self._drag_data["dragging"] = False

  129.     def show_context_menu(self, event):
  130.         self.context_menu.post(event.x_root, event.y_root)

  131.     def quit_app(self):
  132.         self.master.destroy()

  133.     def toggle_details(self, ip):
  134.         device = self.device_frames[ip]
  135.         device['expanded'] = not device['expanded']
  136.         if device['expanded']:
  137.             device['detail_frame'].pack(fill=tk.X, pady=2)
  138.         else:
  139.             device['detail_frame'].pack_forget()

  140.     def start_data_threads(self):
  141.         for ip in self.devices:
  142.             threading.Thread(
  143.                 target=self.fetch_data,
  144.                 args=(ip,),
  145.                 daemon=True
  146.             ).start()

  147.     def fetch_data(self, ip):
  148.         while True:
  149.             try:
  150.                 response = requests.get(self.devices[ip], timeout=3)
  151.                 if response.status_code == 200:
  152.                     data = response.json()['msg']
  153.                     self.queue.put((ip, data))
  154.                 else:
  155.                     self.queue.put((ip, None))
  156.             except:
  157.                 self.queue.put((ip, None))
  158.             threading.Event().wait(3)

  159.     def process_queue(self):
  160.         while not self.queue.empty():
  161.             try:
  162.                 ip, data = self.queue.get_nowait()
  163.                 if data:
  164.                     self.update_ui(ip, data)
  165.                 else:
  166.                     self.show_error(ip)
  167.             except:
  168.                 break
  169.         self.master.after(100, self.process_queue)

  170.     def update_ui(self, ip, data):
  171.         device = self.device_frames[ip]
  172.         # 基础信息
  173.         device['labels']['cpu'].config(text=f"CPU: {data['cpu']:.1f}%")
  174.         device['labels']['temp'].config(text=f"温度: {data['temperatures']:.1f}℃")
  175.         device['labels']['mem'].config(text=f"内存: {data['mem_percent']:.1f}%")
  176.         # 详细信息
  177.         disk_total = round(data['disk_total'] / (1024**3), 1)
  178.         device['detail_labels']['disk'].config(text=f"磁盘: {data['disk_percent']:.1f}% ({disk_total}GB)")
  179.         swap_text = f"{data['swap_percent']:.1f}%" if data['swap_total'] !=0 else "未启用"
  180.         device['detail_labels']['swap'].config(text=f"交换分区: {swap_text}")
  181.         device['detail_labels']['update'].config(text=f"最后更新: {datetime.now().strftime('%H:%M:%S')}")

  182.     def show_error(self, ip):
  183.         device = self.device_frames[ip]
  184.         device['labels']['cpu'].config(text="CPU: 错误")
  185.         device['labels']['temp'].config(text="温度: 错误")
  186.         device['labels']['mem'].config(text="内存: 错误")
  187.         device['detail_labels']['disk'].config(text="磁盘: 获取失败")
  188.         device['detail_labels']['swap'].config(text="交换分区: 获取失败")

  189. if __name__ == "__main__":
  190.     root = tk.Tk()
  191.     app = FloatingMonitor(root)
  192.     root.mainloop()
复制代码




手机版|魔云腾-论坛

GMT+8, 2025-3-12 19:13 , Processed in 0.050384 second(s), 23 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表