setup factor 打包界面 按钮操作

前段时间项目结项需要打包发布,使用了一下SetupFactory,感觉还不错,就把打包过程记录了下来备忘。

       1.下载一个Setup Factory,安装到电脑,我下载的是Setup Factory 7。

       2. 启动软件,根据向导创建一个新的工程,如下图:

              

 

         3.根据向导一路“下一步”完成新建工程,然后向工程里面添加需要打包的文件。

           

       

        4. 修改安装包主题样式,点击如下图“工程主题“按钮,修改主题风格,点击如下图所标出的编辑按钮可以修改安装界面上的一些属性,显示图片等等。

                  

         5. 如果我们程序可以支持多种安装方式或者多种安装版本之类的需求,就要给安装包做分包了,这里相对比较麻烦,可以分3步来实现。

         (1)点击“任务”栏中“设置”标签中的“程序包”,新建你需要安装的版本程序包。

         

 

        (2)在“存档”列表中选择文件右击点击弹出菜单中的“文件属性”,弹出框中选择“程序包”标签,选中此文件所属的程序包。

             

 

          (3) 选中“任务”栏中,“安装之前”,添加一个单选按钮界面,自动被命名为“单选按钮”界面,双击他进入编辑界面,在“设置”标签中设置按钮的个数,已经显示的名称,在“属性”标签中设置该窗体的名称,在“操作”标签中添加该窗体的处理代码。

            

 

            

 

         该窗体的OnNext代码示例如下:

[vb]  view plain copy
  1. SetupData.SetPackageProperties("All", {Install = false});  
  2. SetupData.SetPackageProperties("C#", {Install = false});  
  3. SetupData.SetPackageProperties("C++", {Install = false});  
  4. SetupData.SetPackageProperties("Android", {Install = false});  
  5.   
  6. nSelectedCtrl = String.ToNumber(SessionVar.Expand("%RadioSelection%"));  
  7.   
  8. if(nSelectedCtrl == CTRL_RADIO_BUTTON_01) then   
  9.             SetupData.SetPackageProperties("All", {Install = true});  
  10.             Screen.Jump("准备安装");  
  11. elseif(nSelectedCtrl == CTRL_RADIO_BUTTON_02) then   
  12.             SetupData.SetPackageProperties("C#", {Install = true});  
  13.             Screen.Jump("准备安装");      
  14. elseif(nSelectedCtrl == CTRL_RADIO_BUTTON_03) then   
  15.             SetupData.SetPackageProperties("C++", {Install = true});  
  16.             Screen.Jump("准备安装");  
  17. elseif(nSelectedCtrl == CTRL_RADIO_BUTTON_04) then   
  18.             SetupData.SetPackageProperties("Android", {Install = true});  
  19.             Screen.Jump("准备安装");  
  20. End  


          6.两种方式设置程序的快捷方式

          (1) 在需要设置快捷方式的文件上右键选择“文件属性”,然后在弹出的对话框中,选中“快捷方式”标签设置该文件的快捷方式。

          (2)在安装文件全部解压拷贝完成之后使用Shell命令来设置快捷方式。代码示例如下:

[vb]  view plain copy
  1. Shell.CreateShortcut("%StartProgramsFolder%\\HiMap\\Tools","HiMapDataConversion","%AppFolder%\\HiMap 1.0\\ToolKit\\HiMapDataConversion.exe");  
  2. Shell.CreateShortcut("%StartProgramsFolder%\\HiMap\\Tools","HiMapViewer","%AppFolder%\\HiMap 1.0\\ToolKit\\HiMapViewer.exe");  
  3. Shell.CreateShortcut("%StartProgramsFolder%\\HiMap\\Help","Hi-Map For .NET Help.chm","%AppFolder%\\HiMap 1.0\\Documents\\Hi-Map For .NET Help.chm");  
  4. Shell.CreateShortcut("%StartProgramsFolder%\\HiMap\\Help","Hi-Map For Android Help.chm","%AppFolder%\\HiMap 1.0\\Documents\\Hi-Map For Android Help.chm");  
  5. Shell.CreateShortcut("%StartProgramsFolder%\\HiMap\\Help","Hi-Map For Windows Mobile Help.chm","%AppFolder%\\HiMap 1.0\\Documents\\Hi-Map For Windows Mobile Help.chm");  

    

    上述两种方式都可以实现快捷方式的添加,但是第一种方式实现非常简单,但是却难以适用于自定义路径下的快捷方式;第二种方式非常灵活,但是需要自己写代码,代码添加的位置也比较关键,并且卸载程序不会自动删除这种方式创建的快捷方式,还需要在卸载设置中添加如下代码,来删除已删除的程序的快捷方式,代码示例如下:

