UI

上图 V1



上图 V2





 

V3




Code

import tkinter as tk
from tkinter import messagebox, scrolledtext
import socket
import threading
from datetime import datetime
import os
import logging
from PIL import Image, ImageTk
import subprocess# 定义文件夹路径
folder_path = r'c:\Log123'# 创建日志文件夹
if not os.path.exists(folder_path):os.makedirs(folder_path)# 设置日志记录
logging.basicConfig(filename=os.path.join(folder_path, 'log.log'), level=logging.INFO,format='%(asctime)s:%(levelname)s:%(message)s')class IndustrialApp:def __init__(self, root):self.root = rootself.root.title("Design_By_Tim")self.root.geometry("1200x700")self.root.configure(bg="#333333")# 图像加载相关变量self.img_index = 0self.current_img = None# 创建三列布局self.create_image_column()   # 左侧图像列self.create_control_column()  # 中间控制列self.create_status_column()   # 右侧状态列# 初始化网络连接self.client_socket = None self.standard_dimensions = {}self.standard_tolerances = {}self.update_standard_rectangle()  # 从输入框初始化标准数据# 启动图像更新self.img_update()def create_image_column(self):"""创建左侧图像列"""image_frame = tk.Frame(self.root, bg="#222222", width=400)image_frame.pack(side=tk.LEFT, fill=tk.BOTH, padx=(10,5), pady=10)image_frame.pack_propagate(False)  # 固定宽度# 图像显示标签self.img_label = tk.Label(image_frame, bg="#222222")self.img_label.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)# 视觉打开按钮vision_button = tk.Button(image_frame, text="打开视觉系统", command=self.open_vision_system,font=("黑体", 18, "bold"), fg="#FFFFFF", bg="#006699",relief=tk.RAISED, borderwidth=3)vision_button.pack(side=tk.TOP, fill=tk.X, padx=5, pady=5)def create_control_column(self):"""创建中间控制列"""control_frame = tk.Frame(self.root, bg="#333333")control_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5, pady=10)# 工业风启动按钮self.start_button = tk.Button(control_frame, text="开始测量", command=self.send_command,font=("黑体", 16, "bold"), fg="#FFFFFF", bg="#006699",relief=tk.RAISED, borderwidth=3, width=8)self.start_button.pack(side=tk.TOP, fill=tk.X, anchor=tk.NW, padx=10, pady=10)# 绘图画布self.canvas = tk.Canvas(control_frame, bg="#444444", highlightthickness=0)self.canvas.pack(fill=tk.BOTH, expand=True)# 新增: 醒目的判断结果展示区域self.result_frame = tk.Frame(control_frame, bg="#333333", height=80)self.result_frame.pack(fill=tk.X, pady=(10, 0))# 初始状态为"等待测量"self.result_label = tk.Label(self.result_frame, text="等待测量...", font=("黑体", 24, "bold"), bg="#333333", fg="#FFFFFF")self.result_label.pack(expand=True, fill=tk.BOTH)# 详细结果标签self.detail_result_label = tk.Label(self.result_frame, text="", font=("黑体", 12), bg="#333333", fg="#FFFFFF")self.detail_result_label.pack(fill=tk.X, pady=(0, 5))def create_status_column(self):"""创建右侧状态列"""right_frame = tk.Frame(self.root, bg="#333333", width=300)right_frame.pack(side=tk.RIGHT, fill=tk.Y, padx=(5,10), pady=10)right_frame.pack_propagate(False)  # 固定宽度# 标准矩形设置区settings_frame = tk.LabelFrame(right_frame, text="标准设置", font=("黑体", 12),bg="#333333", fg="#FFFFFF")settings_frame.pack(pady=10, fill=tk.X)# 尺寸输入框   315.021,131.784,315.085,132.322dimensions = [("上边 (mm):", "top", 315.021), ("右边 (mm):", "right", 131.784),("下边 (mm):", "bottom", 315.085), ("左边 (mm):", "left", 132.322)]self.entries = {}for i, (label, name, default_value) in enumerate(dimensions):tk.Label(settings_frame, text=label, bg="#333333", fg="#FFFFFF").grid(row=i, column=0, padx=5, pady=5)entry = tk.Entry(settings_frame, width=10)entry.grid(row=i, column=1, padx=5, pady=5)entry.insert(0, str(default_value))self.entries[name] = entry# 公差输入框tolerances = [("上边公差 (mm):", "top_tol", 0.1), ("右边公差 (mm):", "right_tol", 0.1),("下边公差 (mm):", "bottom_tol", 0.1), ("左边公差 (mm):", "left_tol", 0.1)]self.tolerance_entries = {}for i, (label, name, default_value) in enumerate(tolerances):tk.Label(settings_frame, text=label, bg="#333333", fg="#FFFFFF").grid(row=i, column=2, padx=5, pady=5)entry = tk.Entry(settings_frame, width=10)entry.grid(row=i, column=3, padx=5, pady=5)entry.insert(0, str(default_value))self.tolerance_entries[name] = entry# 更新按钮update_button = tk.Button(settings_frame, text="更新标准数据", command=self.update_standard_rectangle,font=("黑体", 12), fg="#FFFFFF", bg="#555555")update_button.grid(row=len(dimensions), column=0, columnspan=4, pady=10)# 日志区域log_frame = tk.LabelFrame(right_frame, text="操作日志", font=("黑体", 12), bg="#333333", fg="#FFFFFF")log_frame.pack(fill=tk.X, pady=(10, 5))self.log_text = scrolledtext.ScrolledText(log_frame, width=55, height=12,bg="#444444", fg="#FFFFFF", font=("Consolas", 10))self.log_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)self.log_text.insert(tk.END, "操作日志:\n")# 实时状态区域(分为两行,每行显示两组)status_frame = tk.LabelFrame(right_frame, text="实时状态", font=("黑体", 10), bg="#333333", fg="#FFFFFF")status_frame.pack(fill=tk.X, pady=(5, 10))self.status_labels = {"top": {"name": tk.Label(status_frame, text="上边:", bg="#333333", fg="#FFFFFF"),"status": tk.Label(status_frame, text="OK", bg="#333333", fg="#00FF00")},"right": {"name": tk.Label(status_frame, text="右边:", bg="#333333", fg="#FFFFFF"),"status": tk.Label(status_frame, text="OK", bg="#333333", fg="#00FF00")},"bottom": {"name": tk.Label(status_frame, text="下边:", bg="#333333", fg="#FFFFFF"),"status": tk.Label(status_frame, text="OK", bg="#333333", fg="#00FF00")},"left": {"name": tk.Label(status_frame, text="左边:", bg="#333333", fg="#FFFFFF"),"status": tk.Label(status_frame, text="OK", bg="#333333", fg="#00FF00")},}# 实时状态布局:两行,每行显示两组row1_keys = ["top"]row2_keys = ["right"]row3_keys = ["bottom"]row4_keys = ["left"]for i, key in enumerate(row1_keys):self.status_labels[key]["name"].grid(row=0, column=i*2, sticky="w", padx=(10,5), pady=2)self.status_labels[key]["status"].grid(row=0, column=i*2+1, sticky="w", padx=(5,10), pady=2)for i, key in enumerate(row2_keys):self.status_labels[key]["name"].grid(row=1, column=i*2, sticky="w", padx=(10,5), pady=2)self.status_labels[key]["status"].grid(row=1, column=i*2+1, sticky="w", padx=(5,10), pady=2)for i, key in enumerate(row3_keys):self.status_labels[key]["name"].grid(row=2, column=i*2, sticky="w", padx=(10,5), pady=2)self.status_labels[key]["status"].grid(row=2, column=i*2+1, sticky="w", padx=(5,10), pady=2)for i, key in enumerate(row4_keys):self.status_labels[key]["name"].grid(row=3, column=i*2, sticky="w", padx=(10,5), pady=2)self.status_labels[key]["status"].grid(row=3, column=i*2+1, sticky="w", padx=(5,10), pady=2)def img_update(self):"""实时图像更新逻辑"""img_dir = r"C:\Log\Picture\POL"try:if os.path.exists(img_dir):files = sorted([f for f in os.listdir(img_dir) if f.lower().endswith(('.png','.jpg','.bmp'))])if files:# 带缓存的图像加载path = os.path.join(img_dir, files[self.img_index % len(files)])with Image.open(path) as img:img = img.resize((280, 420), Image.Resampling.LANCZOS)  # 调整图像大小以适应列宽self.current_img = ImageTk.PhotoImage(img)self.img_label.config(image=self.current_img)self.img_index += 1except Exception as e:logging.error(f"图像加载异常: {str(e)}")finally:self.root.after(1000, self.img_update)  # 定时刷新def open_vision_system(self):"""打开视觉系统""" try:#vision_path = r"E:\Tim_Study\POL_Case\POLV1\Public_Release\POLV1.exe"vision_path = r"E:\Tim_Study\POL_Case\Vision\Public_Release\Vision.exe"if os.path.exists(vision_path):subprocess.Popen(vision_path)self.log_message("视觉系统已启动")else:messagebox.showerror("错误", f"未找到视觉系统程序: {vision_path}")self.log_message(f"视觉系统程序未找到: {vision_path}")except Exception as e:logging.error(f"启动视觉系统错误: {str(e)}")messagebox.showerror("错误", f"启动视觉系统失败: {e}")self.log_message(f"启动视觉系统错误: {e}")def log_message(self, message):timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")log_entry = f"{timestamp} - {message}\n"self.log_text.insert(tk.END, log_entry)self.log_text.see(tk.END)logging.info(message)def send_command(self):server_ip = "127.0.0.1"port = 7930try:self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)self.client_socket.connect((server_ip, port))self.client_socket.sendall(b"V1_Point_Draw")threading.Thread(target=self.receive_data).start()self.log_message("命令发送成功: V1_Point_Draw")# 更新结果展示区域状态self.result_label.config(text="测量中...", fg="#FFFF00")  # 黄色表示测量中self.detail_result_label.config(text="")except Exception as e:logging.error(f"连接错误 {e}")messagebox.showerror("错误", f"连接失败: {e}\n\n\n请先确认视觉系统")self.log_message(f"连接错误: {e}")# 更新结果展示区域状态self.result_label.config(text="连接失败", fg="#FF0000")  # 红色表示错误self.detail_result_label.config(text=str(e))def receive_data(self):try:while True:data = self.client_socket.recv(1024).decode('utf-8')if not data:breakself.update_ui(data)except Exception as e:logging.error(f"数据接收错误 {e}")messagebox.showerror("错误", f"数据接收失败: {e}")self.log_message(f"数据接收错误: {e}")# 更新结果展示区域状态self.result_label.config(text="接收错误", fg="#FF0000")self.detail_result_label.config(text=str(e))finally:self.client_socket.close()self.log_message("连接已关闭")def update_ui(self, data):self.draw_rectangle_with_dimensions(data)self.log_message(f"接收数据: {data}")# 更新结果展示区域self.update_result_display(data)def draw_rectangle_with_dimensions(self, data):try:self.canvas.delete("all")points = list(map(float, data.split(',')))if len(points) != 4:raise ValueError("数据格式错误,需要4个参数")# 绘制标准矩形self.draw_standard_rectangle()# 绘制实时矩形x1, y1 = 80, 100scale = min(1000 / max(points), 1)  # 自动缩放比例x2 = x1 + points[0] * scaley2 = y1 + points[1] * scaleself.canvas.create_rectangle(x1, y1, x2, y2, outline="#FF0000", width=2)# 实时矩形尺寸标注self.create_dimension_text((x1 + x2)/2, y1-30, f"{points[0]:.3f} mm", "#FF0000")self.create_dimension_text((x1 + x2)/2, y2+30, f"{points[2]:.3f} mm", "#FF0000")self.create_dimension_text(x1-30, (y1 + y2)/2, f"{points[3]:.3f} mm", "#FF0000", 90)self.create_dimension_text(x2+30, (y1 + y2)/2, f"{points[1]:.3f} mm", "#FF0000", 90)# 实时矩形中心显示"当前测量数据"self.canvas.create_text((x1 + x2)/2, (y1 + y2)/2, text="  ",fill="#FFFFFF", font=("Arial", 12), angle=90)# 更新实时状态self.update_status(points)except Exception as e:logging.error(f"绘图错误 {e}")messagebox.showerror("错误", f"绘图失败: {e}")self.log_message(f"绘图错误: {e}")# 更新结果展示区域状态self.result_label.config(text="绘图错误", fg="#FF0000")self.detail_result_label.config(text=str(e))def update_result_display(self, data):"""优化后的结果判断逻辑"""try:points = list(map(float, data.split(',')))if len(points) != 4:raise ValueError("需要4个测量参数")all_ok = Truedetails = []status_colors = {}for key, value in zip(["top", "right", "bottom", "left"], points):std = self.standard_dimensions[key]tol = self.standard_tolerances[f"{key}_tol"]diff = abs(value - std)if diff > tol:all_ok = Falsedetails.append(f"{key} 超差 {diff:.3f}mm")status_colors[key] = "#FF0000"else:details.append(f"{key} 合格 ±{diff:.3f}mm")status_colors[key] = "#00FF00"# 更新实时状态显示self.status_labels[key]["status"].config(text=f"{value:.3f}mm (标准{std:.3f}±{tol:.3f})",fg=status_colors[key])# 更新总体结果显示if all_ok:self.result_label.config(text="测量合格", fg="#00FF00")self.detail_result_label.config(text="所有尺寸均在公差范围内")else:self.result_label.config(text="测量不合格", fg="#FF0000")self.detail_result_label.config(text=" | ".join(details))except Exception as e:self.result_label.config(text="数据解析错误", fg="#FF0000")self.detail_result_label.config(text=str(e))logging.error(f"结果判断错误: {str(e)}")def draw_standard_rectangle(self):try:# 获取标准尺寸dimensions = {k: float(v.get()) for k, v in self.entries.items() if v.get()}if len(dimensions) != 4:return# 更新标准尺寸self.standard_dimensions = dimensions# 标准矩形参数std_x1, std_y1 = 80, 100scale = min(1000 / max(dimensions.values()), 1)  # 自动缩放比例std_x2 = std_x1 + dimensions['top'] * scalestd_y2 = std_y1 + dimensions['right'] * scale# 绘制标准矩形self.canvas.create_rectangle(std_x1, std_y1, std_x2, std_y2, outline="#00FF00", width=2)self.canvas.create_text((std_x1 + std_x2)/2, (std_y1 + std_y2)/2,text="白色标准值\n\n红色测量值", fill="#FFFFFF", font=("黑体", 14, "bold"))# 标准尺寸标注self.create_dimension_text((std_x1 + std_x2)/2, std_y1-10, f"{dimensions['top']:.3f} mm", "#FFFFFF")self.create_dimension_text((std_x1 + std_x2)/2, std_y2+10, f"{dimensions['bottom']:.3f} mm", "#FFFFFF")self.create_dimension_text(std_x1-10, (std_y1 + std_y2)/2, f"{dimensions['left']:.3f} mm", "#FFFFFF", 90)self.create_dimension_text(std_x2+10, (std_y1 + std_y2)/2, f"{dimensions['right']:.3f} mm", "#FFFFFF", 90)except ValueError:passdef create_dimension_text(self, x, y, text, color, angle=0):return self.canvas.create_text(x, y, text=text, fill=color,font=("Arial", 10), angle=angle, anchor=tk.CENTER)def update_status(self, real_time_data):# 获取公差值try:tolerances = {k: float(v.get()) for k, v in self.tolerance_entries.items() if v.get()}except ValueError:messagebox.showerror("错误", "请输入有效的公差值!")returnfor key, value in zip(["top", "right", "bottom", "left"], real_time_data):standard_value = self.standard_dimensions[key]tolerance = tolerances[f"{key}_tol"]  # 动态获取对应边的公差diff = abs(value - standard_value)if diff <= tolerance:status = "OK"color = "#00FF00"else:status = f"NG ({diff - tolerance:.3f} mm)"color = "#FF0000"# 更新状态标签self.status_labels[key]["status"].config(text=status, fg=color)def update_standard_rectangle(self):"""更新标准矩形尺寸和公差"""try:# 验证并获取标准尺寸standard_dimensions = {}required_keys = ["top", "right", "bottom", "left"]for key in required_keys:value = self.entries[key].get()if not value:raise ValueError(f"请填写{key}尺寸")standard_dimensions[key] = float(value)# 验证并获取公差值standard_tolerances = {}required_tols = ["top_tol", "right_tol", "bottom_tol", "left_tol"]for key in required_tols:value = self.tolerance_entries[key].get()if not value:raise ValueError(f"请填写{key}公差")standard_tolerances[key] = float(value)# 更新标准数据self.standard_dimensions = standard_dimensionsself.standard_tolerances = standard_tolerancesself.draw_standard_rectangle()self.log_message("标准数据更新成功")except ValueError as e:messagebox.showerror("输入错误", str(e))logging.error(f"标准数据更新失败: {str(e)}")if __name__ == "__main__":root = tk.Tk()app = IndustrialApp(root)root.mainloop()
import tkinter as tk
from tkinter import messagebox, scrolledtext
import socket
import threading
from datetime import datetime
import os
import logging
from PIL import Image, ImageTk
import subprocess# 定义文件夹路径
folder_path = r'c:\Log123'# 创建日志文件夹
if not os.path.exists(folder_path):os.makedirs(folder_path)# 设置日志记录
logging.basicConfig(filename=os.path.join(folder_path, 'log.log'), level=logging.INFO,format='%(asctime)s:%(levelname)s:%(message)s')class IndustrialApp:def __init__(self, root):self.root = rootself.root.title("Design_By_Tim")self.root.geometry("1200x700")self.root.configure(bg="#333333")# 图像加载相关变量self.img_index = 0self.current_img = None# 创建三列布局self.create_image_column()   # 左侧图像列self.create_control_column()  # 中间控制列self.create_status_column()   # 右侧状态列# 初始化网络连接self.client_socket = None self.standard_dimensions = {}self.standard_tolerances = {}self.update_standard_rectangle()  # 从输入框初始化标准数据# 启动图像更新self.img_update()def create_image_column(self):"""创建左侧图像列"""image_frame = tk.Frame(self.root, bg="#222222", width=400)image_frame.pack(side=tk.LEFT, fill=tk.BOTH, padx=(10,5), pady=10)image_frame.pack_propagate(False)  # 固定宽度# 图像显示标签self.img_label = tk.Label(image_frame, bg="#222222")self.img_label.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)# 视觉打开按钮vision_button = tk.Button(image_frame, text="打开视觉系统", command=self.open_vision_system,font=("黑体", 18, "bold"), fg="#FFFFFF", bg="#006699",relief=tk.RAISED, borderwidth=3)vision_button.pack(side=tk.TOP, fill=tk.X, padx=5, pady=5)def create_control_column(self):"""创建中间控制列"""control_frame = tk.Frame(self.root, bg="#333333")control_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5, pady=10)# 工业风启动按钮self.start_button = tk.Button(control_frame, text="开始测量", command=self.send_command,font=("黑体", 16, "bold"), fg="#FFFFFF", bg="#006699",relief=tk.RAISED, borderwidth=3, width=8)self.start_button.pack(side=tk.TOP, fill=tk.X, anchor=tk.NW, padx=10, pady=10)# 绘图画布self.canvas = tk.Canvas(control_frame, bg="#444444", highlightthickness=0)self.canvas.pack(fill=tk.BOTH, expand=True)# 新增: 醒目的判断结果展示区域self.result_frame = tk.Frame(control_frame, bg="#333333", height=80)self.result_frame.pack(fill=tk.X, pady=(10, 0))# 初始状态为"等待测量"self.result_label = tk.Label(self.result_frame, text="等待测量...", font=("黑体", 24, "bold"), bg="#333333", fg="#FFFFFF")self.result_label.pack(expand=True, fill=tk.BOTH)# 详细结果标签self.detail_result_label = tk.Label(self.result_frame, text="", font=("黑体", 12), bg="#333333", fg="#FFFFFF")self.detail_result_label.pack(fill=tk.X, pady=(0, 5))def create_status_column(self):"""创建右侧状态列"""right_frame = tk.Frame(self.root, bg="#333333", width=300)right_frame.pack(side=tk.RIGHT, fill=tk.Y, padx=(5,10), pady=10)right_frame.pack_propagate(False)  # 固定宽度# 标准矩形设置区settings_frame = tk.LabelFrame(right_frame, text="标准设置", font=("黑体", 12),bg="#333333", fg="#FFFFFF")settings_frame.pack(pady=10, fill=tk.X, padx=(6, 0))# 尺寸输入框   315.021,131.784,315.085,132.322dimensions = [("上边 (mm):", "top", 315.021), ("右边 (mm):", "right", 131.784),("下边 (mm):", "bottom", 315.085), ("左边 (mm):", "left", 132.322)]self.entries = {}for i, (label, name, default_value) in enumerate(dimensions):tk.Label(settings_frame, text=label, bg="#333333", fg="#FFFFFF").grid(row=i, column=0, padx=5, pady=5)entry = tk.Entry(settings_frame, width=10)entry.grid(row=i, column=1, padx=5, pady=5)entry.insert(0, str(default_value))self.entries[name] = entry# 公差输入框tolerances = [("上边公差 (mm):", "top_tol", 0.1), ("右边公差 (mm):", "right_tol", 0.1),("下边公差 (mm):", "bottom_tol", 0.1), ("左边公差 (mm):", "left_tol", 0.1)]self.tolerance_entries = {}for i, (label, name, default_value) in enumerate(tolerances):tk.Label(settings_frame, text=label, bg="#333333", fg="#FFFFFF").grid(row=i, column=2, padx=5, pady=5)entry = tk.Entry(settings_frame, width=10)entry.grid(row=i, column=3, padx=5, pady=5)entry.insert(0, str(default_value))self.tolerance_entries[name] = entry# 更新按钮update_button = tk.Button(settings_frame, text="更新标准数据", command=self.update_standard_rectangle,font=("黑体", 12), fg="#FFFFFF", bg="#555555")update_button.grid(row=len(dimensions), column=0, columnspan=4, pady=10)# 日志区域log_frame = tk.LabelFrame(right_frame, text="操作日志", font=("黑体", 12), bg="#333333", fg="#FFFFFF")log_frame.pack(fill=tk.X, pady=(10, 5), padx=(6, 0))self.log_text = scrolledtext.ScrolledText(log_frame, width=55, height=12,bg="#444444", fg="#FFFFFF", font=("Consolas", 10))self.log_text.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)self.log_text.insert(tk.END, "操作日志:\n")# 实时状态区域(分为两行,每行显示两组)status_frame = tk.LabelFrame(right_frame, text="实时状态", font=("黑体", 10), bg="#333333", fg="#FFFFFF")status_frame.pack(fill=tk.X, pady=(5, 10), padx=(6, 0))self.status_labels = {"top": {"name": tk.Label(status_frame, text="上边:", bg="#333333", fg="#FFFFFF"),"status": tk.Label(status_frame, text="OK", bg="#333333", fg="#00FF00")},"right": {"name": tk.Label(status_frame, text="右边:", bg="#333333", fg="#FFFFFF"),"status": tk.Label(status_frame, text="OK", bg="#333333", fg="#00FF00")},"bottom": {"name": tk.Label(status_frame, text="下边:", bg="#333333", fg="#FFFFFF"),"status": tk.Label(status_frame, text="OK", bg="#333333", fg="#00FF00")},"left": {"name": tk.Label(status_frame, text="左边:", bg="#333333", fg="#FFFFFF"),"status": tk.Label(status_frame, text="OK", bg="#333333", fg="#00FF00")},}# 实时状态布局:两行,每行显示两组row1_keys = ["top"]row2_keys = ["right"]row3_keys = ["bottom"]row4_keys = ["left"]for i, key in enumerate(row1_keys):self.status_labels[key]["name"].grid(row=0, column=i*2, sticky="w", padx=(10,5), pady=2)self.status_labels[key]["status"].grid(row=0, column=i*2+1, sticky="w", padx=(5,10), pady=2)for i, key in enumerate(row2_keys):self.status_labels[key]["name"].grid(row=1, column=i*2, sticky="w", padx=(10,5), pady=2)self.status_labels[key]["status"].grid(row=1, column=i*2+1, sticky="w", padx=(5,10), pady=2)for i, key in enumerate(row3_keys):self.status_labels[key]["name"].grid(row=2, column=i*2, sticky="w", padx=(10,5), pady=2)self.status_labels[key]["status"].grid(row=2, column=i*2+1, sticky="w", padx=(5,10), pady=2)for i, key in enumerate(row4_keys):self.status_labels[key]["name"].grid(row=3, column=i*2, sticky="w", padx=(10,5), pady=2)self.status_labels[key]["status"].grid(row=3, column=i*2+1, sticky="w", padx=(5,10), pady=2)def img_update(self):"""实时图像更新逻辑"""img_dir = r"C:\Log\Picture\POL"try:if os.path.exists(img_dir):files = sorted([f for f in os.listdir(img_dir) if f.lower().endswith(('.png','.jpg','.bmp'))])if files:# 带缓存的图像加载path = os.path.join(img_dir, files[self.img_index % len(files)])with Image.open(path) as img:img = img.resize((280, 420), Image.Resampling.LANCZOS)  # 调整图像大小以适应列宽self.current_img = ImageTk.PhotoImage(img)self.img_label.config(image=self.current_img)self.img_index += 1except Exception as e:logging.error(f"图像加载异常: {str(e)}")finally:self.root.after(1000, self.img_update)  # 定时刷新def open_vision_system(self):"""打开视觉系统""" try:#vision_path = r"E:\Tim_Study\POL_Case\POLV1\Public_Release\POLV1.exe"vision_path = r"E:\Tim_Study\POL_Case\Vision\Public_Release\Vision.exe"if os.path.exists(vision_path):subprocess.Popen(vision_path)self.log_message("视觉系统已启动")else:messagebox.showerror("错误", f"未找到视觉系统程序: {vision_path}")self.log_message(f"视觉系统程序未找到: {vision_path}")except Exception as e:logging.error(f"启动视觉系统错误: {str(e)}")messagebox.showerror("错误", f"启动视觉系统失败: {e}")self.log_message(f"启动视觉系统错误: {e}")def log_message(self, message):timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")log_entry = f"{timestamp} - {message}\n"self.log_text.insert(tk.END, log_entry)self.log_text.see(tk.END)logging.info(message)def send_command(self):server_ip = "127.0.0.1"port = 7930try:self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)self.client_socket.connect((server_ip, port))self.client_socket.sendall(b"V1_Point_Draw")threading.Thread(target=self.receive_data).start()self.log_message("命令发送成功: V1_Point_Draw")# 更新结果展示区域状态self.result_label.config(text="测量中...", fg="#FFFF00")  # 黄色表示测量中self.detail_result_label.config(text="")except Exception as e:logging.error(f"连接错误 {e}")messagebox.showerror("错误", f"连接失败: {e}\n\n\n请先确认视觉系统")self.log_message(f"连接错误: {e}")# 更新结果展示区域状态self.result_label.config(text="连接失败", fg="#FF0000")  # 红色表示错误self.detail_result_label.config(text=str(e))def receive_data(self):try:while True:data = self.client_socket.recv(1024).decode('utf-8')if not data:breakself.update_ui(data)except Exception as e:logging.error(f"数据接收错误 {e}")messagebox.showerror("错误", f"数据接收失败: {e}")self.log_message(f"数据接收错误: {e}")# 更新结果展示区域状态self.result_label.config(text="接收错误", fg="#FF0000")self.detail_result_label.config(text=str(e))finally:self.client_socket.close()self.log_message("连接已关闭")def update_ui(self, data):self.draw_rectangle_with_dimensions(data)self.log_message(f"接收数据: {data}")# 更新结果展示区域self.update_result_display(data)def draw_rectangle_with_dimensions(self, data):try:self.canvas.delete("all")points = list(map(float, data.split(',')))if len(points) != 4:raise ValueError("数据格式错误,需要4个参数")# 绘制标准矩形self.draw_standard_rectangle()# 绘制实时矩形x1, y1 = 80, 100scale = min(1000 / max(points), 1)  # 自动缩放比例x2 = x1 + points[0] * scaley2 = y1 + points[1] * scaleself.canvas.create_rectangle(x1, y1, x2, y2, outline="#FF0000", width=2)# 实时矩形尺寸标注self.create_dimension_text((x1 + x2)/2, y1-30, f"{points[0]:.3f} mm", "#FF0000")self.create_dimension_text((x1 + x2)/2, y2+30, f"{points[2]:.3f} mm", "#FF0000")self.create_dimension_text(x1-30, (y1 + y2)/2, f"{points[3]:.3f} mm", "#FF0000", 90)self.create_dimension_text(x2+30, (y1 + y2)/2, f"{points[1]:.3f} mm", "#FF0000", 90)# 实时矩形中心显示"当前测量数据"self.canvas.create_text((x1 + x2)/2, (y1 + y2)/2, text="  ",fill="#FFFFFF", font=("Arial", 12), angle=90)# 更新实时状态self.update_status(points)except Exception as e:logging.error(f"绘图错误 {e}")messagebox.showerror("错误", f"绘图失败: {e}")self.log_message(f"绘图错误: {e}")# 更新结果展示区域状态self.result_label.config(text="绘图错误", fg="#FF0000")self.detail_result_label.config(text=str(e))def update_result_display(self, data):"""优化后的结果判断逻辑"""try:points = list(map(float, data.split(',')))if len(points) != 4:raise ValueError("需要4个测量参数")all_ok = Truedetails = []status_colors = {}for key, value in zip(["top", "right", "bottom", "left"], points):std = self.standard_dimensions[key]tol = self.standard_tolerances[f"{key}_tol"]diff = abs(value - std)if diff > tol:all_ok = Falsedetails.append(f"{key} 超差 {diff:.3f}mm")status_colors[key] = "#FF0000"else:details.append(f"{key} 合格 ±{diff:.3f}mm")status_colors[key] = "#00FF00"# 更新实时状态显示self.status_labels[key]["status"].config(text=f"{value:.3f}mm (标准{std:.3f}±{tol:.3f})",fg=status_colors[key])# 更新总体结果显示if all_ok:self.result_label.config(text="测量合格", fg="#00FF00")self.detail_result_label.config(text="所有尺寸均在公差范围内")else:self.result_label.config(text="测量不合格", fg="#FF0000")self.detail_result_label.config(text=" | ".join(details))except Exception as e:self.result_label.config(text="数据解析错误", fg="#FF0000")self.detail_result_label.config(text=str(e))logging.error(f"结果判断错误: {str(e)}")def draw_standard_rectangle(self):try:# 获取标准尺寸dimensions = {k: float(v.get()) for k, v in self.entries.items() if v.get()}if len(dimensions) != 4:return# 更新标准尺寸self.standard_dimensions = dimensions# 标准矩形参数std_x1, std_y1 = 80, 100scale = min(1000 / max(dimensions.values()), 1)  # 自动缩放比例std_x2 = std_x1 + dimensions['top'] * scalestd_y2 = std_y1 + dimensions['right'] * scale# 绘制标准矩形self.canvas.create_rectangle(std_x1, std_y1, std_x2, std_y2, outline="#00FF00", width=2)self.canvas.create_text((std_x1 + std_x2)/2, (std_y1 + std_y2)/2,text="白色标准值\n\n红色测量值", fill="#FFFFFF", font=("黑体", 14, "bold"))# 标准尺寸标注self.create_dimension_text((std_x1 + std_x2)/2, std_y1-10, f"{dimensions['top']:.3f} mm", "#FFFFFF")self.create_dimension_text((std_x1 + std_x2)/2, std_y2+10, f"{dimensions['bottom']:.3f} mm", "#FFFFFF")self.create_dimension_text(std_x1-10, (std_y1 + std_y2)/2, f"{dimensions['left']:.3f} mm", "#FFFFFF", 90)self.create_dimension_text(std_x2+10, (std_y1 + std_y2)/2, f"{dimensions['right']:.3f} mm", "#FFFFFF", 90)except ValueError:passdef create_dimension_text(self, x, y, text, color, angle=0):return self.canvas.create_text(x, y, text=text, fill=color,font=("Arial", 10), angle=angle, anchor=tk.CENTER)def update_status(self, real_time_data):# 获取公差值try:tolerances = {k: float(v.get()) for k, v in self.tolerance_entries.items() if v.get()}except ValueError:messagebox.showerror("错误", "请输入有效的公差值!")returnfor key, value in zip(["top", "right", "bottom", "left"], real_time_data):standard_value = self.standard_dimensions[key]tolerance = tolerances[f"{key}_tol"]  # 动态获取对应边的公差diff = abs(value - standard_value)if diff <= tolerance:status = "OK"color = "#00FF00"else:status = f"NG ({diff - tolerance:.3f} mm)"color = "#FF0000"# 更新状态标签self.status_labels[key]["status"].config(text=status, fg=color)def update_standard_rectangle(self):"""更新标准矩形尺寸和公差"""try:# 验证并获取标准尺寸standard_dimensions = {}required_keys = ["top", "right", "bottom", "left"]for key in required_keys:value = self.entries[key].get()if not value:raise ValueError(f"请填写{key}尺寸")standard_dimensions[key] = float(value)# 验证并获取公差值standard_tolerances = {}required_tols = ["top_tol", "right_tol", "bottom_tol", "left_tol"]for key in required_tols:value = self.tolerance_entries[key].get()if not value:raise ValueError(f"请填写{key}公差")standard_tolerances[key] = float(value)# 更新标准数据self.standard_dimensions = standard_dimensionsself.standard_tolerances = standard_tolerancesself.draw_standard_rectangle()self.log_message("标准数据更新成功")except ValueError as e:messagebox.showerror("输入错误", str(e))logging.error(f"标准数据更新失败: {str(e)}")if __name__ == "__main__":root = tk.Tk()app = IndustrialApp(root)root.mainloop()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/80307.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/80307.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/80307.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【优秀三方库研读】【C++基础知识】odygrd/quill -- 折叠表达式

