在线测试来料公差

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()
相关推荐
A__tao2 小时前
Elasticsearch Mapping 一键生成 Java 实体类(支持嵌套 + 自动过滤注释)
java·python·elasticsearch
研究点啥好呢2 小时前
Github热门项目推荐 | 创建你的像素风格!
c++·python·node.js·github·开源软件
迷藏4943 小时前
**发散创新:基于Rust实现的开源合规权限管理框架设计与实践**在现代软件架构中,**权限控制(RBAC)** 已成为保障
java·开发语言·python·rust·开源
明日清晨3 小时前
python扫码登录dy
开发语言·python
bazhange3 小时前
python如何像matlab一样使用向量化替代for循环
开发语言·python·matlab
人工干智能4 小时前
科普:python中你写的模块找不到了——`ModuleNotFoundError`
服务器·python
unicrom_深圳市由你创科技4 小时前
做虚拟示波器这种实时波形显示的上位机,用什么语言?
c++·python·c#
小敬爱吃饭4 小时前
Ragflow Docker部署及问题解决方案(界面为Welcome to nginx,ragflow上传文件失败,Docker中的ragflow-cpu-1一直重启)
人工智能·python·nginx·docker·语言模型·容器·数据挖掘
宸津-代码粉碎机4 小时前
Spring Boot 4.0虚拟线程实战调优技巧,最大化发挥并发优势
java·人工智能·spring boot·后端·python
知行合一。。。4 小时前
Python--04--数据容器(集合)
python