[vb]  view plain copy
  1. Shell.DeleteShortcut("%StartProgramsFolder%\\HiMap\\Tools","HiMapDataConversion","%AppFolder%\\HiMap 1.0\\ToolKit\\HiMapDataConversion.exe");  
  2. Shell.DeleteShortcut("%StartProgramsFolder%\\HiMap\\Tools","HiMapViewer","%AppFolder%\\HiMap 1.0\\ToolKit\\HiMapViewer.exe");  
  3. Shell.DeleteShortcut("%StartProgramsFolder%\\HiMap\\Help","Hi-Map For .NET Help.chm","%AppFolder%\\HiMap 1.0\\Documents\\Hi-Map For .NET Help.chm");  
  4. Shell.DeleteShortcut("%StartProgramsFolder%\\HiMap\\Help","Hi-Map For Android Help.chm","%AppFolder%\\HiMap 1.0\\Documents\\Hi-Map For Android Help.chm");  
  5. Shell.DeleteShortcut("%StartProgramsFolder%\\HiMap\\Help","Hi-Map For Windows Mobile Help.chm","%AppFolder%\\HiMap 1.0\\Documents\\Hi-Map For Windows Mobile Help.chm");  
  6.   
  7. Folder.Delete("%StartProgramsFolder%\\HiMap\\Tools");  
  8. Folder.Delete("%StartProgramsFolder%\\HiMap\\Help");  

 

      最后只需要点击一下工具条上的“构建”啦……

 

             Thanks god~ 经过以上六步你就可以很顺利的制作出来一个比较简单的安装包了。

