|
本帖最后由 angenet 于 2025-3-10 13:13 编辑
非常简单的一个小工具,需要先在盒子中安装魔云腾超级SDK才能使用,自己在源码里修改IP地址即可,可以设置透明度,点击单行,会显示详细信息
代码如下:
- # 作者微信:ybjiaxu
- import tkinter as tk
- from tkinter import ttk
- import requests
- import threading
- from queue import Queue
- from datetime import datetime
- class FloatingMonitor:
- def __init__(self, master):
- self.master = master
- # 窗口属性设置
- master.overrideredirect(True) # 隐藏标题栏
- master.attributes('-topmost', True) # 窗口置顶
- master.attributes('-alpha', 0.9) # 默认透明度90%
-
- # 初始化拖动变量
- self._drag_data = {"x": 0, "y": 0, "dragging": False}
-
- # 设备配置
- self.devices = {
- "192.168.2.10": "http://192.168.2.10:83/systeminfo",
- "192.168.2.11": "http://192.168.2.11:83/systeminfo",
- "192.168.2.12": "http://192.168.2.12:83/systeminfo"
- }
-
- # 创建UI组件
- self.create_widgets()
- self.create_context_menu()
-
- # 绑定全局事件
- self.bind_global_events()
-
- # 启动数据线程
- self.queue = Queue()
- self.start_data_threads()
- self.process_queue()
- # 初始窗口位置
- self.master.geometry("+20+20")
- def create_widgets(self):
- # 主容器
- self.main_frame = ttk.Frame(self.master)
- self.main_frame.pack(padx=5, pady=5)
-
- # 设备信息显示
- self.device_frames = {}
- for ip in self.devices:
- frame = ttk.Frame(self.main_frame)
- frame.pack(fill=tk.X, pady=2)
-
- # 点击区域(保留原有功能)
- click_area = ttk.Label(frame, cursor="hand2")
- click_area.pack(fill=tk.X)
- click_area.bind("<Button-1>", lambda e, ip=ip: self.toggle_details(ip))
-
- # 基础信息
- labels = {
- 'ip': ttk.Label(click_area, text=ip, width=15),
- 'cpu': ttk.Label(click_area, text="CPU: --%"),
- 'temp': ttk.Label(click_area, text="温度: --℃"),
- 'mem': ttk.Label(click_area, text="内存: --%")
- }
- labels['ip'].pack(side=tk.LEFT)
- labels['cpu'].pack(side=tk.LEFT, padx=5)
- labels['temp'].pack(side=tk.LEFT, padx=5)
- labels['mem'].pack(side=tk.LEFT, padx=5)
-
- # 详细信息(初始隐藏)
- detail_frame = ttk.Frame(frame)
- detail_labels = {
- 'disk': ttk.Label(detail_frame, text="磁盘: --% (--GB)"),
- 'swap': ttk.Label(detail_frame, text="交换分区: --"),
- 'update': ttk.Label(detail_frame, text="最后更新: --")
- }
- for label in detail_labels.values():
- label.pack(anchor=tk.W)
-
- self.device_frames[ip] = {
- 'frame': frame,
- 'detail_frame': detail_frame,
- 'labels': labels,
- 'detail_labels': detail_labels,
- 'expanded': False
- }
- detail_frame.pack_forget()
- def bind_global_events(self):
- """绑定全局事件到所有组件"""
- # 绑定拖动事件到主窗口
- self.master.bind("<ButtonPress-1>", self.start_drag)
- self.master.bind("<B1-Motion>", self.on_drag)
- self.master.bind("<ButtonRelease-1>", self.stop_drag)
-
- # 绑定右键菜单到主窗口
- self.master.bind("<Button-3>", self.show_context_menu)
-
- # 阻止事件冒泡到子组件
- for child in self.main_frame.winfo_children():
- child.bind("<Button-1>", lambda e: "break") # 阻止子组件响应拖动
- child.bind("<B1-Motion>", lambda e: "break")
- child.bind("<ButtonRelease-1>", lambda e: "break")
- def create_context_menu(self):
- # 右键菜单
- self.context_menu = tk.Menu(self.master, tearoff=0)
- self.context_menu.add_command(label="透明度+", command=lambda: self.adjust_opacity(0.1))
- self.context_menu.add_command(label="透明度-", command=lambda: self.adjust_opacity(-0.1))
- self.context_menu.add_separator()
- self.context_menu.add_command(label="退出", command=self.quit_app)
- def adjust_opacity(self, delta):
- current = self.master.attributes('-alpha')
- new_alpha = max(0.3, min(1.0, current + delta))
- self.master.attributes('-alpha', new_alpha)
- def start_drag(self, event):
- """开始拖动"""
- self._drag_data["dragging"] = True
- self._drag_data["x"] = event.x_root
- self._drag_data["y"] = event.y_root
- def on_drag(self, event):
- """处理拖动"""
- if self._drag_data["dragging"]:
- delta_x = event.x_root - self._drag_data["x"]
- delta_y = event.y_root - self._drag_data["y"]
- x = self.master.winfo_x() + delta_x
- y = self.master.winfo_y() + delta_y
- self.master.geometry(f"+{x}+{y}")
- self._drag_data["x"] = event.x_root
- self._drag_data["y"] = event.y_root
- def stop_drag(self, event):
- """停止拖动"""
- self._drag_data["dragging"] = False
- def show_context_menu(self, event):
- self.context_menu.post(event.x_root, event.y_root)
- def quit_app(self):
- self.master.destroy()
- def toggle_details(self, ip):
- device = self.device_frames[ip]
- device['expanded'] = not device['expanded']
- if device['expanded']:
- device['detail_frame'].pack(fill=tk.X, pady=2)
- else:
- device['detail_frame'].pack_forget()
- def start_data_threads(self):
- for ip in self.devices:
- threading.Thread(
- target=self.fetch_data,
- args=(ip,),
- daemon=True
- ).start()
- def fetch_data(self, ip):
- while True:
- try:
- response = requests.get(self.devices[ip], timeout=3)
- if response.status_code == 200:
- data = response.json()['msg']
- self.queue.put((ip, data))
- else:
- self.queue.put((ip, None))
- except:
- self.queue.put((ip, None))
- threading.Event().wait(3)
- def process_queue(self):
- while not self.queue.empty():
- try:
- ip, data = self.queue.get_nowait()
- if data:
- self.update_ui(ip, data)
- else:
- self.show_error(ip)
- except:
- break
- self.master.after(100, self.process_queue)
- def update_ui(self, ip, data):
- device = self.device_frames[ip]
- # 基础信息
- device['labels']['cpu'].config(text=f"CPU: {data['cpu']:.1f}%")
- device['labels']['temp'].config(text=f"温度: {data['temperatures']:.1f}℃")
- device['labels']['mem'].config(text=f"内存: {data['mem_percent']:.1f}%")
- # 详细信息
- disk_total = round(data['disk_total'] / (1024**3), 1)
- device['detail_labels']['disk'].config(text=f"磁盘: {data['disk_percent']:.1f}% ({disk_total}GB)")
- swap_text = f"{data['swap_percent']:.1f}%" if data['swap_total'] !=0 else "未启用"
- device['detail_labels']['swap'].config(text=f"交换分区: {swap_text}")
- device['detail_labels']['update'].config(text=f"最后更新: {datetime.now().strftime('%H:%M:%S')}")
- def show_error(self, ip):
- device = self.device_frames[ip]
- device['labels']['cpu'].config(text="CPU: 错误")
- device['labels']['temp'].config(text="温度: 错误")
- device['labels']['mem'].config(text="内存: 错误")
- device['detail_labels']['disk'].config(text="磁盘: 获取失败")
- device['detail_labels']['swap'].config(text="交换分区: 获取失败")
- if __name__ == "__main__":
- root = tk.Tk()
- app = FloatingMonitor(root)
- root.mainloop()
复制代码
|
|