compute_encoded_size_and_cache_string_lengths 方法中这段代码是一个C的折叠表达式&#xff08;fold expression&#xff09;的应用&#xff0c;用于计算多个参数编码后的总大小。下面我将详细解释这段代码的每个部分&#xff0c;并说明为什么这样写。 代码如下&#xff1a; …

数据库安装和升级和双主配置

备份和导入数据 ./mysqldump -u root -p123321 test > test.sql rsync -av test.sql root192.168.0.212:/usr/local/mysql/ ./mysql -uroot -p test < …/test.sql sudo tar -zxvf mysql-5.7.44-linux-glibc2.12-x86_64.tar.gz -C /usr/local/ sudo ln -sfn /usr/loca…

【C语言】条件编译

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:C语言 ⚙️操作环境:Visual Studio 2022 目录 条件编译 常用的预处理指令 核心应用场景 1.防止头文件重复包含 2.跨平台兼容性 3.调试模式与发布模式 4.功能开关 5.代码兼容性处理 结语 条件编译 一般情况下,源程序中所有…

如何在安卓平板上下载安装Google Chrome【轻松安装】

安卓平板可以通过系统内置的应用商店直接搜索并下载谷歌浏览器。用户打开平板上的“Play 商店”&#xff0c;在搜索框输入Google Chrome。出现结果后&#xff0c;点击第一个带有“Google LLC”字样的应用图标&#xff0c;然后点“安装”按钮。下载和安装时间和网速有关&#xf…