import os import sys import io import socket import time import re import threading import tkinter as tk import ttkbootstrap as tb import psutil import math import random import subprocess import json import queue from ttkbootstrap.constants import * from PIL import Image, ImageTk, ImageDraw # ====================== 数据采集服务 ====================== class HardwareMonitorService: def __init__(self): self.config = self.read_config() if self.config is None: raise Exception("配置读取失败,无法启动服务") self.server_ip = self.config.get('SERVER_IP') self.server_port = int(self.config.get('SERVER_PORT')) self.client_ip = self.config.get('CLIENT_IP') self.client_port = int(self.config.get('CLIENT_PORT')) self.running = True self.sock = None self.send_count = 1 self.setup_socket() # 启动服务线程 self.service_thread = threading.Thread(target=self.run_service, daemon=True) self.service_thread.start() def read_config(self): config = {} try: with open('config.txt', 'r') as config_file: for line in config_file: if '=' in line: key, value = line.strip().split('=', 1) config[key] = value print("读取配置成功", flush=True) return config except FileNotFoundError: print("无法打开配置文件!", flush=True) return None def is_command_available(self, command): """检查命令是否可用""" if os.name == 'nt': # Windows 系统 result = os.system(f'where {command} >nul 2>&1') else: # Linux 系统 result = os.system(f'which {command} >/dev/null 2>&1') return result == 0 def get_hardware_info(self, send_count): # 初始化硬件信息字典 hardware_data = { "cpu_temp": 0.0, "power": 0.0, "memory_used": 0, "memory_total": 0, "bandwidth": 0.0, "mlu_usage": 0.0, "cpu_usage": 0.0 } try: # 获取温度信息 result_temp = subprocess.run( ['cnmon', 'info', '-e'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=1.0, check=True ).stdout.decode('utf-8') temp_match = re.search(r"Board\s*[::]?\s*([-+]?\d*\.?\d+)\s*[cC°]", result_temp) if temp_match: hardware_data["cpu_temp"] = float(temp_match.group(1)) # 获取功耗信息 result_power = subprocess.run( ['cnmon', 'info', '-p'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=1.0, check=True ).stdout.decode('utf-8') power_match = re.search(r"Usage\s+:\s+(\d+\.?\d*)\s*W", result_power) if power_match: hardware_data["power"] = float(power_match.group(1)) # 获取内存信息 result_memory = subprocess.run( ['cnmon', 'info', '-m'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=1.0, check=True ).stdout.decode('utf-8') mem_match = re.search(r"Used\s+:\s+(\d+)\s*MiB.*?Total\s+:\s+(\d+)\s*MiB", result_memory, re.DOTALL) if mem_match: hardware_data["memory_used"] = int(mem_match.group(1)) hardware_data["memory_total"] = int(mem_match.group(2)) # 获取带宽信息 result_bandwidth = subprocess.run( ['cnmon', 'info', '-b'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=1.0, check=True ).stdout.decode('utf-8') bw_match = re.search(r"Bandwidth\s+:\s+([\d.]+)\s*GB/s", result_bandwidth) if bw_match: hardware_data["bandwidth"] = float(bw_match.group(1)) # 获取利用率信息 result_usage = subprocess.run( ['cnmon', 'info', '-u'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=1.0, check=True ).stdout.decode('utf-8') mlu_match = re.search(r"MLU Average\s+:\s+(\d+) %", result_usage) if mlu_match: hardware_data["mlu_usage"] = float(mlu_match.group(1)) cpu_match = re.search(r"Device CPU Chip\s+:\s+(\d+) %", result_usage) if cpu_match: hardware_data["cpu_usage"] = float(cpu_match.group(1)) except Exception as e: print(f"硬件信息获取错误: {e}") # 返回模拟数据 return self.get_fallback_data(send_count) # 添加发送次数 hardware_data["send_count"] = send_count return json.dumps(hardware_data) def get_fallback_data(self, send_count): """返回全0数据""" return json.dumps({ "cpu_temp":0.0, "power": 0.0, "memory_used": 0, "memory_total": 0, "bandwidth": 0.0, "mlu_usage": 0.0, "cpu_usage": 0.0, "send_count": send_count }) def setup_socket(self): """设置UDP套接字""" try: # 创建 UDP 套接字 self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 端口号快速重用 self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 绑定服务器 IP 和端口 self.sock.bind((self.server_ip, self.server_port)) print(f"绑定到 {self.server_ip}:{self.server_port}", flush=True) except OSError as e: print(f"绑定错误: {e}", flush=True) self.running = False def run_service(self): print("硬件监控服务已启动", flush=True) while self.running: try: if not self.is_command_available('cnmon'): # 模拟数据 info = self.get_fallback_data(self.send_count) else: # 获取真实数据 info = self.get_hardware_info(self.send_count) # 发送JSON数据到客户端 self.sock.sendto(info.encode(), (self.client_ip, self.client_port)) self.send_count += 1 time.sleep(0.5) except Exception as e: print(f"服务错误: {e}", flush=True) time.sleep(1) def stop_service(self): """停止数据采集服务""" self.running = False if self.sock: self.sock.close() print("硬件监控服务已停止", flush=True) # ====================== GUI 监控界面 ====================== class EnhancedCircularProgressBar: def __init__(self, parent, size=200, thickness=20, bg_color="#1a1a1a", fg_color="#4caf50", text_color="#ffffff", font_size=16, title="", unit="", max_value=100, glow_effect=True): self.parent = parent self.size = size self.thickness = thickness self.bg_color = bg_color self.fg_color = fg_color self.text_color = text_color self.font_size = font_size self.title = title self.unit = unit self.max_value = max_value self.glow_effect = glow_effect # 创建Canvas self.canvas = tk.Canvas( parent, width=size, height=size, bg="black", highlightthickness=0, bd=0 ) # 计算圆心和半径 self.center_x = size / 2 self.center_y = size / 2 self.radius = (size - thickness) / 2 - 5 # 创建渐变效果 self.create_gradient() # 绘制背景圆环 self.draw_background() # 创建进度弧 self.arc_id = self.canvas.create_arc( self.center_x - self.radius, self.center_y - self.radius, self.center_x + self.radius, self.center_y + self.radius, start=90, extent=0, style=tk.ARC, outline="", width=thickness, tags="progress" ) # 创建发光效果 if self.glow_effect: self.glow_id = self.canvas.create_oval( self.center_x - self.radius - 5, self.center_y - self.radius - 5, self.center_x + self.radius + 5, self.center_y + self.radius + 5, outline="", fill="", tags="glow" ) # 创建文本元素 self.create_text_elements() # 动画控制变量 self.current_value = 0 self.target_value = 0 self.animation_running = False self.animation_id = None self.last_update_time = time.time() # 性能优化 self.canvas.tag_raise("progress") self.canvas.tag_raise("text") def create_gradient(self): """创建渐变背景效果""" self.gradient_img = Image.new("RGBA", (self.size, self.size), (0, 0, 0, 0)) draw = ImageDraw.Draw(self.gradient_img) for r in range(int(self.radius), 0, -1): alpha = int(150 * (1 - r/self.radius)) draw.ellipse([ self.center_x - r, self.center_y - r, self.center_x + r, self.center_y + r ], outline=(40, 40, 40, alpha)) self.gradient_photo = ImageTk.PhotoImage(self.gradient_img) self.canvas.create_image( self.center_x, self.center_y, image=self.gradient_photo, tags="background" ) def draw_background(self): """绘制背景圆环""" self.bg_arc_id = self.canvas.create_arc( self.center_x - self.radius, self.center_y - self.radius, self.center_x + self.radius, self.center_y + self.radius, start=0, extent=359.9, style=tk.ARC, outline=self.bg_color, width=self.thickness, tags="background" ) def create_text_elements(self): """创建所有文本元素""" # 标题文本 self.title_id = self.canvas.create_text( self.center_x, self.center_y - self.radius * 0.5, text=self.title, fill=self.text_color, font=("Arial", self.font_size, "bold"), tags="text" ) # 数值文本 self.value_id = self.canvas.create_text( self.center_x, self.center_y, text="0", fill=self.text_color, font=("Arial", int(self.font_size * 1.8), "bold"), tags="text" ) # 单位文本 self.unit_id = self.canvas.create_text( self.center_x, self.center_y + self.radius * 0.3, text=self.unit, fill=self.text_color, font=("Arial", self.font_size - 2), tags="text" ) def calculate_color(self, value): """实现绿→黄→橙→红颜色过渡""" ratio = value / self.max_value if ratio <= 0.5: # 绿(0,255,0) → 黄(255,255,0) r = int(510 * ratio) g = 255 b = 0 elif ratio <= 0.75: # 黄(255,255,0) → 橙(255,165,0) r = 255 g = int(255 - 360 * (ratio - 0.5)) # 255 → 165 b = 0 else: # 橙(255,165,0) → 红(255,0,0) r = 255 g = int(165 - 660 * (ratio - 0.75)) # 165 → 0 b = 0 return f"#{r:02x}{g:02x}{b:02x}" def set_value(self, value): """设置目标值""" self.target_value = max(0, min(self.max_value, value)) # 更新数值显示 self.canvas.itemconfig(self.value_id, text=f"{self.target_value:.1f}") # 启动动画 if not self.animation_running: self.animate() def animate(self): """平滑动画更新进度""" self.animation_running = True # 计算插值(使用缓动函数) delta = self.target_value - self.current_value speed_factor = 0.2 # 控制动画速度 if abs(delta) > 0.1: self.current_value += delta * speed_factor else: self.current_value = self.target_value # 计算弧的角度 angle = 360 * (self.current_value / self.max_value) # 更新弧 self.canvas.itemconfig(self.arc_id, extent=-angle) # 更新颜色 color = self.calculate_color(self.current_value) self.canvas.itemconfig(self.arc_id, outline=color) # 更新发光效果 if self.glow_effect and time.time() - self.last_update_time > 0.1: self.update_glow_effect(color) self.last_update_time = time.time() # 继续动画或停止 if abs(self.current_value - self.target_value) > 0.5: self.animation_id = self.canvas.after(16, self.animate) else: self.current_value = self.target_value self.animation_running = False self.animation_id = None def update_glow_effect(self, color): """更新发光效果""" if not self.glow_effect: return # 创建新的发光图像 glow_img = Image.new("RGBA", (self.size, self.size), (0, 0, 0, 0)) draw = ImageDraw.Draw(glow_img) # 解析颜色 r = int(color[1:3], 16) g = int(color[3:5], 16) b = int(color[5:7], 16) # 绘制发光效果 for i in range(1, 6): alpha = int(50 * (1 - i/6)) radius = self.radius + i draw.ellipse([ self.center_x - radius, self.center_y - radius, self.center_x + radius, self.center_y + radius ], outline=(r, g, b, alpha), width=1) self.glow_photo = ImageTk.PhotoImage(glow_img) self.canvas.itemconfig(self.glow_id, image=self.glow_photo) def reset(self): """重置进度条""" if self.animation_id: self.canvas.after_cancel(self.animation_id) self.current_value = 0 self.target_value = 0 self.canvas.itemconfig(self.arc_id, extent=0) self.canvas.itemconfig(self.value_id, text="0") color = self.calculate_color(0) self.canvas.itemconfig(self.arc_id, outline=color) class SystemMonitorApp: def __init__(self): # 启动数据采集服务 try: self.monitor_service = HardwareMonitorService() client_ip = self.monitor_service.client_ip client_port = self.monitor_service.client_port except Exception as e: print(f"无法启动数据采集服务: {e}") self.monitor_service = None client_ip = "127.0.0.1" client_port = 9999 # 创建主窗口 self.root = tb.Window(themename="darkly", title="系统资源监控", size=(1300, 800)) self.root.iconbitmap("") self.root.minsize(1000, 700) # 设置样式 style = tb.Style() style.configure("TFrame", background="#121212") style.configure("Title.TLabel", background="#121212", foreground="#e0e0e0", font=("Arial", 16, "bold")) # 创建UDP接收套接字 self.udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) try: self.udp_socket.bind((client_ip, client_port)) print(f"GUI绑定到 {client_ip}:{client_port} 接收数据") except Exception as e: print(f"GUI绑定错误: {e}") self.udp_socket.settimeout(0.1) # 设置超时避免阻塞 # 存储真实数据的变量 self.real_data = { "cpu_temp": 0.0, "power": 0.0, "memory": 0.0, # 内存使用百分比 "bandwidth": 0.0, # 带宽,单位GB/s "mlu_usage": 0.0, "cpu_usage": 0.0 } # 数据更新队列(用于线程安全) self.data_queue = queue.Queue() # 创建主架 - 改为水平分割布局 main_frame = tb.Frame(self.root, padding=10) main_frame.pack(fill=tk.BOTH, expand=True) # ========== 左侧控制面板 ========== left_panel = tb.Frame(main_frame, width=220, padding=10) left_panel.pack(side=tk.LEFT, fill=tk.Y, padx=(0, 10)) # 下拉选项按钮 tb.Label(left_panel, text="选择监控设备", bootstyle=PRIMARY).pack(anchor=tk.W, pady=(0, 5)) self.device_var = tk.StringVar() device_options = ["设备A", "设备B", "设备C", "设备D"] device_combo = tb.Combobox( left_panel, textvariable=self.device_var, values=device_options, state="readonly", bootstyle=PRIMARY ) device_combo.pack(fill=tk.X, pady=(0, 20)) device_combo.current(0) # 设置默认选项 # 其他控制选项 tb.Label(left_panel, text="监控设置", bootstyle=PRIMARY).pack(anchor=tk.W, pady=(10, 5)) # 采样频率滑块 self.sampling_rate = tk.IntVar(value=1) tb.Label(left_panel, text="采样频率(秒):").pack(anchor=tk.W) tb.Scale( left_panel, from_=0.5, to=5, length=180, orient=tk.HORIZONTAL, variable=self.sampling_rate, bootstyle=PRIMARY ).pack(fill=tk.X, pady=(0, 15)) # 报警阈值设置 tb.Label(left_panel, text="温度报警阈值(°C):").pack(anchor=tk.W) self.temp_threshold = tk.IntVar(value=80) tb.Entry( left_panel, textvariable=self.temp_threshold, width=10, bootstyle=PRIMARY ).pack(fill=tk.X, pady=(0, 15)) # 控制按钮 control_frame = tb.Frame(left_panel) control_frame.pack(fill=tk.X, pady=(10, 0)) tb.Button( control_frame, text="启动", bootstyle=SUCCESS, command=self.start_monitoring ).pack(side=tk.LEFT, padx=2) tb.Button( control_frame, text="暂停", bootstyle=DANGER, command=self.stop_monitoring ).pack(side=tk.LEFT, padx=2) tb.Button( control_frame, text="重置", bootstyle=WARNING, command=self.reset_all ).pack(side=tk.LEFT, padx=2) # 状态指示器 tb.Label(left_panel, text="连接状态", bootstyle=PRIMARY).pack(anchor=tk.W, pady=(15, 5)) self.status_indicator = tb.Label( left_panel, text="● 已连接", bootstyle=(SUCCESS, INVERSE), font=("Arial", 10) ) self.status_indicator.pack(fill=tk.X, pady=(0, 5)) # ========== 右侧监控面板 ========== right_panel = tb.Frame(main_frame) right_panel.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True) # 标题 tb.Label( right_panel, text="系统资源实时监控", style="Title.TLabel" ).pack(pady=(0, 15)) # 创建进度条容器架 progress_container = tb.Frame(right_panel) progress_container.pack(fill=tk.BOTH, expand=True, pady=5) # 创建监控指标配置 (保持不变) monitor_config = [ {"title": "CPU温度", "unit": "°C", "max_value": 100, "thickness": 18, "fg_color": "#ff5555"}, {"title": "功耗", "unit": "W", "max_value": 200, "thickness": 18, "fg_color": "#ffaa00"}, {"title": "内存使用", "unit": "%", "max_value": 100, "thickness": 18, "fg_color": "#55aaff"}, {"title": "网络带宽", "unit": "Mbps", "max_value": 1000, "thickness": 18, "fg_color": "#aa55ff"}, {"title": "MLU利用率", "unit": "%", "max_value": 100, "thickness": 18, "fg_color": "#00cc99"}, {"title": "CPU利用率", "unit": "%", "max_value": 100, "thickness": 18, "fg_color": "#ff55ff"} ] # 使用网格布局排列进度条 (保持不变) self.progress_bars = [] for i, config in enumerate(monitor_config): frame = tb.Frame(progress_container) frame.grid(row=i//3, column=i%3, padx=15, pady=15, sticky="nsew") # 创建增强型进度条 progress_bar = EnhancedCircularProgressBar( frame, size=220, thickness=config["thickness"], title=config["title"], unit=config["unit"], max_value=config["max_value"], fg_color=config["fg_color"], glow_effect=True ) self.progress_bars.append(progress_bar) progress_bar.canvas.pack(fill=tk.BOTH, expand=True) # 设置网格列权重 (保持不变) for i in range(3): progress_container.columnconfigure(i, weight=1) for i in range(2): progress_container.rowconfigure(i, weight=1) # ========== 状态栏 ========== self.status = tb.Label( self.root, text="系统准备就绪 | 当前设备: 设备A", bootstyle=(SECONDARY, INVERSE), anchor=tk.CENTER ) self.status.pack(side=tk.BOTTOM, fill=tk.X) # 监控控制变量 self.monitoring_active = False self.monitoring_thread = None # 启动初始监控 self.start_monitoring() # 设置定时器处理数据队列 self.root.after(100, self.process_updates) # 窗口关闭事件处理 self.root.protocol("WM_DELETE_WINDOW", self.on_close) self.root.mainloop() def start_monitoring(self): """启动资源监控""" if self.monitoring_active: return self.status.config(text="启动系统资源监控...") self.monitoring_active = True # 使用线程运行监控,避免阻塞UI self.monitoring_thread = threading.Thread(target=self.monitor_resources, daemon=True) self.monitoring_thread.start() def stop_monitoring(self): """停止资源监控""" self.monitoring_active = False self.status.config(text="监控已暂停") def reset_all(self): """重置所有监控指标""" for bar in self.progress_bars: bar.reset() self.status.config(text="所有监控指标已重置") def receive_real_data(self): """接收并解析真实硬件数据""" try: data, _ = self.udp_socket.recvfrom(4096) data_str = data.decode('utf-8') try: # 解析JSON数据 data_dict = json.loads(data_str) # 更新real_data self.real_data["cpu_temp"] = data_dict.get("cpu_temp", 0.0) self.real_data["power"] = data_dict.get("power", 0.0) # 计算内存使用百分比 mem_used = data_dict.get("memory_used", 0) mem_total = data_dict.get("memory_total", 1) # 避免除零错误 if mem_total > 0: self.real_data["memory"] = (mem_used / mem_total) * 100 self.real_data["bandwidth"] = data_dict.get("bandwidth", 0.0) self.real_data["mlu_usage"] = data_dict.get("mlu_usage", 0.0) self.real_data["cpu_usage"] = data_dict.get("cpu_usage", 0.0) except json.JSONDecodeError: # 兼容旧版文本格式 self._legacy_parse(data_str) except socket.timeout: pass # 没有数据是正常的 except Exception as e: print(f"接收数据错误: {e}") def _legacy_parse(self, info_str): """兼容旧版文本格式解析""" try: # 解析CPU温度 temp_match = re.search(r"Board\s+:\s+(\d+\.?\d*)\s*C", info_str) if temp_match: self.real_data["cpu_temp"] = float(temp_match.group(1)) # 解析功耗 power_match = re.search(r"Usage\s+:\s+(\d+\.?\d*)\s*W", info_str) if power_match: self.real_data["power"] = float(power_match.group(1)) # 解析内存使用率 mem_match = re.search(r"Used\s+:\s+(\d+)\s*MiB.*?Total\s+:\s+(\d+)\s*MiB", info_str, re.DOTALL) if mem_match: used = float(mem_match.group(1)) total = float(mem_match.group(2)) if total > 0: self.real_data["memory"] = (used / total) * 100 # 解析带宽 bw_match = re.search(r"Bandwidth\s+:\s+([\d.]+)\s*GB/s", info_str) if bw_match: self.real_data["bandwidth"] = float(bw_match.group(1)) # 解析MLU利用率 mlu_match = re.search(r"MLU Average:\s*(\d+\.?\d*)%", info_str) if mlu_match: self.real_data["mlu_usage"] = float(mlu_match.group(1)) # 解析CPU利用率 cpu_match = re.search(r"Device CPU Chip:\s*(\d+\.?\d*)%", info_str) if cpu_match: self.real_data["cpu_usage"] = float(cpu_match.group(1)) except Exception as e: print(f"旧版解析错误: {e}") def monitor_resources(self): """监控系统资源""" while self.monitoring_active: # 接收并解析真实数据 self.receive_real_data() # 使用真实数据或模拟数据 cpu_temp = self.real_data["cpu_temp"] or self.get_cpu_temperature() power = self.real_data["power"] or self.get_power_usage() mem_usage = self.real_data["memory"] or self.get_memory_usage() # 带宽单位转换:GB/s → Mbps (1 GB/s = 8000 Mbps) bandwidth_gb = self.real_data["bandwidth"] network = bandwidth_gb * 8000 # 转换为Mbps if network <= 0: # 如果真实数据无效,使用模拟数据 network = self.get_network_usage() mlu_usage = self.real_data["mlu_usage"] or self.get_mlu_usage() cpu_usage = self.real_data["cpu_usage"] or psutil.cpu_percent() # 将数据放入队列,由主线程更新UI self.data_queue.put((cpu_temp, power, mem_usage, network, mlu_usage, cpu_usage)) time.sleep(1) def process_updates(self): """从队列中取出数据并更新UI(在主线程中调用)""" try: while not self.data_queue.empty(): data = self.data_queue.get_nowait() # 更新进度条 self.progress_bars[0].set_value(data[0]) self.progress_bars[1].set_value(data[1]) self.progress_bars[2].set_value(data[2]) self.progress_bars[3].set_value(data[3]) self.progress_bars[4].set_value(data[4]) self.progress_bars[5].set_value(data[5]) # 更新状态栏 status_text = ( f"CPU: {data[5]:.1f}% | " f"温度: {data[0]:.1f}°C | " f"内存: {data[2]:.1f}% | " f"MLU: {data[4]:.1f}%" ) self.status.config(text=status_text) except queue.Empty: pass # 每100毫秒检查一次 self.root.after(100, self.process_updates) def get_cpu_temperature(self): """获取CPU温度(模拟)""" base_temp = 40.0 fluctuation = random.uniform(-2, 8) load_factor = self.progress_bars[5].current_value / 100 * 10 return min(100, max(30, base_temp + fluctuation + load_factor)) def get_power_usage(self): """获取功耗使用(模拟)""" base_power = 80.0 fluctuation = random.uniform(-10, 15) load_factor = (self.progress_bars[5].current_value + self.progress_bars[4].current_value) / 200 * 50 return min(200, max(50, base_power + fluctuation + load_factor)) def get_memory_usage(self): """获取内存使用率""" return psutil.virtual_memory().percent def get_network_usage(self): """获取网络带宽使用(模拟)""" base_usage = 300.0 fluctuation = random.uniform(-50, 100) return min(1000, max(0, base_usage + fluctuation)) def get_mlu_usage(self): """获取MLU利用率(模拟)""" base_usage = 30.0 fluctuation = random.uniform(-5, 15) load_factor = random.uniform(0, 40) return min(100, max(0, base_usage + fluctuation + load_factor)) def change_theme(self): """更改应用主题""" theme = self.theme_var.get() tb.Style(theme=theme) self.status.config(text=f"主题已切换为: {theme.capitalize()}") def on_close(self): """窗口关闭时清理资源""" self.monitoring_active = False if self.monitoring_thread and self.monitoring_thread.is_alive(): self.monitoring_thread.join(timeout=2.0) try: if self.monitor_service: self.monitor_service.stop_service() self.udp_socket.close() except Exception as e: print(f"关闭资源时出错: {e}") self.root.destroy() if __name__ == "__main__": # 设置无缓冲输出 sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', line_buffering=True) # 启动GUI应用 SystemMonitorApp() 现在这段程序需要分为两部分,第一部分是服务端MLU220运行Server文件然后返回文本数据,第二部分是客户端主机接收服务端MLU220的文本数据并提取这些文本数据显示在主机写好的UI界面中,应该怎么拆开,使用Socket通讯。
最新发布
06-21
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值