功能:
1 界面上展示圖片,log, pass、fail、total、rate
2 自動開始運行 Main_process内部的 代碼,如果pass,播放过站语音,等待一秒,循环执行main_process,如果fail,播放不能通过的语音,测试暂停,展示图片,当按下空格键时开始下一轮循环。
3 界面中图片区域可以双击放大,查看图片细节
4 device可以点击修改,当修改窗口打开时,不可再次点击该按钮,防止多开。
注意:
可直接替換Main_process中的下面一段:
# main_process(loger).camera_run()
status, result = self.getsfis()
loger.info(f"{result}")
具體界面效果如下:
完整代碼如下:
import os
import queue
import winsound
from pathlib import Path
# from scancamera import main_process
import pysfis
from tkinter.font import Font
from ttkbootstrap import *
import tkinter as tk
from tkinter import scrolledtext,END
from tkinter import messagebox
import time
import logging
from PIL import Image,ImageTk
import threading
import chardet
def readDATfile(path):
tt = "NA"
with open(path, "rb")as f:
fixid = f.read()
f_charInfo = chardet.detect(fixid)
tt = fixid.decode(f_charInfo['encoding'])
return tt
def window_reflesh():
return window.after(100,window_reflesh)
# 重寫logging模塊中的emit,將log寫入控件中。
class TextHandler(logging.Handler):
def __init__(self, logtext):
logging.Handler.__init__(self)
self.log = logtext
@staticmethod
def current_time():
current_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
return current_time
def emit(self, record):
msg = self.format(record)
logstr = str(TextHandler.current_time()) + " " + str(msg) + "\n"
self.log.insert('end',logstr)
self.log.see(END)
class Armani(threading.Thread):
def __init__(self):
super().__init__()
self.testpath = "D:\LabelAOI\Test"
# 暂停标志, 如果Fail,界面停止, 如果pass,暂停1s重新检测
self.pause_flag = False
# 暂停 触发标致,防止多次触发, 多次测试
self.test_running = False
# device 修改标志, 防止多次触发修改弹窗
self.device_running = False
# 测试结果标致
self.resutl = "Pass"
def changedevice(self):
if self.device_running:
return
self.device_running = True
device.config(state=tk.DISABLED) # 禁用按钮
def checkstr():
new_device = devicevar.get()
if not new_device.isdigit():
messagebox.showerror("ERROR","the new device is not isdigit")
elif not len(new_device) == 6:
messagebox.showerror("ERROR","the device lenght is eque 6")
else:
messagebox.showinfo("Tips","Alter the device is successful!")
device.config(state=tk.NORMAL) # 重新启用按钮
self.device_running = False
chage_dev_ui.destroy()
device_id.set(new_device)
with open(device_path,'w')as f:
f.write(new_device)
window.after(100,window_reflesh)
chage_dev_ui = tk.Toplevel(window)
chage_dev_ui.geometry("300x200")
chage_dev_ui.title("change the deviceid")
devicevar = tk.StringVar()
tk.Label(chage_dev_ui, text='new device:',font=("", 15)).place(x=10,y=30)
tk.Entry(chage_dev_ui,textvariable=devicevar,width=10,font=("", 15)).place(x=120,y=30)
tk.Button(chage_dev_ui,text="confirm",height=3,width=10,command=checkstr).place(x=110,y=70)
def on_popup_close():
self.device_running = False
device.config(state=tk.NORMAL) # 重新启用按钮
chage_dev_ui.destroy()
chage_dev_ui.protocol("WM_DELETE_WINDOW", on_popup_close) # 绑定关闭事件
def run(self):
t1 = threading.Thread(target=self.Main_Process)
t1.start()
def getsfis(self):
SSNFile = os.path.join(self.testpath, "SSN.DAT")
if not os.path.exists(SSNFile):
self.resutl = "Fail"
errorinfor = "Camera not fount!"
return False, errorinfor
ISN = readDATfile(SSNFile).strip()
# 获取节点信息
status, result = pysfis.check_route(ISN)
# if not status or "WRONG STEP" in result[1]:
if not status:
return status, result
routeinfor = result[1]
loger.info("SFIS ROUTE:{}".format(routeinfor))
# 获取工单号
status, result = pysfis.check_MO(ISN)
if not status:
return status, result
MO = result[2]
loger.info(f"SFIS MO:{MO}")
time.sleep(0.5)
# 获取机种名
status, result = pysfis.check_model(ISN)
if not status:
return status, result
model = result[2]
time.sleep(0.5)
loger.info(f"SFIS 机种名:{model}")
# 获取90料号
status, result = pysfis.check_90info(ISN)
if not status:
return status, result
PN90 = result[3]
time.sleep(0.5)
loger.info(f"SFIS 90料号:{PN90}")
return True, "SFIS is OK"
def Main_Process(self):
while True:
if not self.test_running:
break
else:
time.sleep(0.5)
self.Result_wait()
logtext.delete('1.0', END)
self.test_running = True
# main_process(loger).camera_run()
status, result = self.getsfis()
loger.info(f"{result}")
self.image_open = os.path.join(self.testpath, "L_main_CAM_basler.jpg")
self.load_image(self.image_open)
viewimg.bind("<Double-Button-1>", lambda event: self.show_image(self.image_open))
self.END()
def END(self):
if self.resutl == "Fail":
self.Result_Fail()
self.pause_flag = True
self.resutl = "PASS"
self.Main_Process()
else:
self.Result_pass()
self.resutl = "Fail"
self.test_running = False
self.Main_Process()
def Result_Fail(self):
result_var.set("FAIL")
result_font = Font(family="Arial", size=79, weight="bold")
result.config(fg = 'red',font=result_font)
result.place(x=540, y=400)
winsound.PlaySound("D:\LabelAOI\source\FAIL.wav", winsound.SND_ALIAS)
self.load_image(self.image_open)
viewimg.bind("<Double-Button-1>", lambda event: self.show_image(self.image_open))
window.after(500, window_reflesh)
def on_key_press(self, event=None):
if self.pause_flag:
self.pause_flag = False
window.unbind('<space>') # 解绑按键事件
self.test_running = False
self.load_image(self.image_open)
viewimg.bind("<Double-Button-1>", lambda event: self.show_image(self.image_open))
window.after(500, window_reflesh)
def Result_wait(self):
result_var.set("测试中...")
result_font = Font(family="Arial", size=45, weight="bold")
result.config(fg = 'brown', font = result_font)
result.place(x=540, y=430)
window.bind('<space>', self.on_key_press)
def Result_pass(self):
result_var.set("PASS")
result_font = Font(family="Aria", size=68, weight="bold")
result.config(fg = 'green',font = result_font)
result.place(x=530, y=400)
winsound.PlaySound("D:\LabelAOI\source\PASS.wav", winsound.SND_ALIAS)
window.after(500, window_reflesh)
def show_image(self,imagepath):
self.show_image_UI = tk.Toplevel(window)
self.show_image_UI.geometry("700x500")
png = Image.open(imagepath)
filename = Path(imagepath)
name = filename.name
self.show_image_UI.title(name)
canvas = tk.Canvas(self.show_image_UI, bg='white', highlightthickness=0)
canvas.pack(side=LEFT, anchor=CENTER, fill=BOTH, expand=YES)
self.image = ImageTk.PhotoImage(image=self.image_resize(image = png, event = None, window = self.show_image_UI, frame = canvas))
self.image1 = canvas.create_image(self.win_size(self.show_image_UI, canvas)[0] // 2, self.win_size(self.show_image_UI, canvas)[1] // 2, image=self.image)
self.show_image_UI.bind(sequence = '<Configure>', func = self.handler_adaptor(self.image_resize, image = png, window = self.show_image_UI, frame = canvas))
def load_image(self, filename):
self.image = Image.open(filename)
self.photo = ImageTk.PhotoImage(image=self.image_resize(image=self.image, event=None, window= window,frame = viewimg))
self.image1 = viewimg.create_image(self.win_size(window, viewimg)[0]//2, self.win_size(window, viewimg)[1] // 2, image=self.photo)
viewimg.bind(sequence='<Configure>', func=self.handler_adaptor(self.image_resize, image=self.image, window = window, frame = viewimg))
def image_resize(self,event=None, image=None, window=None, frame=None):
if event is None:
screen_width, screen_height = self.win_size(window, frame)
else:
screen_width, screen_height = event.width, event.height
raw_width, raw_height = image.size[0], image.size[1]
max_width, max_height = raw_width, screen_height
min_width = max(raw_width, max_width)
# 按照比例缩放
min_height = int(raw_height * min_width / raw_width)
# 第1次快速调整
while min_height > screen_height:
min_height = int(min_height * .9533)
# 第2次精确微调
while min_height < screen_height:
min_height += 1
# 按照比例缩放
min_width = int(raw_width * min_height / raw_height)
# 适应性调整
while min_width > screen_width:
min_width -= 1
# 按照比例缩放
min_height = int(raw_height * min_width / raw_width)
images = image.resize((min_width, min_height), Image.Resampling.LANCZOS)
if event is None:
return images
else:
global png
frame.delete(self.image1)
png = ImageTk.PhotoImage(images)
frame.create_image(screen_width // 2, screen_height // 2, image=png)
def win_size(self, window, frame):
"""
获取窗口大小,在没有bind事件时使用
"""
window.update()
width = frame.winfo_width()
height = frame.winfo_height()
return width, height
def handler_adaptor(self, fun, **kwds):
return lambda event, fun=fun, kwds=kwds: fun(event, **kwds)
if __name__ == '__main__':
device_path = r"D:\LABELAOI\Config\DEVICE.INI"
webip_path = r"D:\LABELAOI\Config\WEBIP.INI"
TooVer = "Armani"
window = tk.Tk()
window.title(f'Armani test')
window.geometry("800x600")
title = tk.Label(window, text = 'show log Detials', font=("",15))
title.place(x=10, y=10)
viewimg = tk.Canvas(window, height =428, width = 490 , bg="green")
viewimg.place(x=10, y=40)
webver = tk.StringVar()
device_label = tk.Label(window, text='device:', font=("", 15))
web_label = tk.Label(window, text='webip:', font=("", 15))
deviceid = readDATfile(device_path).strip()
webip = readDATfile(webip_path).strip()
device_id = tk.StringVar()
device_id.set(deviceid)
device = tk.Button(window,textvariable=device_id,font=("",10),command=Armani().changedevice)
webserver = tk.Button(window,text=webip, width=25, height=1, anchor=tk.CENTER, font=("",10))
device_label.place(x=530, y=80)
device.place(x=600, y=80)
web_label.place(x=530, y=120)
webserver.place(x=600, y=120)
passcout = tk.Label(window, text = 'Pass:', font=("",15), fg='green')
passcout.place(x=530, y=160)
errorcout = tk.Label(window, text='Error:', font=("", 15), fg='red')
errorcout.place(x=530, y=200)
totalout = tk.Label(window, text='Total:', font=("", 15), fg='brown')
totalout.place(x=680, y=160)
rate = tk.Label(window, text='Rate:', font=("", 15), fg='brown')
rate.place(x=680, y=200)
result_var = tk.StringVar()
result_var.set("测试中...")
result_font = Font(family="Arial", size=45, weight="bold")
result = tk.Label(window, textvariable = result_var, font=result_font, fg = 'brown', anchor=tk.CENTER)
result.place(x = 540, y=430)
contect_font = Font(family="Arial", size=22, weight="bold")
contect = tk.Button(window, text='异常联系人', height=1, width=13, font=contect_font, fg = 'brown', bg="yellow", anchor=tk.CENTER)
contect.place(x=530, y=520)
errorTip = tk.Label(window, text = "錯誤提示", font=("", 15), fg = 'brown', anchor=tk.W)
errorTip.place(x=530, y=240)
error_variable = tk.StringVar()
error_variable.set("多貼,31d0多貼請檢查!")
result_font = Font(family="Arial", size=15, weight="bold")
errorinfo = tk.Label(window, textvariable = error_variable, font=result_font, fg = 'brown', anchor=tk.W)
errorinfo.place(x=530, y=270)
logtext = scrolledtext.ScrolledText(window, width=70, height=7)
logtext.place(x=10, y=480)
loger = logging.getLogger("log")
loger.setLevel(logging.INFO)
Handler = TextHandler(logtext)
loger.addHandler(Handler)
Armani().run()
window.mainloop()