在线测试来料公差

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()
相关推荐
MY_TEUCK5 小时前
【2026最新Python+AI学习基础】Python 入门笔记篇
笔记·python·学习
赢乐6 小时前
大模型学习笔记:检索增强生成(RAG)架构
人工智能·python·深度学习·机器学习·智能体·幻觉·检索增强生成(rag)
浪里行舟8 小时前
你的品牌正在被AI“遗忘”?用BuildSOM找回搜索的下一个风口
人工智能·python·程序员
码界筑梦坊8 小时前
120-基于Python的食品营养特征数据可视化分析系统
开发语言·python·信息可视化·数据分析·毕业设计·echarts·fastapi
logo_289 小时前
Xpath语法规则的学习和使用
javascript·python·xpath·xpath语法
快乐江湖9 小时前
「层层包装」—— 装饰器模式
开发语言·python·装饰器模式
m0_7020365310 小时前
mysql如何通过索引减少行锁范围_mysql索引与加锁逻辑
jvm·数据库·python
用户03321266636710 小时前
使用 Python 设置 Word 文档文本的颜色
python
qxwlcsdn10 小时前
如何用 IndexedDB 存储从 API 获取的超大列表并实现二级索引
jvm·数据库·python
小新同学^O^10 小时前
简单学习 --> 模型微调
开发语言·人工智能·python·模型微淘