在线测试来料公差


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.mzph.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许可不足的原因&…