在线测试来料公差

UI

上图 V1

上图 V2

V3

Code

python 复制代码
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 = root
        self.root.title("Design_By_Tim")
        self.root.geometry("1200x700")
        self.root.configure(bg="#333333")
        
        # 图像加载相关变量
        self.img_index = 0
        self.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.322
        dimensions = [("上边 (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 += 1
        except 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 = 7930
        
        try:
            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:
                    break
                self.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, 100
            scale = min(1000 / max(points), 1)  # 自动缩放比例
            x2 = x1 + points[0] * scale
            y2 = y1 + points[1] * scale
            self.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 = True
            details = []
            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 = False
                    details.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, 100
            scale = min(1000 / max(dimensions.values()), 1)  # 自动缩放比例
            std_x2 = std_x1 + dimensions['top'] * scale
            std_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:
            pass

    def 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("错误", "请输入有效的公差值!")
            return
        
        for 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_dimensions
            self.standard_tolerances = standard_tolerances
            
            self.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()
python 复制代码
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 = root
        self.root.title("Design_By_Tim")
        self.root.geometry("1200x700")
        self.root.configure(bg="#333333")
        
        # 图像加载相关变量
        self.img_index = 0
        self.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.322
        dimensions = [("上边 (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 += 1
        except 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 = 7930
        
        try:
            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:
                    break
                self.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, 100
            scale = min(1000 / max(points), 1)  # 自动缩放比例
            x2 = x1 + points[0] * scale
            y2 = y1 + points[1] * scale
            self.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 = True
            details = []
            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 = False
                    details.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, 100
            scale = min(1000 / max(dimensions.values()), 1)  # 自动缩放比例
            std_x2 = std_x1 + dimensions['top'] * scale
            std_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:
            pass

    def 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("错误", "请输入有效的公差值!")
            return
        
        for 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_dimensions
            self.standard_tolerances = standard_tolerances
            
            self.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()
相关推荐
深海潜水员8 分钟前
【Python】 切割图集的小脚本
开发语言·python
276695829230 分钟前
东方航空 m端 wasm req res分析
java·python·node·wasm·东方航空·东航·东方航空m端
星月昭铭1 小时前
Spring AI调用Embedding模型返回HTTP 400:Invalid HTTP request received分析处理
人工智能·spring boot·python·spring·ai·embedding
Dreamsi_zh2 小时前
Python爬虫02_Requests实战网页采集器
开发语言·爬虫·python
weixin_448617053 小时前
疏老师-python训练营-Day30模块和库的导入
开发语言·python
程序员三藏4 小时前
Web UI自动化测试之PO篇
自动化测试·软件测试·python·selenium·测试工具·职场和发展·测试用例
旧时光巷4 小时前
【Flask 基础 ①】 | 路由、参数与模板渲染
后端·python·零基础·flask·web·模板渲染·路由系统
java1234_小锋4 小时前
【NLP舆情分析】基于python微博舆情分析可视化系统(flask+pandas+echarts) 视频教程 - 微博评论IP地图可视化分析实现
python·自然语言处理·flask
golitter.5 小时前
python的异步、并发开发
开发语言·python
陈敬雷-充电了么-CEO兼CTO5 小时前
强化学习三巨头PK:PPO、GRPO、DPO谁是大模型训练的「王炸」?
人工智能·python·机器学习·chatgpt·aigc·ppo·grpo