在线测试来料公差

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()
相关推荐
belldeep1 分钟前
python:mido 提取 midi文件中某一音轨的音乐数据
python·track·mido
铭阳(●´∇`●)1 小时前
Python内置函数---breakpoint()
笔记·python·学习
zhanghongyi_cpp1 小时前
python基础语法测试
python
MurphyStar1 小时前
UV: Python包和项目管理器(从入门到不放弃教程)
开发语言·python·uv
linux kernel1 小时前
Python基础语法3
python
种时光的人1 小时前
多线程出bug不知道如何调试?java线程几种常见状态
java·python·bug
Freak嵌入式2 小时前
一文速通Python并行计算:09 Python多进程编程-进程之间的数据同步-基于互斥锁、递归锁、信号量、条件变量、事件和屏障
开发语言·python·多线程·并发·并行
T糖锅G2 小时前
小白自学python第一天
开发语言·python
最爱茄子包2 小时前
从0到1掌握机器学习核心概念:用Python亲手构建你的第一个AI模型(超多代码+可视化)
人工智能·python·机器学习
心碎烤肠2 小时前
MySQL运算符
python·sql