.NET代码保护混淆和软件许可系统——Eziriz .NET Reactor 7

.NET代码保护混淆和软件许可系统——Eziriz .NET Reactor 7 1、简介2、功能特点3、知识产权保护功能4、强大的许可系统5、软件开发工具包6、部署方式7、下载 1、简介 .NET Reactor是用于为.NET Framework编写的软件的功能强大的代码保护和软件许可系统&#xff0c;并且支持生成…

利用 SSE 实现文字吐字效果:技术与实践

利用 SSE 实现文字吐字效果:技术与实践 引言 在现代 Web 应用开发中,实时交互功能愈发重要。例如,在线聊天、实时数据监控、游戏中的实时更新等场景,都需要服务器能够及时将数据推送给客户端。传统的请求 - 响应模式在处理实时性要求较高的场景时显得力不从心,而 Server…

一个简单易用的密码生成器

基于浏览器的确定性密码生成工具&#xff0c;通过用户输入的网站名称和盐值生成符合安全要求的密码。特点&#xff1a; • 相同输入始终生成相同密码 • 密码自动包含大小写字母、数字和特殊符号 • 以字母开头&#xff0c;固定8位长度 • 完全在客户端运行&#xff0c;保护…

水上与水下遥控技术要点对比

1. 水上无人机遥控器技术要点 (1) 控制方式 多通道控制&#xff1a;通常使用2.4GHz或5.8GHz无线电信号&#xff0c;支持多通道&#xff08;如4通道以上&#xff09;分别控制飞行器的姿态&#xff08;俯仰、横滚、偏航&#xff09;和油门。 高级飞行模式&#xff1a;如定高模…

