commit d9f898715e5b39b613abd386b9e9e270ec4955a3 Author: gitea Date: Wed Jan 1 13:20:39 2025 +0800 init: UI design basically completed diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..efc4af6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +test.py +.idea/ +.venv/ +assets/logdata/ +package/ \ No newline at end of file diff --git a/assets/media/icon.ico b/assets/media/icon.ico new file mode 100644 index 0000000..4c3b21a Binary files /dev/null and b/assets/media/icon.ico differ diff --git a/assets/version/file_version_info.txt b/assets/version/file_version_info.txt new file mode 100644 index 0000000..faf5707 --- /dev/null +++ b/assets/version/file_version_info.txt @@ -0,0 +1,43 @@ +# UTF-8 +# +# For more details about fixed file info 'ffi' see: +# http://msdn.microsoft.com/en-us/library/ms646997.aspx +VSVersionInfo( + ffi=FixedFileInfo( + # filevers and prodvers should be always a tuple with four items: (1, 2, 3, 4) + # Set not needed items to zero 0. + filevers=(0, 2, 1, 1), + prodvers=(0, 2, 1, 1), + # Contains a bitmask that specifies the valid bits 'flags'r + mask=0x3f, + # Contains a bitmask that specifies the Boolean attributes of the file. + flags=0x0, + # The operating system for which this file was designed. + # 0x4 - NT and there is no need to change it. + OS=0x4, + # The general type of file. + # 0x1 - the file is an application. + fileType=0x1, + # The function of the file. + # 0x0 - the function is not defined for this fileType + subtype=0x0, + # Creation date and time stamp. + date=(0, 0) + ), + kids=[ + StringFileInfo( + [ + StringTable( + '040904b0', + [StringStruct('CompanyName', 'Rokae - https://www.rokae.com/'), + StringStruct('FileDescription', 'All in one automatic toolbox'), + StringStruct('FileVersion', '0.2.1.1 (2024-12-16)'), + StringStruct('InternalName', 'AIO.exe'), + StringStruct('LegalCopyright', '© 2024-2024 Manford Fan'), + StringStruct('OriginalFilename', 'AIO.exe'), + StringStruct('ProductName', 'AIO'), + StringStruct('ProductVersion', '0.2.1.1 (2024-12-16)')]) + ]), + VarFileInfo([VarStruct('Translation', [1033, 1200])]) + ] +) diff --git a/assets/version/vers b/assets/version/vers new file mode 100644 index 0000000..65d4fef --- /dev/null +++ b/assets/version/vers @@ -0,0 +1 @@ +0.2.1.1@12/16/2024 \ No newline at end of file diff --git a/code/common/aio.py b/code/common/aio.py new file mode 100644 index 0000000..7283d9a --- /dev/null +++ b/code/common/aio.py @@ -0,0 +1,215 @@ +# from tkinter import colorchooser +# from tkinter import font +# import tkinter as tk +# import threading +# import logging +# import time +# import os + +import customtkinter as ctk +from tkinter import messagebox +from tkinter import filedialog +from tkinter import ttk + + +class App: + def __init__(self): + # ======================================================================== + self.root = ctk.CTk() + self.__set_root() + # ======================================================================== + # self.style = ttk.Style() + # self.style.configure("nb.TNotebook", font=("Consolas", 28, "normal")) + self.entry_path_dpv = ctk.StringVar() + self.entry_path_dpv.set("数据文件夹路径") + self.entry_path_atv = ctk.StringVar() + self.entry_path_atv.set("数据文件夹路径") + self.entry_ip_atv = ctk.StringVar() + self.entry_ip_atv.set("192.168.0.160") + # ======================================================================== + self.frame_left = ctk.CTkFrame(self.root, width=80, corner_radius=0, fg_color="#E9E9E9") + # ------- + self.tabview_top = ctk.CTkTabview(self.root, width=900, height=180, fg_color="#E9E9E9", border_width=2, anchor="w", command=self.__switch_tab) + self.tabview_top.add("数据处理") + self.tabview_top.add("自动测试") + # ------- + self.tabview_bottom = ctk.CTkTabview(self.root, fg_color="#E9E9E9", border_width=2, anchor="w") + self.tabview_bottom.add("输出") + self.tabview_bottom.add("日志") + # ------- + self.frame_status = ctk.CTkFrame(self.root, height=30, bg_color="purple") + # ======================================================================== + self.label_logo = ctk.CTkLabel(self.frame_left, text="Rokae AIO", font=self.f_logo, text_color="#4F4F4F") + self.btn_start = ctk.CTkButton(self.frame_left, text="开始运行", font=self.f_normal, fg_color='#4F4F4F', command=lambda: print("---")) + self.btn_save_log = ctk.CTkButton(self.frame_left, text="保存日志", font=self.f_normal, fg_color='#4F4F4F', command=lambda: print("---")) + # ======================================================================== + self.om_main_dp = ctk.CTkOptionMenu(self.tabview_top.tab("数据处理"), width=120, dynamic_resizing=False, values=["INIT", "brake", "current", "iso", "wavelog"], font=self.f_normal, text_color='#3C3C3C', button_color='#7B6B5B', fg_color="#8D8D8D", command=print) + self.om_sub_dp = ctk.CTkOptionMenu(self.tabview_top.tab("数据处理"), width=120, dynamic_resizing=False, values=["cycle", "max", "avg"], font=self.f_normal, text_color='#3C3C3C', button_color='#7B6B5B', fg_color="#8D8D8D", command=print) + self.label_path_dp = ctk.CTkLabel(self.tabview_top.tab("数据处理"), width=50, anchor="e", text="Path", font=self.f_normal) + self.entry_path_dp = ctk.CTkEntry(self.tabview_top.tab("数据处理"), width=80, state="disabled", textvariable=self.entry_path_dpv, font=self.f_entry, text_color="#818181") + self.label_vel_dp = ctk.CTkLabel(self.tabview_top.tab("数据处理"), width=50, anchor="e", text="Vel", font=self.f_normal) + self.om_vel_dp = ctk.CTkOptionMenu(self.tabview_top.tab("数据处理"), width=80, values=["1", "2", "3", "4", "5"], font=self.f_normal) + self.label_trq_dp = ctk.CTkLabel(self.tabview_top.tab("数据处理"), width=50, anchor="e", text="Trq", font=self.f_normal) + self.om_trq_dp = ctk.CTkOptionMenu(self.tabview_top.tab("数据处理"), width=80, values=["1", "2", "3", "4", "5"], font=self.f_normal) + self.label_sensor_dp = ctk.CTkLabel(self.tabview_top.tab("数据处理"), width=50, anchor="e", text="Sensor", font=self.f_normal) + self.om_sensor_dp = ctk.CTkOptionMenu(self.tabview_top.tab("数据处理"), width=80, values=["1", "2", "3", "4", "5"], font=self.f_normal) + self.label_estop_dp = ctk.CTkLabel(self.tabview_top.tab("数据处理"), width=50, anchor="e", text="Estop", font=self.f_normal) + self.om_estop_dp = ctk.CTkOptionMenu(self.tabview_top.tab("数据处理"), width=80, values=["1", "2", "3", "4", "5"], font=self.f_normal) + self.label_trqh_dp = ctk.CTkLabel(self.tabview_top.tab("数据处理"), width=50, anchor="e", text="TrqH", font=self.f_normal) + self.om_trqh_dp = ctk.CTkOptionMenu(self.tabview_top.tab("数据处理"), width=80, values=["1", "2", "3", "4", "5"], font=self.f_normal) + # ======================================================================== + self.om_main_at = ctk.CTkOptionMenu(self.tabview_top.tab("自动测试"), width=120, dynamic_resizing=False, values=["INIT", "brake", "current"], font=self.f_normal, text_color='#3C3C3C', button_color='#7B6B5B', fg_color="#8D8D8D", command=print) + self.om_sub_at = ctk.CTkOptionMenu(self.tabview_top.tab("自动测试"), width=120, dynamic_resizing=False, values=["负载信息", "tool33", "tool66", "tool100", "inertia"], font=self.f_normal, text_color='#3C3C3C', button_color='#7B6B5B', fg_color="#8D8D8D", command=print) + self.label_ip_at = ctk.CTkLabel(self.tabview_top.tab("自动测试"), anchor="e", text="IP", font=self.f_normal) + self.entry_ip_at = ctk.CTkEntry(self.tabview_top.tab("自动测试"), width=160, textvariable=self.entry_ip_atv, font=self.f_entry, text_color="#818181") + self.btn_conn = ctk.CTkButton(self.tabview_top.tab("自动测试"), text="连接", width=60, font=self.f_segbtn) + self.progressbar_at = ctk.CTkProgressBar(self.tabview_top.tab("自动测试"), width=160, mode="indeterminate") + self.label_path_at = ctk.CTkLabel(self.tabview_top.tab("自动测试"), width=50, anchor="e", text="Path", font=self.f_normal) + self.entry_path_at = ctk.CTkEntry(self.tabview_top.tab("自动测试"), width=80, state="disabled", textvariable=self.entry_path_atv, font=self.f_entry, text_color="#818181") + self.segbutton_at = ctk.CTkSegmentedButton(self.tabview_top.tab("自动测试"), width=120, dynamic_resizing=False, values=["功能切换", "触发急停", "恢复急停", "待定功能", "功能待定", "机器状态", "告警信息"], font=self.f_segbtn) + # ======================================================================== + self.text_output = ctk.CTkTextbox(self.tabview_bottom.tab("输出"), height=10, font=self.f_text) + # ======================================================================== + self.segbutton_logs = ctk.CTkSegmentedButton(self.tabview_bottom.tab("日志"), width=200, dynamic_resizing=False, values=["上一页", "实时", "下一页"], font=self.f_segbtn) + self.btn_find = ctk.CTkButton(self.tabview_bottom.tab("日志"), text="查找", width=60, font=self.f_segbtn) + self.entry_keyword = ctk.CTkEntry(self.tabview_bottom.tab("日志"), placeholder_text="[id-level] 查找内容", width=60, font=self.f_segbtn) + self.label_loglevel = ctk.CTkLabel(self.tabview_bottom.tab("日志"), width=60, anchor="e", text="等级", font=self.f_normal) + self.om_loglevel = ctk.CTkOptionMenu(self.tabview_bottom.tab("日志"), width=60, dynamic_resizing=False, values=["DEBUG", "INFO", "WARNING", "ERROR"], font=self.f_normal, text_color='#3C3C3C', button_color='#7B6B5B', fg_color="#8D8D8D", command=print) + self.treeview_logs = ttk.Treeview(self.tabview_bottom.tab("日志"), height=10, columns=("time", "level", "module", "content")) + # ======================================================================== + with open("../../assets/version/vers", mode="r", encoding="utf-8") as f_vers: + _version, _update = f_vers.read().split("@") + _text = f" v{_version} Update@{_update}" + self.label_vers = ctk.CTkLabel(self.frame_status, text=_text, bg_color="#C9C9C9", font=self.f_status, anchor="w") + var_tips = ctk.StringVar() + var_tips.set("当前是最新版本!") + self.label_tips = ctk.CTkLabel(self.frame_status, textvariable=var_tips, bg_color="#ABCDEF", font=self.f_status, anchor="e") + # ======================================================================== + self.__draw() + + def __set_root(self): + self.root.title("AIO - All in one automatic toolbox") + self.root.iconbitmap("../../assets/media/icon.ico") + self.root.configure(fg_color="#E9E9E9") + self.root.geometry(f"1100x500+10+10") + # self.root.resizable(False, False) + # self.root.protocol("WM_DELETE_WINDOW", self.__close_root) + self.f_normal = ("Consolas", 20, "bold") + self.f_entry = ("Consolas", 18, "bold") + self.f_segbtn = ("楷体", 20, "bold") + self.f_logo = ("Segoe Script Bold", 28, "bold") + self.f_text = ("仿宋", 16, "normal") + self.f_status = ("Consolas", 12, "bold") + + def __close_root(self): + msg = "相关数据可能未保存,正在运行程序时有概率会损坏数据文件,确定要终止程序运行吗?" + res = messagebox.askyesno(title="退出程序", message=msg, default=messagebox.NO, icon=messagebox.WARNING) + if res: + self.root.destroy() + + def __switch_tab(self): + t_name = self.tabview_top.get() + if t_name == "数据处理": + self.tabview_top.configure(height=180) + elif t_name == "自动测试": + self.tabview_top.configure(height=180) + + def __draw(self): + def select_path(event): + t_name = self.tabview_top.get() + dir_path = filedialog.askdirectory() + if t_name == "数据处理": + c_origin = self.entry_path_dpv.get() + if dir_path: + self.entry_path_dpv.set(dir_path) + else: + self.entry_path_dpv.set(c_origin) + elif t_name == "自动测试": + c_origin = self.entry_path_atv.get() + if dir_path: + self.entry_path_atv.set(dir_path) + else: + self.entry_path_atv.set(c_origin) + + # ======================================================================== + self.root.rowconfigure(0, weight=1) + self.root.rowconfigure(1, weight=99) + self.root.columnconfigure(0, weight=1) + self.root.columnconfigure(1, weight=99) + self.frame_left.grid(row=0, column=0, rowspan=2, sticky="news") + self.tabview_top.grid(row=0, column=1, padx=10, pady=5, sticky="news") + self.tabview_bottom.grid(row=1, column=1, padx=10, pady=(0, 10), sticky="news") + self.frame_status.grid(row=2, column=0, columnspan=2, sticky="news") + # ======================================================================== + self.frame_left.rowconfigure(list(range(30)), weight=1) + self.frame_left.columnconfigure(0, weight=1) + self.label_logo.grid(row=0, column=0, sticky="new", padx=20, pady=(20, 40)) + self.btn_start.grid(row=1, column=0, sticky="new", padx=15, ipady=4) + self.btn_save_log.grid(row=2, column=0, sticky="new", padx=15, ipady=4) + # ======================================================================== + # self.tabview_top.tab("数据处理").grid_rowconfigure([0, 1], weight=1) + self.tabview_top.tab("数据处理").grid_columnconfigure(11, weight=1) + self.om_main_dp.grid(row=0, column=0, padx=10) + self.om_sub_dp.grid(row=1, column=0, padx=10, pady=(0, 10)) + self.label_path_dp.grid(row=0, column=1, padx=(0, 5), pady=10) + self.entry_path_dp.grid(row=0, column=2, columnspan=10, padx=(0, 10), pady=10, sticky="we") + self.label_vel_dp.grid(row=1, column=1, padx=(0, 5), pady=(0, 10)) + self.om_vel_dp.grid(row=1, column=2, padx=(0, 5), pady=(0, 10)) + self.label_trq_dp.grid(row=1, column=3, padx=(0, 5), pady=(0, 10)) + self.om_trq_dp.grid(row=1, column=4, padx=(0, 5), pady=(0, 10)) + self.label_trqh_dp.grid(row=1, column=5, padx=(0, 5), pady=(0, 10)) + self.om_trqh_dp.grid(row=1, column=6, padx=(0, 5), pady=(0, 10)) + self.label_estop_dp.grid(row=1, column=7, padx=(0, 5), pady=(0, 10)) + self.om_estop_dp.grid(row=1, column=8, padx=(0, 5), pady=(0, 10)) + self.label_sensor_dp.grid(row=1, column=9, padx=(0, 5), pady=(0, 10)) + self.om_sensor_dp.grid(row=1, column=10, padx=(0, 10), pady=(0, 10)) + + self.entry_path_dp.bind("", select_path) + self.om_main_dp.set("INIT") + self.om_vel_dp.set("1") + self.om_trq_dp.set("2") + self.om_trqh_dp.set("2") + self.om_estop_dp.set("3") + self.om_sensor_dp.set("3") + # ======================================================================== + # self.tabview_top.tab("自动测试").grid_rowconfigure([0, 1, 2], weight=1) + self.tabview_top.tab("自动测试").grid_columnconfigure(4, weight=1) + self.om_main_at.grid(row=0, column=0, padx=10, pady=10, sticky="w") + self.om_sub_at.grid(row=1, column=0, padx=10, pady=(0, 10), sticky="w") + self.label_ip_at.grid(row=0, column=1, padx=(0, 10), sticky="e") + self.entry_ip_at.grid(row=0, column=2) + self.btn_conn.grid(row=0, column=3, padx=10) + self.progressbar_at.grid(row=0, column=4, sticky="e") + self.label_path_at.grid(row=1, column=1, padx=(0, 10), sticky="e") + self.entry_path_at.grid(row=1, column=2, columnspan=3, sticky="we") + self.segbutton_at.grid(row=2, column=0, columnspan=5, sticky="we") + + self.progressbar_at.start() + self.entry_path_at.bind("", select_path) + # ======================================================================== + self.tabview_bottom.tab("输出").grid_rowconfigure(0, weight=1) + self.tabview_bottom.tab("输出").grid_columnconfigure(0, weight=1) + self.text_output.grid(row=0, column=0, padx=0, pady=1, sticky="news") + # ======================================================================== + self.tabview_bottom.tab("日志").grid_rowconfigure(1, weight=1) + self.tabview_bottom.tab("日志").grid_columnconfigure(2, weight=1) + self.segbutton_logs.grid(row=0, column=0, padx=10, pady=(0, 10), sticky="w") + self.btn_find.grid(row=0, column=1, padx=(0, 10), pady=(0, 10), sticky="w") + self.entry_keyword.grid(row=0, column=2, padx=0, pady=(0, 10), sticky="we") + self.treeview_logs.grid(row=1, column=0, columnspan=3, padx=0, pady=1, sticky="news") + + self.segbutton_logs.set("实时") + # ======================================================================== + self.frame_status.rowconfigure(0, weight=1) + self.frame_status.columnconfigure([0, 1], weight=1) + self.label_vers.grid(row=0, column=0, sticky="news") + self.label_tips.grid(row=0, column=1, sticky="news") + # ======================================================================== + + def show(self): + self.root.mainloop() + + +if __name__ == "__main__": + aio = App() + aio.show() diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..967528e --- /dev/null +++ b/readme.md @@ -0,0 +1,6 @@ +#### 其他 +customtkinter的tabview组件不支持修改字体大小,可以参考 [Changing Font of a Tabview](https://github.com/TomSchimansky/CustomTkinter/issues/2296) 进行手动修改源码实现: + a. 运行 `pip show customtkinter`,获取到库的路径 + b. 修改.../windows/widgets/ctk_tabview.py + c. 增加 from .font.ctk_font import CTkFont + d. 在大概 78 行的位置,增加 font=CTkFont(family="Consolas", size=18, weight='bold') \ No newline at end of file