在线测试来料公差

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()
相关推荐
我的xiaodoujiao3 小时前
Django 权限系统项目实战详细图文教程 2--环境搭建
后端·python·django
4SAPI9 小时前
多模型请求路由怎么设计?成本、速度和能力如何平衡
人工智能·python·gateway·php
XCDoris11 小时前
郴州logo设计机构
大数据·人工智能·python
gCode Teacher 格码致知12 小时前
Pandas教学-17:Series与Dataframe的关系
开发语言·python·pandas
马良神笔13 小时前
2026 年Rag最近技术前沿总结
后端·python·django
不像程序员的程序媛13 小时前
maven基础
python·pycharm·maven
xiaogai_gai15 小时前
仅查询策略实战:从金蝶云·星空旗舰版定时拉取收料通知单
大数据·数据库·python
benchmark_cc15 小时前
Python 量化系统如何设计统一的数据访问接口:从策略解耦到数据层架构
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
const_qiu15 小时前
第四章 00:开篇 —— 从「会聊天」到「记得住、会干活、能协作」
java·开发语言·人工智能·python
估值探索者16 小时前
【Python量化选股流水线 #04】选股器好不好用?「昨日候选→今日表现」回看验收
开发语言·python·股票数据·股票数据api接口