Android_SDK链接 雷神模拟器(端口问题) --- app笔记

调试环境&#xff1a;JDK&#xff08;java&#xff09; SDK&#xff08;android&#xff09; Node.js 雷神模拟器&#xff08;或 真机&#xff09; Appium&#xff08;Appium Server【内外件&#xff08;dos内件、界面化工具&#xff09;】、Appium Inspector&#xff09; p…

FreeRTOS【3】任务调度算法

重要概念 在运行的任务&#xff0c;被称为"正在使用处理器"&#xff0c;它处于运行状态。在单处理系统中&#xff0c;任何时间里只能有一个任务处于运行状态。 非运行状态的任务&#xff0c;它处于这 3 中状态之一&#xff1a;阻塞(Blocked)、暂停(Suspended)、就绪…

SLAM常用地图对比示例

序号地图类型概述1格栅地图将现实环境栅格化&#xff0c;每一个栅格用 0 和 1 分别表示空闲和占据状态&#xff0c;初始化为未知状态 0.52特征地图以点、线、面等几何特征来描绘周围环境&#xff0c;将采集的信息进行筛选和提取得到关键几何特征3拓扑地图将重要部分抽象为地图&…

【Vue】TypeScript与Vue3集成

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Vue 文章目录 1. 前言2. 环境准备与基础搭建2.1. 安装 Node.js 与 npm/yarn/pnpm2.2. 创建 Vue3 TypeScript 项目2.2.1. 使用 Vue CLI2.2.2. 使用 Vite&#xff08;推荐&#xff09;2.2.3. 目录结构简述 3. Vue3 TS 基础语法整…

