from os.path import exists from os import getcwd from threading import Thread import tkinter.messagebox import customtkinter import brake import current from time import time, strftime, localtime from urllib.request import urlopen import socket customtkinter.set_appearance_mode("System") # Modes: "System" (standard), "Dark", "Light" customtkinter.set_default_color_theme("blue") # Themes: "blue" (standard), "green", "dark-blue" customtkinter.set_widget_scaling(1.1) # widget dimensions and text size customtkinter.set_window_scaling(1.1) # window geometry dimensions socket.setdefaulttimeout(10) class App(customtkinter.CTk): def __init__(self): super().__init__() self.my_font = customtkinter.CTkFont(family="Consolas", size=16, weight="bold") self.w_param = 96 # ===================================================================== # configure window self.title("AIO - All in one automatic toolbox") # self.iconbitmap('./icon.ico') screen_width = self.winfo_screenwidth() screen_height = self.winfo_screenheight() width = screen_width - 200 height = screen_height - 200 self.geometry(f"{width}x{height}+{100}+{100}") self.protocol("WM_DELETE_WINDOW", self.func_end_call_back) self.grid_rowconfigure(3, weight=1) self.grid_columnconfigure((1, 2, 3, 4, 5, 6, 7, 8, 9), weight=1) self.minsize(1100, 500) # ===================================================================== # create frame sidebar(left) self.frame_func = customtkinter.CTkFrame(self, width=120, corner_radius=0) self.frame_func.grid(row=0, column=0, rowspan=7, sticky='nsew') # create AIO logo self.label_logo = customtkinter.CTkLabel(self.frame_func, text="Rokae AIO", height=60, font=customtkinter.CTkFont(family="Segoe Script Bold", size=24, weight="bold"), text_color="DarkSlateGray") self.label_logo.grid(row=0, column=0, padx=15, pady=15) # create start button self.btn_start = customtkinter.CTkButton(self.frame_func, corner_radius=10, text='开始运行', font=self.my_font, command=lambda: self.thread_it(self.func_start_callback)) self.btn_start.grid(row=1, column=0, sticky='new', padx=10, pady=10, ipadx=5, ipady=5) # create param check button self.btn_check = customtkinter.CTkButton(self.frame_func, corner_radius=10, text='检查参数', font=self.my_font, command=lambda: self.thread_it(self.func_check_callback)) self.btn_check.grid(row=2, column=0, sticky='new', padx=10, pady=10, ipadx=5, ipady=5) # create start button self.btn_log = customtkinter.CTkButton(self.frame_func, corner_radius=10, text='保存日志', font=self.my_font, command=lambda: self.thread_it(self.func_log_callback)) self.btn_log.grid(row=3, column=0, sticky='new', padx=10, pady=10, ipadx=5, ipady=5) # create start button self.btn_end = customtkinter.CTkButton(self.frame_func, corner_radius=10, text='结束运行', font=self.my_font, command=lambda: self.thread_it(self.func_end_call_back)) self.btn_end.grid(row=4, column=0, sticky='new', padx=10, pady=10, ipadx=5, ipady=5) # create version info self.label_version = customtkinter.CTkLabel(self.frame_func, justify='left', text="Vers: 0.1.1\nDate: 05/30/2024", font=self.my_font, text_color="DarkCyan") self.frame_func.rowconfigure(6, weight=1) self.label_version.grid(row=6, column=0, padx=20, pady=20, sticky='s') # ===================================================================== # create frame self.frame_param = customtkinter.CTkFrame(self, height=240, corner_radius=10) self.frame_param.grid(row=0, column=1, rowspan=3, columnspan=9, sticky='new', ipadx=20, ipady=10, padx=10, pady=10) # create main menu self.menu_main = customtkinter.CTkOptionMenu(self.frame_param, values=["INIT", "brake", "current"], font=self.my_font, command=self.func_main_callback) self.menu_main.grid(row=0, column=1, sticky='we', padx=(20, 10), pady=(10, 0)) self.menu_main.set("Start Here!") # create sub menu self.menu_sub = customtkinter.CTkOptionMenu(self.frame_param) # create path related self.label_path = customtkinter.CTkLabel(self.frame_param, width=self.w_param//10, text="Path", font=self.my_font) self.label_path.grid(row=0, column=2, sticky='e', pady=(10, 5)) self.entry_path = customtkinter.CTkEntry(self.frame_param, width=680, placeholder_text="数据文件夹路径", font=self.my_font) self.entry_path.grid(row=0, column=3, columnspan=7, padx=(5, 10), pady=(10, 5), sticky='we') self.entry_path.configure(state='disabled') # create av related self.label_av = customtkinter.CTkLabel(self.frame_param, width=self.w_param//10, text="AV", font=self.my_font) self.label_av.grid(row=1, column=2, sticky='e', pady=(5, 5)) self.entry_av = customtkinter.CTkEntry(self.frame_param, width=self.w_param, placeholder_text=f"角速度", font=self.my_font) self.entry_av.grid(row=1, column=3, padx=(5, 20), pady=(5, 5), sticky='w') self.entry_av.configure(state='disabled') # create rc related self.label_rc = customtkinter.CTkLabel(self.frame_param, width=self.w_param//10, text="RC", font=self.my_font) self.label_rc.grid(row=1, column=4, sticky='e', pady=(5, 5)) self.entry_rc = customtkinter.CTkEntry(self.frame_param, width=self.w_param, placeholder_text=f"额定电流", font=self.my_font) self.entry_rc.grid(row=1, column=5, padx=(5, 20), pady=(5, 5), sticky='w') self.entry_rc.configure(state='disabled') # create rpm related self.label_rpm = customtkinter.CTkLabel(self.frame_param, width=self.w_param//10, text="RPM", font=self.my_font) self.label_rpm.grid(row=1, column=6, sticky='e', pady=(5, 5)) self.entry_rpm = customtkinter.CTkEntry(self.frame_param, width=self.w_param, placeholder_text=f"额定转速", font=self.my_font) self.entry_rpm.grid(row=1, column=7, padx=(5, 20), pady=(5, 5), sticky='w') self.entry_rpm.configure(state='disabled') # create rr related self.label_rr = customtkinter.CTkLabel(self.frame_param, width=self.w_param//10, text="RR", font=self.my_font) self.label_rr.grid(row=1, column=8, sticky='e', pady=(5, 5)) self.entry_rr = customtkinter.CTkEntry(self.frame_param, width=self.w_param, placeholder_text=f"减速比", font=self.my_font) self.entry_rr.grid(row=1, column=9, padx=(5, 20), pady=(5, 5), sticky='w') self.entry_rr.configure(state='disabled') # create axis related self.label_axis = customtkinter.CTkLabel(self.frame_param, width=self.w_param//10, text="AXIS", font=self.my_font) self.label_axis.grid(row=2, column=2, sticky='e', pady=(5, 5)) self.option_axis = customtkinter.CTkOptionMenu(self.frame_param, values=["1", "2", "3", "4", "5", "6", "7"], width=self.w_param, font=self.my_font) self.option_axis.grid(row=2, column=3, padx=(5, 20), pady=(5, 5), sticky='w') self.option_axis.configure(state='disabled') # create vel related self.label_vel = customtkinter.CTkLabel(self.frame_param, width=self.w_param//10, text="Vel", font=self.my_font) self.label_vel.grid(row=2, column=4, sticky='e', pady=(5, 5)) self.option_vel = customtkinter.CTkOptionMenu(self.frame_param, values=["1", "2", "3", "4", "5", "6", "7"], width=self.w_param, font=self.my_font) self.option_vel.grid(row=2, column=5, padx=(5, 20), pady=(5, 5), sticky='w') self.option_vel.configure(state='disabled') # create trq related self.label_trq = customtkinter.CTkLabel(self.frame_param, width=self.w_param//10, text="Trq", font=self.my_font) self.label_trq.grid(row=2, column=6, sticky='e', pady=(5, 5)) self.option_trq = customtkinter.CTkOptionMenu(self.frame_param, values=["1", "2", "3", "4", "5", "6", "7"], width=self.w_param, font=self.my_font) self.option_trq.grid(row=2, column=7, padx=(5, 20), pady=(5, 5), sticky='w') self.option_trq.configure(state='disabled') # ===================================================================== # create textbox self.textbox = customtkinter.CTkTextbox(self, height=640, wrap='none', font=customtkinter.CTkFont(family="consolas", size=14), text_color="blue") self.textbox.grid(row=3, column=1, rowspan=5, columnspan=13, ipadx=10, ipady=10, padx=10, pady=10, sticky='nsew') self.textbox.configure(state='disabled') # ===================================================================== # version check cur_vers = self.label_version.cget("text").replace('\n', ' @ ').replace("Vers: ", '').replace("Date: ", '') url_vers = 'http://10.2.23.150:10003/api/v3/file/download/iJe0JkyvHtMlJQgb?sign=rqHtR2_wIoTAOts_I7GNq5xI_ZMRM7Dj6Vd3VvK6OPE%3D%3A1717072209' try: new_vers = urlopen(url_vers).read().decode('utf-8') if cur_vers.strip() != new_vers.strip(): msg = f"""当前版本:{cur_vers}\n更新版本:{new_vers}\n\n请及时更新 http://10.2.23.150:10003/s/jRfM?path=%2F""" tkinter.messagebox.showwarning(title="版本更新", message=msg) except: tkinter.messagebox.showwarning(title="版本更新", message="连接服务器失败,无法确认当前是否是最新版本......") def thread_it(self, func, *args): """ 将函数打包进线程 """ self.myThread = Thread(target=func, args=args) self.myThread.daemon = True # 主线程退出就直接让子线程跟随退出,不论是否运行完成。 self.myThread.start() def initialization(self): self.label_path.configure(text="Path", text_color="black") self.label_av.configure(text="AV", text_color="black") self.label_rc.configure(text="RC", text_color="black") self.label_rpm.configure(text="RPM", text_color="black") self.label_rr.configure(text="RR", text_color="black") self.label_axis.configure(text="AXIS", text_color="black") self.label_vel.configure(text="Vel", text_color="black") self.label_trq.configure(text="Trq", text_color="black") self.entry_path.configure(placeholder_text="数据文件夹路径", state="disabled") self.entry_av.configure(placeholder_text="角速度", state="disabled") self.entry_rc.configure(placeholder_text="额定电流", state="disabled") self.entry_rpm.configure(placeholder_text="额定转速", state="disabled") self.entry_rr.configure(placeholder_text="减速比", state="disabled") self.option_axis.configure(state="disabled") self.option_vel.configure(state="disabled") self.option_trq.configure(state="disabled") self.menu_sub.grid_forget() self.textbox.delete(index1='1.0', index2='end') self.textbox.configure(state='disabled') def func_main_callback(self, func_name): self.initialization() if func_name == 'brake': self.menu_sub = customtkinter.CTkOptionMenu(self.frame_param, values=["industrial", "cobot"], font=self.my_font, command=self.func_sub_callback) self.menu_sub.grid(row=1, column=1, sticky='we', padx=(20, 10), pady=(5, 5)) self.menu_sub.set("--select--") self.label_path.configure(text="*Path", text_color='red') self.label_av.configure(text="*AV", text_color='red') self.label_rr.configure(text="*RR", text_color='red') self.label_axis.configure(text="*AXIS", text_color='red') self.label_vel.configure(text="*Vel", text_color='red') self.label_trq.configure(text="*Trq", text_color='red') self.entry_path.configure(state="normal") self.entry_av.configure(state="normal") self.entry_rr.configure(state="normal") self.option_axis.configure(state="normal") self.option_vel.configure(state="normal") self.option_trq.configure(state="normal") elif func_name == 'current': self.menu_sub = customtkinter.CTkOptionMenu(self.frame_param, values=["max", "avg"], font=self.my_font, command=self.func_sub_callback) self.menu_sub.grid(row=1, column=1, sticky='we', padx=(20, 10), pady=(5, 5)) self.menu_sub.set("--select--") self.label_path.configure(text="*Path", text_color='red') self.label_rc.configure(text="*RC", text_color='red') self.label_trq.configure(text="*Trq", text_color='red') self.entry_path.configure(state="normal") self.entry_rc.configure(state="normal") self.option_trq.configure(state="normal") else: self.initialization() self.menu_main.set("Start Here!") def func_sub_callback(self, func_name): if func_name == "industrial": self.label_rpm.configure(text="*RPM", text_color='red') self.entry_rpm.configure(state="normal") elif func_name == "cobot": self.label_rpm.configure(text="RPM", text_color='black') self.entry_rpm.configure(state="disabled") elif func_name == "max": pass elif func_name == 'avg': pass def write2textbox(self, text, wait=0, exitcode=0): if wait != 0: self.textbox.insert(index='end', text=text) self.textbox.update() self.textbox.see('end') elif exitcode != 0: self.textbox.configure(text_color='red') self.textbox.insert(index='end', text=text + '\n') self.textbox.update() self.textbox.see('end') raise Exception(f"Error code: {exitcode}") else: self.textbox.insert(index='end', text=text + '\n') self.textbox.update() self.textbox.see('end') def check_param(self): func_name = self.menu_main.get() if func_name == 'brake': path = self.entry_path.get().strip(' ') av = self.entry_av.get().strip('- ') rr = self.entry_rr.get().strip('- ') axis = self.option_axis.get() vel = self.option_vel.get() trq = self.option_trq.get() sub_func = self.menu_sub.get() c1 = exists(path) c2 = av.isdigit() c3 = rr.isdigit() c4 = rpm = 1 c5 = sub_func in ['industrial', 'cobot'] if self.menu_sub.get() == 'industrial': rpm = self.entry_rpm.get().strip('- ') c4 = rpm.isdigit() elif self.menu_sub.get() == 'cobot': pass else: pass if c1 and c2 and c3 and c4 and c5: return 1, path, int(av), int(rr), int(rpm), int(axis), int(vel), int(trq) else: return 0, 0 elif func_name == 'current': path = self.entry_path.get() rc = self.entry_rc.get() vel = self.option_vel.get() trq = self.option_trq.get() sub_func = self.menu_sub.get() c1 = exists(path) c2 = sub_func in ['max', 'avg'] try: _ = float(rc) c3 = True except ValueError: c3 = False if c1 and c2 and c3: return 2, path, float(rc), int(vel), int(trq), sub_func else: return 0, 0 else: return 0, 0 def func_start_callback(self): self.textbox.configure(state='normal') self.textbox.delete(index1='1.0', index2='end') flag, *args = self.check_param() func_dict = {1: brake.main, 2: current.main} if flag == 1: func_dict[flag](path=args[0], av=args[1], rr=args[2], rpm=args[3], axis=args[4], vel=args[5], trq=args[6], w2t=self.write2textbox) elif flag == 2: tkinter.messagebox.showinfo(title="TBD", message="功能待实现......") # func_dict[flag](path=args[0], rc=args[1], sub_func=args[2]) else: tkinter.messagebox.showerror(title="参数错误", message="请检查对应参数是否填写正确!", ) self.textbox.configure(state='disabled') def func_check_callback(self): flag, *args = self.check_param() if flag: tkinter.messagebox.showinfo(title="参数正确", message="所有参数形式上填写无误,可以开始运行!") else: tkinter.messagebox.showerror(title="参数错误", message="需要检查对应参数是否填写正确!", ) def func_log_callback(self): content = self.textbox.get(index1='1.0', index2='end') if len(content) > 1: try: now = strftime('%Y%m%d%H%M%S', localtime(time())) log_name = f"{now}_aio.log" with open(f'{log_name}', 'w', encoding='utf-8') as objlog: objlog.write(content) tkinter.messagebox.showinfo(title="保存成功", message=f'{log_name}已被保存存至↓↓↓\n{getcwd()}') except Exception as Err: print(Err) tkinter.messagebox.showerror(title="保存失败", message="未能保存本次日志,或未能完整保存,请准备好相关数据,联系fanmingfu@rokae.com查看详细信息!", ) else: tkinter.messagebox.showwarning(title="未能保存", message="日志数据为空,不可保存!") def func_end_call_back(self): if tkinter.messagebox.askyesno(title="关闭程序", message="相关数据可能未保存,正在运行程序时有概率会损坏数据文件,确定要终止程序运行吗?"): self.destroy() else: pass pass if __name__ == "__main__": aio = App() aio.mainloop()