Core-Plot的.a文件不能支持armv6解决方法

本文介绍了一种将CorePlot图表库集成到iOS项目的简便方法,适合新手开发者使用。通过直接拷贝source目录下的源文件进行编译,可以轻松实现图表功能,并支持跟踪调试。

直接把source 和iPhone only下的文件拷出来自己编译,算是一种野蛮方法了吧。


之前网上也有很多人在找怎么在自己的工程里引用CorePlot,包括项目wiki和其他一些博客里介绍各种配置步骤。其实如果是新手,最简单方便的就是把source目录下的源码拷出来自己编译了,还可以跟踪调试XD。


import tkinter as tk from tkinter import ttk import socket import threading import matplotlib.pyplot as plt from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg from matplotlib.font_manager import FontProperties import subprocess # 指定黑体字体文件路径,需要根据实际情况修改 font_path = '/home/nvidia/test/simhei.ttf' font_prop = FontProperties(fname=font_path) plt.rcParams['font.family'] = font_prop.get_name() # 解决负号显示问题 plt.rcParams['axes.unicode_minus'] = False class DeviceManager(tk.Tk): def __init__(self): super().__init__() self.title("设备管理器") self.geometry("1100x900") self.resizable(False, False) self.configure(bg="#f9f9f9") self.devices = { "设备1": { "ip": "192.168.31.50", "status": "离线", "temperature": 0, "power": 0, "memory": 0, "bandwidth": 0, "send_count": 0, "mlu_avg_usage": 0, "cpu_avg_usage": 0, "mlu_core_usage": [1, 1, 1, 1], "cpu_core_usage": [1, 1, 1, 1] } } self.current_device = "设备1" self.current_page = 1 self.create_sidebar() self.create_pages() self.start_udp_receive() self.has_received_data = False self.frame_count = 0 # 用于标记页面2、页面3和页面4的折线图是否已初始化 self.page2_plots_initialized = False self.page3_plots_initialized = False self.page4_plots_initialized = False def create_sidebar(self): # 增大侧边栏宽度 self.sidebar = tk.Frame(self, bg="#e0e0e0", width=300) self.sidebar.pack(side="left", fill="y") # 增大按钮尺寸并增加与左侧边界的间距 button_style = ttk.Style() button_style.configure('TButton', font=('Arial', 16)) self.page1_button = ttk.Button(self.sidebar, text="主页面", command=lambda: self.show_page(1), style='TButton') self.page1_button.pack(pady=20, padx=30, fill=tk.X) self.page2_button = ttk.Button(self.sidebar, text="MLU", command=lambda: self.show_page(2), style='TButton') self.page2_button.pack(pady=20, padx=30, fill=tk.X) self.page3_button = ttk.Button(self.sidebar, text="CPU", command=lambda: self.show_page(3), style='TButton') self.page3_button.pack(pady=20, padx=30, fill=tk.X) self.page4_button = ttk.Button(self.sidebar, text="内存", command=lambda: self.show_page(4), style='TButton') self.page4_button.pack(pady=20, padx=30, fill=tk.X) def create_pages(self): self.pages = [] for i in range(4): page = tk.Frame(self, bg="#f9f9f9") page.pack(side="right", fill="both", expand=True, padx=20, pady=20) self.pages.append(page) self.create_page1() self.create_page2() self.create_page3() self.create_page4() self.show_page(1) def create_page1(self): self.info_frame = self.pages[0] self.ip_frame = tk.Frame(self.info_frame, bg="#f9f9f9") self.ip_frame.pack(pady=20, anchor="w") self.create_info_widget("IP 地址:", self.ip_frame, "ip") self.status_frame = tk.Frame(self.info_frame, bg="#f9f9f9") self.status_frame.pack(pady=20, anchor="w") self.create_info_widget("状态:", self.status_frame, "status") self.temp_frame = tk.Frame(self.info_frame, bg="#f9f9f9") self.temp_frame.pack(pady=20, anchor="w") self.create_info_widget("温度:", self.temp_frame, "temperature", "°C") self.power_frame = tk.Frame(self.info_frame, bg="#f9f9f9") self.power_frame.pack(pady=20, anchor="w") self.create_info_widget("功率:", self.power_frame, "power", "W") self.bandwidth_frame = tk.Frame(self.info_frame, bg="#f9f9f9") self.bandwidth_frame.pack(pady=20, anchor="w") self.create_info_widget("带宽:", self.bandwidth_frame, "bandwidth", "GB/s") # self.send_count_frame = tk.Frame(self.info_frame, bg="#f9f9f9") # self.send_count_frame.pack(pady=20) # self.create_info_widget("发送次数:", self.send_count_frame, "send_count") self.mlu_avg_frame = tk.Frame(self.info_frame, bg="#f9f9f9") self.mlu_avg_frame.pack(pady=20, anchor="w") self.create_info_widget("MLU 平均占用率:", self.mlu_avg_frame, "mlu_avg_usage", "%") self.cpu_avg_frame = tk.Frame(self.info_frame, bg="#f9f9f9") self.cpu_avg_frame.pack(pady=20, anchor="w") self.create_info_widget("CPU 平均占用率:", self.cpu_avg_frame, "cpu_avg_usage", "%") def create_info_widget(self, label_text, parent_frame, data_key, unit=""): label = ttk.Label(parent_frame, text=f"{label_text}", font=("Arial", 14, "bold"), background="#f9f9f9") label.pack(side="left", padx=5) value = ttk.Label(parent_frame, text="", font=("Arial", 14), background="#f9f9f9") value.pack(side="left", padx=5) setattr(self, f"{data_key}_value", value) if unit: setattr(self, f"{data_key}_unit", unit) def create_page2(self): self.mlu_figs = [] self.mlu_axs = [] self.mlu_xs = [[] for _ in range(4)] self.mlu_ys = [[] for _ in range(4)] self.mlu_lines = [] for i in range(4): fig = plt.Figure(figsize=(5, 5), dpi=80) ax = fig.add_subplot(111) line, = ax.plot([], [], lw=2) ax.set_xlabel('') ax.set_ylabel('占用率 (%)') ax.set_title(f'MLU 核 {i + 1} 占用率') ax.set_xlim(0, 20) ax.set_ylim(0, 100) # 手动设置横轴刻度 ax.set_xticks(range(0, 21, 5)) canvas = FigureCanvasTkAgg(fig, master=self.pages[1]) if i < 2: canvas.get_tk_widget().grid(row=0, column=i, padx=10, pady=10) else: canvas.get_tk_widget().grid(row=1, column=i - 2, padx=10, pady=10) self.mlu_figs.append(fig) self.mlu_axs.append(ax) self.mlu_lines.append(line) def create_page3(self): self.cpu_figs = [] self.cpu_axs = [] self.cpu_xs = [[] for _ in range(4)] self.cpu_ys = [[] for _ in range(4)] self.cpu_lines = [] for i in range(4): fig = plt.Figure(figsize=(5, 5), dpi=80) ax = fig.add_subplot(111) line, = ax.plot([], [], lw=2) ax.set_xlabel('') ax.set_ylabel('占用率 (%)') ax.set_title(f'CPU 核 {i + 1} 占用率') ax.set_xlim(0, 20) ax.set_ylim(0, 100) # 手动设置横轴刻度 ax.set_xticks(range(0, 21, 5)) canvas = FigureCanvasTkAgg(fig, master=self.pages[2]) if i < 2: canvas.get_tk_widget().grid(row=0, column=i, padx=10, pady=10) else: canvas.get_tk_widget().grid(row=1, column=i - 2, padx=10, pady=10) self.cpu_figs.append(fig) self.cpu_axs.append(ax) self.cpu_lines.append(line) def create_page4(self): self.memory_fig = plt.Figure(figsize=(10, 8), dpi=80) self.memory_ax = self.memory_fig.add_subplot(111) self.memory_line, = self.memory_ax.plot([], [], lw=2) self.memory_ax.set_xlabel('') self.memory_ax.set_ylabel('占用率 (%)') self.memory_ax.set_title('内存占用率') self.memory_ax.set_xlim(0, 20) self.memory_ax.set_ylim(0, 100) # 手动设置横轴刻度 self.memory_ax.set_xticks(range(0, 21, 5)) canvas = FigureCanvasTkAgg(self.memory_fig, master=self.pages[3]) canvas.get_tk_widget().pack(padx=10, pady=10) self.memory_xs = [] self.memory_ys = [] def show_page(self, page_num): for i, page in enumerate(self.pages): if i == page_num - 1: page.pack(side="right", fill="both", expand=True, padx=20, pady=20) self.current_page = page_num else: page.pack_forget() def update_device_info(self, info_str): info = self.parse_info(info_str) device = self.devices[self.current_device] device.update(info) self.update_display() if not self.has_received_data: self.has_received_data = True self.initialize_plots() def parse_info(self, info_str): info = {} sections = info_str.split("---------------END---------------")[0].split("\n\n") for section in sections: lines = [line.strip() for line in section.splitlines() if line.strip()] if not lines: continue key = lines[0].split(":")[0].strip() if key == "温度信息": info.update(self.parse_temperature(lines[1:])) elif key == "功率信息": info.update(self.parse_power(lines[1:])) elif key == "内存信息": info.update(self.parse_memory(lines)) elif key == "带宽信息": info.update(self.parse_bandwidth(lines[1:])) elif key == "发送次数": info.update(self.parse_send_count(lines)) elif key == "MLU信息": info.update(self.parse_mlu_avg_usage(lines)) info.update(self.parse_mlu_core_usage(lines)) elif key == "CPU信息": info.update(self.parse_cpu_avg_usage(lines)) info.update(self.parse_cpu_core_usage(lines)) return info def parse_temperature(self, lines): temp = 0 for line in lines: if "C" in line: try: temp = max(temp, float(line.split(":")[1].strip().replace(" C", ""))) except (IndexError, ValueError): continue return {"temperature": temp} def parse_power(self, lines): power = 0 for line in lines: if "W" in line: try: power = float(line.split(":")[1].strip().replace(" W", "")) except (IndexError, ValueError): continue return {"power": power} def parse_memory(self, lines): total = 0 used = 0 physical_memory_section = False for line in lines: if "Physical Memory Usage" in line: physical_memory_section = True elif physical_memory_section: if "Total" in line: total = self.parse_memory_value(line) elif "Used" in line: used = self.parse_memory_value(line) return {"memory": round(used / total * 100, 1) if total != 0 else 0} def parse_memory_value(self, line): try: value = line.split(":")[1].strip() num = float(value.split()[0]) unit = value.split()[1] if unit == "MiB": return num * 1024 * 1024 return num except (IndexError, ValueError): return 0 def parse_bandwidth(self, lines): bandwidth = 0 for line in lines: if "GB/s" in line: try: bandwidth = float(line.split(":")[1].strip().replace(" GB/s", "")) except (IndexError, ValueError): continue return {"bandwidth": bandwidth} def parse_send_count(self, lines): send_count = 0 for line in lines: if "次" in line: try: value_part = line.split(":")[-1].strip() send_count = float(value_part.replace("次", "")) except (IndexError, ValueError): continue return {"send_count": int(send_count)} def parse_mlu_avg_usage(self, lines): for line in lines: if "MLU Average" in line: try: parts = line.split(':') if len(parts) > 1: mlu_avg_usage = float(parts[1].strip().replace("%", "")) return {"mlu_avg_usage": mlu_avg_usage} except (IndexError, ValueError): continue return {"mlu_avg_usage": 0} def parse_cpu_avg_usage(self, lines): for line in lines: if "Device CPU Chip" in line: try: parts = line.split(':') if len(parts) > 1: cpu_avg_usage = float(parts[1].strip().replace("%", "")) return {"cpu_avg_usage": cpu_avg_usage} except (IndexError, ValueError): continue return {"cpu_avg_usage": 0} def parse_mlu_core_usage(self, lines): mlu_core_usage = [1, 1, 1, 1] for line in lines: if "MLU " in line and "%" in line: try: parts = line.split(':') core_num = int(parts[0].split('MLU ')[1]) usage = float(parts[1].strip().replace("%", "")) mlu_core_usage[core_num] = usage except (IndexError, ValueError) as e: pass return {"mlu_core_usage": mlu_core_usage} def parse_cpu_core_usage(self, lines): cpu_core_usage = [1, 1, 1, 1] for line in lines: if "Device CPU Core" in line and "%" in line: try: parts = line.split(':') core_num = int(parts[0].split('Device CPU Core ')[1]) usage = float(parts[1].strip().replace("%", "")) cpu_core_usage[core_num] = usage except (IndexError, ValueError) as e: pass return {"cpu_core_usage": cpu_core_usage} def update_display(self): device = self.devices[self.current_device] # 新增ping检测逻辑 ip = device["ip"] try: result = subprocess.run(['ping', '-c', '1', '-W', '1', ip], stdout=subprocess.PIPE, stderr=subprocess.PIPE) if result.returncode == 0: device["status"] = "在线" else: device["status"] = "离线" except Exception as e: print(f"Ping 检测出错: {e}") device["status"] = "离线" if self.current_page == 1: self.ip_value.config(text=device["ip"]) self.status_value.config(text=device["status"], foreground="green" if device["status"] == "在线" else "red") self.temperature_value.config(text=f"{device['temperature']:.1f}°C") self.power_value.config(text=f"{device['power']:.2f} W") self.bandwidth_value.config(text=f"{device['bandwidth']:.1f} GB/s") # self.send_count_value.config(text=device["send_count"]) self.mlu_avg_usage_value.config(text=f"{device['mlu_avg_usage']:.1f}%") self.cpu_avg_usage_value.config(text=f"{device['cpu_avg_usage']:.1f}%") self.update_page2_plots() self.update_page3_plots() self.update_page4_plots() self.frame_count += 1 def start_udp_receive(self): def read_config(): 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("Read config success.") except FileNotFoundError: print("Unable to open config file!") return None return config config = read_config() if config is None: return server_ip = config.get('SERVER_IP') server_port = int(config.get('SERVER_PORT')) client_ip = config.get('CLIENT_IP') client_port = int(config.get('CLIENT_PORT')) print("ServerIP: {}".format(server_ip)) print("ServerPort: {}".format(server_port)) print("ClientIP: {}".format(client_ip)) print("ClientPort: {}".format(client_port)) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) print("Set socket ok.") try: sock.bind((client_ip, client_port)) print("Bind success.") except OSError: print("Bind error!") return def receive_data(): print("Start receive data.") try: while True: data, addr = sock.recvfrom(4096) try: info_str = data.decode('utf-8') self.update_device_info(info_str) except UnicodeDecodeError: print("解码数据时出错,请检查数据编码。") except OSError: print("Receive data error!") except KeyboardInterrupt: print("Program interrupted by user.") finally: sock.close() receive_thread = threading.Thread(target=receive_data) receive_thread.daemon = True receive_thread.start() def initialize_plots(self): if not self.page2_plots_initialized: self.page2_plots_initialized = True if not self.page3_plots_initialized: self.page3_plots_initialized = True if not self.page4_plots_initialized: self.page4_plots_initialized = True def update_page2_plots(self): device = self.devices[self.current_device] for i in range(4): try: usage = device["mlu_core_usage"][i] if not isinstance(usage, (int, float)): usage = 1 except (IndexError, KeyError): usage = 1 # 确保只添加新的时间点 if not self.mlu_xs[i] or self.mlu_xs[i][-1] < self.frame_count: self.mlu_xs[i].append(self.frame_count) self.mlu_ys[i].append(usage) else: # 如果当前时间点已存在,更新该时间点的值 self.mlu_ys[i][-1] = usage # 保证数据列表长度不超过20 if len(self.mlu_xs[i]) > 20: self.mlu_xs[i] = self.mlu_xs[i][-20:] self.mlu_ys[i] = self.mlu_ys[i][-20:] # 调整横轴范围 start = max(self.mlu_xs[i][0], self.frame_count - 19) end = start + 19 self.mlu_axs[i].set_xlim(start, end) # 确保刻度是 5 的倍数 tick_start = (start // 5) * 5 tick_end = (end // 5) * 5 ticks = [tick for tick in range(tick_start, tick_end + 1, 5) if start <= tick <= end] self.mlu_axs[i].set_xticks(ticks) self.mlu_lines[i].set_data(self.mlu_xs[i], self.mlu_ys[i]) self.mlu_figs[i].canvas.draw() def update_page3_plots(self): device = self.devices[self.current_device] for i in range(4): try: usage = device["cpu_core_usage"][i] if not isinstance(usage, (int, float)): usage = 1 except (IndexError, KeyError): usage = 1 # 确保只添加新的时间点 if not self.cpu_xs[i] or self.cpu_xs[i][-1] < self.frame_count: self.cpu_xs[i].append(self.frame_count) self.cpu_ys[i].append(usage) else: # 如果当前时间点已存在,更新该时间点的值 self.cpu_ys[i][-1] = usage # 保证数据列表长度不超过20 if len(self.cpu_xs[i]) > 20: self.cpu_xs[i] = self.cpu_xs[i][-20:] self.cpu_ys[i] = self.cpu_ys[i][-20:] # 调整横轴范围 start = max(self.cpu_xs[i][0], self.frame_count - 19) end = start + 19 self.cpu_axs[i].set_xlim(start, end) # 确保刻度是 5 的倍数 tick_start = (start // 5) * 5 tick_end = (end // 5) * 5 ticks = [tick for tick in range(tick_start, tick_end + 1, 5) if start <= tick <= end] self.cpu_axs[i].set_xticks(ticks) self.cpu_lines[i].set_data(self.cpu_xs[i], self.cpu_ys[i]) self.cpu_figs[i].canvas.draw() def update_page4_plots(self): device = self.devices[self.current_device] memory_usage = device["memory"] # 确保只添加新的时间点 if not self.memory_xs or self.memory_xs[-1] < self.frame_count: self.memory_xs.append(self.frame_count) self.memory_ys.append(memory_usage) else: # 如果当前时间点已存在,更新该时间点的值 self.memory_ys[-1] = memory_usage # 保证数据列表长度不超过20 if len(self.memory_xs) > 20: self.memory_xs = self.memory_xs[-20:] self.memory_ys = self.memory_ys[-20:] # 调整横轴范围 start = max(self.memory_xs[0], self.frame_count - 19) end = start + 19 self.memory_ax.set_xlim(start, end) # 确保刻度是 5 的倍数 tick_start = (start // 5) * 5 tick_end = (end // 5) * 5 ticks = [tick for tick in range(tick_start, tick_end + 1, 5) if start <= tick <= end] self.memory_ax.set_xticks(ticks) self.memory_line.set_data(self.memory_xs, self.memory_ys) self.memory_fig.canvas.draw() if __name__ == "__main__": app = DeviceManager() app.mainloop() 这是一段基于Socket通讯用于接收服务端MLU220文本数据的客户端程序,用这段程序提取文本数据的方法写入到下面这段程序中以便用相同的方法提取文本数据import tkinter as tk import ttkbootstrap as tb import psutil import random import threading import time from ttkbootstrap.constants import * from PIL import Image, ImageTk, ImageDraw class EnhancedCircularProgressBar: def __init__(self, parent, size=200, thickness=20, bg_color="#1a1a1a", 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.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 self.current_value = 0 self.target_value = 0 self.animation_speed = 1.0 # 动画速度因子 # 创建画布 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.draw_background() # 绘制文本 self.text_id = self.canvas.create_text( self.center_x, self.center_y, text="0%", fill=text_color, font=("Arial", font_size, "bold") ) # 绘制标题 self.title_id = self.canvas.create_text( self.center_x, self.center_y + 40, text=title, fill=text_color, font=("Arial", int(font_size*0.8)) ) # 初始绘制 self.set_value(0) def draw_background(self): """绘制背景圆环""" # 计算圆环的外接矩形坐标 x0 = self.center_x - self.radius y0 = self.center_y - self.radius x1 = self.center_x + self.radius y1 = self.center_y + self.radius # 绘制背景圆环 self.bg_arc = self.canvas.create_arc( x0, y0, x1, y1, start=0, # 起始角度 extent=360, # 360度完整圆环 width=self.thickness, outline=self.bg_color, style=tk.ARC ) def interpolate_color(self, progress): """根据进度值插值计算颜色(绿---红过渡)""" # 定义颜色过渡点 color_points = [ (0.00, (0, 255, 0)), # 绿色 (0.25, (170, 255, 0)), # 黄绿色 (0.50, (255, 255, 0)), # 黄色 (0.75, (255, 170, 0)), # 橙色 (1.00, (255, 0, 0)) # 红色 ] # 找到当前进度所在的区间 for i in range(1, len(color_points)): if progress <= color_points[i][0]: # 计算区间内的比例 t = (progress - color_points[i-1][0]) / (color_points[i][0] - color_points[i-1][0]) # 线性插值计算RGB值(不使用numpy) r1, g1, b1 = color_points[i-1][1] r2, g2, b2 = color_points[i][1] r = int(r1 + t * (r2 - r1)) g = int(g1 + t * (g2 - g1)) b = int(b1 + t * (b2 - b1)) return f"#{r:02x}{g:02x}{b:02x}" # 默认返回红色 return "#ff0000" def set_value(self, value, animate=True): """设置当前值并更新进度条""" # 确保值在合理范围内 value = max(0, min(value, self.max_value)) if animate: self.target_value = value # 启动动画(如果尚未运行) if abs(self.current_value - self.target_value) > 0.1: self.animate_step() else: self.target_value = value self.current_value = value self.update_display() def update_display(self): """更新进度条显示""" # 计算进度比例 progress = self.current_value / self.max_value # 计算角度(从-90度开始,即12点钟方向) angle = progress * 360 # 清除旧的前景圆环 if hasattr(self, 'fg_arc'): self.canvas.delete(self.fg_arc) # 计算圆环的外接矩形坐标 x0 = self.center_x - self.radius y0 = self.center_y - self.radius x1 = self.center_x + self.radius y1 = self.center_y + self.radius # 获取插值颜色 color = self.interpolate_color(progress) # 绘制前景圆环(进度指示) self.fg_arc = self.canvas.create_arc( x0, y0, x1, y1, start=90, # 从12点钟方向开始 extent=angle, # 根据值计算角度 width=self.thickness, outline=color, style=tk.ARC ) # 提升前景圆环的显示层级 self.canvas.tag_raise(self.fg_arc) # 更新文本显示 display_text = f"{self.current_value:.1f}" if self.unit == "%": display_text = f"{progress*100:.1f}%" self.canvas.itemconfig(self.text_id, text=display_text) def animate_step(self): """执行一步动画(不使用numpy)""" if abs(self.current_value - self.target_value) < 0.1: self.current_value = self.target_value else: # 使用缓动函数实现平滑动画 diff = self.target_value - self.current_value self.current_value += diff * 0.2 * self.animation_speed self.update_display() # 如果未达到目标值,继续动画 if abs(self.current_value - self.target_value) > 0.1: self.parent.after(16, self.animate_step) # 约60fps class SystemMonitorApp: def __init__(self): # 创建主窗口 self.root = tb.Window(themename="darkly", title="系统资源监控", size=(1300, 800)) 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")) style.configure("Section.TLabelframe", font=("Arial", 10, "bold")) # 创建主框架 - 使用网格布局 main_frame = tb.Frame(self.root, padding=10) main_frame.pack(fill=tk.BOTH, expand=True) # ========== 顶部控制栏 ========== control_bar = tb.Frame(main_frame, padding=(10, 5)) control_bar.grid(row=0, column=0, columnspan=3, sticky="ew", pady=(0, 10)) # 设备选择下拉框 tb.Label(control_bar, text="监控设备:", bootstyle=PRIMARY).pack(side=tk.LEFT, padx=(0, 5)) self.device_var = tk.StringVar() device_options = ["设备A", "设备B", "设备C", "设备D", "设备E"] device_combo = tb.Combobox( control_bar, textvariable=self.device_var, values=device_options, width=15, state="readonly", bootstyle=PRIMARY ) device_combo.pack(side=tk.LEFT, padx=5) device_combo.current(0) # 设置默认选项 # 采样频率滑块 tb.Label(control_bar, text="采样频率:", bootstyle=PRIMARY).pack(side=tk.LEFT, padx=(20, 5)) self.sampling_rate = tk.IntVar(value=1) tb.Scale( control_bar, from_=0.5, to=5, length=120, orient=tk.HORIZONTAL, variable=self.sampling_rate, bootstyle=PRIMARY ).pack(side=tk.LEFT, padx=5) # 动画速度滑块 (修复resolution问题) tb.Label(control_bar, text="动画速度:", bootstyle=PRIMARY).pack(side=tk.LEFT, padx=(20, 5)) self.animation_speed = tk.DoubleVar(value=1.0) tb.Scale( control_bar, from_=0.5, to=3.0, length=120, orient=tk.HORIZONTAL, variable=self.animation_speed, bootstyle=PRIMARY ).pack(side=tk.LEFT, padx=5) # 控制按钮 tb.Button( control_bar, text="启动", bootstyle=SUCCESS, width=8, command=self.start_monitoring ).pack(side=tk.LEFT, padx=5) tb.Button( control_bar, text="暂停", bootstyle=DANGER, width=8, command=self.stop_monitoring ).pack(side=tk.LEFT, padx=5) tb.Button( control_bar, text="重置", bootstyle=WARNING, width=8, command=self.reset_all ).pack(side=tk.LEFT, padx=5) # 状态指示器 self.status_indicator = tb.Label( control_bar, text="● 已连接", bootstyle=(SUCCESS, INVERSE), font=("Arial", 10), padding=(10, 0) ) self.status_indicator.pack(side=tk.RIGHT, padx=(10, 0)) # ========== 左侧设置面板 ========== settings_frame = tb.Labelframe( main_frame, text="监控设置", bootstyle="info", padding=10, style="Section.TLabelframe" ) settings_frame.grid(row=1, column=0, sticky="nsew", padx=(0, 10), pady=(0, 10)) # 温度报警设置 temp_frame = tb.Frame(settings_frame) temp_frame.pack(fill=tk.X, pady=5) tb.Label(temp_frame, text="温度报警阈值(°C):").pack(side=tk.LEFT) self.temp_threshold = tk.IntVar(value=80) tb.Entry( temp_frame, textvariable=self.temp_threshold, width=8, bootstyle=PRIMARY ).pack(side=tk.RIGHT, padx=(5, 0)) # 内存报警设置 mem_frame = tb.Frame(settings_frame) mem_frame.pack(fill=tk.X, pady=5) tb.Label(mem_frame, text="内存报警阈值(%):").pack(side=tk.LEFT) self.mem_threshold = tk.IntVar(value=90) tb.Entry( mem_frame, textvariable=self.mem_threshold, width=8, bootstyle=PRIMARY ).pack(side=tk.RIGHT, padx=(5, 0)) # 网络报警设置 net_frame = tb.Frame(settings_frame) net_frame.pack(fill=tk.X, pady=5) tb.Label(net_frame, text="网络报警阈值(Mbps):").pack(side=tk.LEFT) self.net_threshold = tk.IntVar(value=800) tb.Entry( net_frame, textvariable=self.net_threshold, width=8, bootstyle=PRIMARY ).pack(side=tk.RIGHT, padx=(5, 0)) # 分隔线 tb.Separator(settings_frame, bootstyle=SECONDARY).pack(fill=tk.X, pady=10) # 主题选择 tb.Label(settings_frame, text="界面主题:", bootstyle=PRIMARY).pack(anchor=tk.W, pady=(0, 5)) self.theme_var = tk.StringVar(value="darkly") themes = ["darkly", "solar", "superhero", "cyborg", "vapor"] tb.Combobox( settings_frame, textvariable=self.theme_var, values=themes, state="readonly", bootstyle=PRIMARY ).pack(fill=tk.X, pady=(0, 10)) # 历史数据按钮 tb.Button( settings_frame, text="查看历史数据", bootstyle=(OUTLINE, INFO), command=self.show_history ).pack(fill=tk.X, pady=5) # ========== 中间监控面板 ========== monitor_frame = tb.Frame(main_frame) monitor_frame.grid(row=1, column=1, sticky="nsew", pady=(0, 10)) # 标题 tb.Label( monitor_frame, text="系统资源实时监控", style="Title.TLabel" ).pack(pady=(0, 15)) # 创建进度条容器框架 progress_container = tb.Frame(monitor_frame) progress_container.pack(fill=tk.BOTH, expand=True, pady=5) # 创建监控指标配置 monitor_config = [ {"title": "CPU温度", "unit": "°C", "max_value": 100, "thickness": 18}, {"title": "功耗", "unit": "W", "max_value": 200, "thickness": 18}, {"title": "内存使用", "unit": "%", "max_value": 100, "thickness": 18}, {"title": "网络带宽", "unit": "Mbps", "max_value": 1000, "thickness": 18}, {"title": "MLU利用率", "unit": "%", "max_value": 100, "thickness": 18}, {"title": "CPU利用率", "unit": "%", "max_value": 100, "thickness": 18} ] # 使用网格布局排列进度条 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"], 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) # ========== 右侧信息面板 ========== info_frame = tb.Labelframe( main_frame, text="系统信息", bootstyle="info", padding=10, style="Section.TLabelframe" ) info_frame.grid(row=1, column=2, sticky="nsew", padx=(10, 0), pady=(0, 10)) # 系统信息标签 info_labels = [ ("设备型号:", "MLU"), ("操作系统:", "Ubuntu 20.04 LTS"), ("处理器:", "16ARMv8"), ("内存总量:", "32 GB"), ("MLU数量:", "4"), ("网络接口:", "eth0 (10Gbps)") ] for label, value in info_labels: frame = tb.Frame(info_frame) frame.pack(fill=tk.X, pady=3) tb.Label(frame, text=label, width=10, anchor=tk.W).pack(side=tk.LEFT) tb.Label(frame, text=value, bootstyle=INFO).pack(side=tk.LEFT) # 分隔线 tb.Separator(info_frame, bootstyle=SECONDARY).pack(fill=tk.X, pady=10) # 实时状态 tb.Label(info_frame, text="实时状态", bootstyle=PRIMARY).pack(anchor=tk.W, pady=(0, 5)) self.realtime_labels = {} status_items = [ ("CPU温度", "cpu_temp", "°C"), ("功耗", "power", "W"), ("内存使用", "memory", "%"), ("网络带宽", "bandwidth", "Mbps"), ("MLU利用率", "mlu_usage", "%"), ("CPU利用率", "cpu_usage", "%") ] for name, key, unit in status_items: frame = tb.Frame(info_frame) frame.pack(fill=tk.X, pady=2) tb.Label(frame, text=name, width=12, anchor=tk.W).pack(side=tk.LEFT) value_label = tb.Label(frame, text="0.0", width=8, anchor=tk.W) value_label.pack(side=tk.LEFT) tb.Label(frame, text=unit).pack(side=tk.LEFT) self.realtime_labels[key] = value_label # ========== 状态栏 ========== self.status = tb.Label( self.root, text="系统准备就绪 | 当前设备: 设备A", bootstyle=(SECONDARY, INVERSE), anchor=tk.CENTER ) self.status.pack(side=tk.BOTTOM, fill=tk.X) # 配置网格权重 main_frame.columnconfigure(0, weight=1) # 左侧设置面板 main_frame.columnconfigure(1, weight=3) # 中间监控面板主要区域 main_frame.columnconfigure(2, weight=1) # 右侧信息面板 main_frame.rowconfigure(1, weight=1) # 监控控制变量 self.monitoring_active = False self.monitoring_thread = None # 启动初始监控 self.start_monitoring() # 绑定主题切换事件 self.theme_var.trace_add("write", lambda *args: self.change_theme()) 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.set_value(0) self.status.config(text="所有监控指标已重置") def change_theme(self): """更改应用主题""" theme = self.theme_var.get() # 正确切换主题方法 self.root.style.theme_use(theme) self.status.config(text=f"主题已切换为: {theme.capitalize()}") def show_history(self): """显示历史数据""" self.status.config(text="历史数据查看功能开发中...") def monitor_resources(self): """监控系统资源(线程安全实现)""" while self.monitoring_active: # 获取系统资源数据 data = { 'cpu_temp': self.get_cpu_temperature(), 'power': self.get_power_usage(), 'mem_usage': self.get_memory_usage(), 'network': self.get_network_usage(), 'mlu_usage': self.get_mlu_usage(), 'cpu_usage': psutil.cpu_percent() } # 使用after安全更新UI self.root.after(0, self.update_ui, data) time.sleep(max(0.5, self.sampling_rate.get())) def update_ui(self, data): """安全更新UI组件(在主线程执行)""" # 更新进度条的动画速度 speed = self.animation_speed.get() for bar in self.progress_bars: bar.animation_speed = speed # 更新进度条 self.progress_bars[0].set_value(data['cpu_temp']) self.progress_bars[1].set_value(data['power']) self.progress_bars[2].set_value(data['mem_usage']) self.progress_bars[3].set_value(data['network']) self.progress_bars[4].set_value(data['mlu_usage']) self.progress_bars[5].set_value(data['cpu_usage']) # 更新实时状态标签 self.realtime_labels["cpu_temp"].config(text=f"{data['cpu_temp']:.1f}") self.realtime_labels["power"].config(text=f"{data['power']:.1f}") self.realtime_labels["memory"].config(text=f"{data['mem_usage']:.1f}") self.realtime_labels["bandwidth"].config(text=f"{data['network']:.1f}") self.realtime_labels["mlu_usage"].config(text=f"{data['mlu_usage']:.1f}") self.realtime_labels["cpu_usage"].config(text=f"{data['cpu_usage']:.1f}") # 更新状态栏 status_text = ( f"当前设备: {self.device_var.get()} | " f"CPU: {data['cpu_usage']:.1f}% | " f"温度: {data['cpu_temp']:.1f}°C | " f"内存: {data['mem_usage']:.1f}% | " f"MLU: {data['mlu_usage']:.1f}%" ) self.status.config(text=status_text) # 资源获取方法 def get_cpu_temperature(self): """获取CPU温度(模拟数据)""" return random.uniform(40, 90) def get_power_usage(self): """获取功耗(模拟数据)""" return random.uniform(50, 180) def get_memory_usage(self): """获取内存使用率""" return psutil.virtual_memory().percent def get_network_usage(self): """获取网络带宽(模拟数据)""" return random.uniform(100, 900) def get_mlu_usage(self): """获取MLU利用率(模拟数据)""" return random.uniform(10, 95) if __name__ == "__main__": SystemMonitorApp()
06-22
<think>我们正在处理一个C# WinForms应用程序中使用ScottPlot库的问题。用户试图计算图表X轴和Y轴的范围(最大值减最小值),但遇到了错误:"运算符无法用于方法组和方法组的运算"。 分析错误原因: 在C#中,当试图对方法(而不是属性或字段)使用运算符时会出现"方法组"错误。用户代码中`formsPlot1.Plot.XAxis.Max`和`formsPlot1.Plot.XAxis.Min`可能实际上是方法而不是属性。 查阅ScottPlot文档(特别是WinForms的ScottPlot.WinForms版本): - 在ScottPlot中,轴的范围可以通过`GetAxisLimits`方法获取,或者直接通过轴的`Min`和`Max`属性。但是需要注意的是,在ScottPlot.WinForms中,`Plot`对象有一个`GetAxisLimits`方法,该方法返回一个`AxisLimits`结构,包含X轴和Y轴的最小值和最大值。 然而,根据用户代码,他使用的是`formsPlot1.Plot.XAxis.Max`和`formsPlot1.Plot.XAxis.Min`。在ScottPlot中,`XAxis`和`YAxis`是数组(因为可以有多个轴),但默认情况下,主要轴是索引0。 在ScottPlot 4.x版本中,获取轴范围的标准做法是: 1. 使用主X轴和Y轴(索引0)的`Min`和`Max`属性。但是注意,这些属性是double类型,应该是可访问的。 但是,错误提示“方法组”意味着`Max`和`Min`被编译器解释为方法而不是属性。这通常是因为在类中定义了名为`Max`或`Min`的方法,而没有同名的属性。或者,可能是用户错误地使用了括号(例如,`Max()`)而没有参数,导致编译器将其解释为方法。 在ScottPlot.WinForms中,轴对象(Axis)的`Min`和`Max`是属性(property)而不是方法(method)。因此,直接访问应该没有问题。 但是,用户代码中`formsPlot1.Plot.XAxis`可能返回的是一个轴数组?在ScottPlot中,`Plot`的`XAxis`属性是一个列表(`List<Axis>`),因此我们需要通过索引来访问特定的轴。通常,主X轴是索引0。 因此,正确的访问方式应该是: ```csharp double xMin = formsPlot1.Plot.XAxis[0].Min; double xMax = formsPlot1.Plot.XAxis[0].Max; double xRange = xMax - xMin; double yMin = formsPlot1.Plot.YAxis[0].Min; double yMax = formsPlot1.Plot.YAxis[0].Max; double yRange = yMax - yMin; ``` 或者,更简单的方法是使用`Plot`对象的`GetAxisLimits`方法: ```csharp var limits = formsPlot1.Plot.GetAxisLimits(); double xRange = limits.XMax - limits.XMin; double yRange = limits.YMax - limits.YMin; ``` 第二种方法更简洁,并且不容易出错,因为它直接返回了当前视图的坐标轴范围(包括主X轴和Y轴)。 因此,我建议用户使用`GetAxisLimits`方法。 但是,如果用户坚持使用第一种方式,那么必须确保通过索引访问轴。 现在,用户遇到的错误“运算符无法用于方法组和方法组的运算”很可能是因为他没有使用索引器(即`XAxis`是一个方法?)。但实际上,在ScottPlot.WinForms中,`Plot.XAxis`是一个属性,返回`List<Axis>`。所以,如果直接写`formsPlot1.Plot.XAxis.Min`,那么`XAxis`是列表,而列表没有`Min`属性,所以编译器会去找名为`Min`的方法(例如`List.Min()`,但那是LINQ的方法,需要参数),因此会报告“方法组”。 所以,根本原因是用户没有通过索引访问轴。 解决方案: 1. 修改为通过索引访问轴(如`XAxis[0].Min`)。 2. 使用`GetAxisLimits`方法。 由于`GetAxisLimits`方法更简单,且是推荐做法,所以我将推荐这种方法。 步骤: - 调用`formsPlot1.Plot.GetAxisLimits()`,它返回一个`AxisLimits`对象。 - `AxisLimits`对象有`XMin`, `XMax`, `YMin`, `YMax`属性。 代码示例: ```csharp // 获取坐标轴范围 var axisLimits = formsPlot1.Plot.GetAxisLimits(); double xRange = axisLimits.XMax - axisLimits.XMin; double yRange = axisLimits.YMax - axisLimits.YMin; ``` 这样写既简洁又避免了错误。 注意:在使用前确保`formsPlot1.Plot`不为空,并且已经绘制了图形(即轴的范围已经设置)。 因此,我将向用户推荐这种方法。 </think>### 错误分析与解决方案 #### 错误原因分析 在 C# 中,错误 "运算符无法用于方法组和方法组的运算" 通常是由于尝试对**方法而非属性**进行数学运算导致的。在您的代码中: ```csharp double xRange = formsPlot1.Plot.XAxis.Max - formsPlot1.Plot.XAxis.Min; ``` `Max` 和 `Min` 被编译器识别为**方法(method)** 而非**属性(property)**,因此无法直接用于数学运算。 #### 解决方案(两种方式) ##### 方案 1:调用方法获取值(推荐) 使用括号 `()` 显式调用方法: ```csharp double xRange = formsPlot1.Plot.XAxis.Max() - formsPlot1.Plot.XAxis.Min(); double yRange = formsPlot1.Plot.YAxis.Max() - formsPlot1.Plot.YAxis.Min(); ``` ##### 方案 2:使用内置范围属性(更简洁) ScottPlot 提供直接获取范围的属性: ```csharp var xLim = formsPlot1.Plot.GetAxisLimits().XAxis; double xRange = xLim.Max - xLim.Min; var yLim = formsPlot1.Plot.GetAxisLimits().YAxis; double yRange = yLim.Max - yLim.Min; ``` #### 关键区别说明 | 类型 | 语法 | 是否可运算 | |-----------|----------------|------------| | 方法 | `.Max()` | ✅ 需调用 | | 属性 | `.Max` | ✅ 直接使用 | | 未调用方法| `.Max` (无括号)| ❌ 报错 | ### 根本原因解析 1. **ScottPlot 的 API 设计** 在 ScottPlot 中,`XAxis.Max/Min` 是**方法**而非属性(类似 Matplotlib 的 `get_xlim()`[^2]),必须通过调用获取值。 2. **C# 编译器行为** 编译器将未加括号的 `.Max/.Min` 识别为**方法组(method group)**,而方法不能直接参与数学运算[^3]。 3. **可视化库通用模式** 许多图表库(如 Matplotlib、Plotly)都采用方法获取坐标范围,这是行业通用设计模式[^2][^3]。 ### 相关问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值