高防IP是什么

"高防IP"是指"高防护IP"&#xff0c;是一种防御DDoS&#xff08;分布式拒绝服务攻击&#xff09;的网络安全服务。在分布式拒绝服务攻击中&#xff0c;攻击者会利用许多不同的计算机或者其他设备&#xff0c;通过向目标发送大量的网络请求来尝试使目标服务…

手机访问电脑端Nginx服务器配置方式

修改当前站点Nginx的配置如下。其中端口号必须是一个比较独特的端口号&#xff0c;比如8001。这样可以跟别的项目区分开来。域名使用0.0.0.0。 server {listen 80;listen 8001;server_name zfmap.cc 0.0.0.0;假设你电脑端的ip地址是192.168.1.101,那么你的手机与你的电脑连在同…

【算法】计数排序、桶排序、基数排序

算法系列八&#xff1a;非比较排序 一、计数排序 1.实现 1.1步骤 1.2代码 2.性质 2.1稳定性 2.1.1从前往后前始版&#xff1a; 2.1.2从后往前末始版&#xff1a; 2.2复杂度 2.2.1时间复杂度 2.2.2空间复杂度 二、桶排序 1.实现 1.1步骤 1.2代码 2.稳定性 三、…

JDK版本与Spring Boot版本之间对应关系

JDK&#xff08;Java Development Kit&#xff09;版本与Spring Boot版本之间存在一定的对应关系&#xff0c;选择合适的搭配对项目的稳定性、性能及功能实现至关重要&#xff0c;以下是详细介绍&#xff1a; 主要版本对应关系 Spring Boot版本发布日期支持的JDK版本备注3.2.…

如何检测Python项目哪些依赖库没有使用

要检测Python项目中哪些依赖库未被使用&#xff0c;可以采用以下方法&#xff1a; 1. 使用静态分析工具 vulture&#xff1a;静态分析工具&#xff0c;检测未使用的代码和导入 pip install vulture vulture your_project/pyflakes&#xff1a;检查未使用的导入语句 pip ins…

【智能指针】—— 我与C++的不解之缘(三十三)

一、智能指针的使用 还记得&#xff0c;在异常学习的时候&#xff0c;我们分析出了一个问题 double Divide(int x, int y) {if (y 0){throw string("the y is zero");}return (double)x / double(y); } void test(int x, int y) {int* arr new int[10];Divide(x,…

Hadoop+Spark 笔记 2025/4/21

读书笔记 定义 1. 大数据&#xff08;Big Data&#xff09; - 指传统数据处理工具难以处理的海量、高速、多样的数据集合&#xff0c;通常具备3V特性&#xff08;Volume体量大、Velocity速度快、Variety多样性&#xff09;。扩展后还包括Veracity&#xff08;真实性&#x…

femap许可不足如何解决

在复杂的工程仿真领域&#xff0c;Femap以其强大的功能和广泛的应用场景而备受青睐。然而&#xff0c;随着用户需求的增长和项目规模的扩大&#xff0c;Femap许可不足的问题逐渐凸显&#xff0c;成为了许多工程师和团队面临的挑战。本文将为您详细解析Femap许可不足的原因&…