import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import globals
class Surface:
def __init__(self, r=float('inf'), d=0.0, n=1.0, vd=0.0):
self.r = r # 曲率半径 (mm)
self.d = d # 厚度/间隔 (mm)
self.n = n # 折射率
self.vd = vd # 阿贝数
self.x = 0.0 # 表面位置,将在系统中设置
def __str__(self):
r_str = f"{self.r:.2f}" if abs(self.r) < 1e10 else "平面"
return f"表面: r={r_str}, d={self.d:.2f}, n={self.n:.4f}, vd={self.vd:.1f}"
# 字典文件处理函数
def parse_file_to_dict(file_path):
"""从文件读取键值对到字典"""
result = {}
try:
with open(file_path, 'r') as file:
for line in file:
cleaned_line = line.strip()
if not cleaned_line or ':' not in cleaned_line:
continue
parts = cleaned_line.split(':', 1)
key = parts[0].strip()
value = parts[1].strip()
if key:
result[key] = value
return result
except Exception as e:
messagebox.showerror("错误", f"读取文件失败: {str(e)}")
return {}
def write_dict_to_file(file_path, data_dict):
"""将字典写入文件"""
try:
with open(file_path, 'w') as file:
for key, value in data_dict.items():
file.write(f"{key}:{value}\n")
return True
except Exception as e:
messagebox.showerror("错误", f"写入文件失败: {str(e)}")
return False
# 计算函数 - 留作接口
def calculate(surfaces, var1, var2, var3, var4, var5, var6):
"""计算函数,留作接口"""
# 这里可以添加实际的计算逻辑
result = "计算结果:\n"
result += f"变量1: {var1}, 变量2: {var2}, 变量3: {var3}\n"
result += f"变量4: {var4}, 变量5: {var5}, 变量6: {var6}\n\n"
result += "光学表面参数:\n"
for i, surf in enumerate(surfaces):
result += f"表面 {i+1}: {surf}\n"
return result
class MainApplication:
def __init__(self, root):
self.root = root
self.root.title("光学系统计算工具")
self.root.geometry("850x750")
# 存储光学表面的列表
self.surfs = []
# 变量定义
self.var1 = None
self.var2 = None
self.var3 = None
self.var4 = None
self.var5 = None
self.var6 = None
# 自定义数据字典
self.data_dict = {}
# 存储选项变量的字典
self.option_vars = {}
self.entry_vars = {}
self.create_widgets()
self.create_option_widgets()
self.create_optical_surface_ui()
def create_widgets(self):
# 文件操作框架
file_frame = ttk.LabelFrame(self.root, text="文件操作")
file_frame.pack(padx=10, pady=5, fill="x")
# 加载路径
ttk.Label(file_frame, text="镜头数据路径:").grid(row=0, column=0, padx=5, pady=5, sticky="e")
self.load_path_entry = ttk.Entry(file_frame, width=50)
self.load_path_entry.grid(row=0, column=1, padx=5, pady=5)
load_btn = ttk.Button(file_frame, text="加载", command=self.load_data)
load_btn.grid(row=0, column=2, padx=5, pady=5)
# 保存路径
ttk.Label(file_frame, text="保存镜头数据:").grid(row=1, column=0, padx=5, pady=5, sticky="e")
self.save_path_entry = ttk.Entry(file_frame, width=50)
self.save_path_entry.grid(row=1, column=1, padx=5, pady=5)
save_btn = ttk.Button(file_frame, text="保存", command=self.save_data)
save_btn.grid(row=1, column=2, padx=5, pady=5)
def create_option_widgets(self):
"""创建选项控件和输入框"""
option_frame = ttk.LabelFrame(self.root, text="参数选项")
option_frame.pack(padx=10, pady=5, fill="x")
# 选项配置
options = [
("物距", ["有限", "无限"]),
("孔径", ["入瞳直径", "半孔径角", "物高"]),
("视场", ["半视场角", "物高"])
]
for i, (label, choices) in enumerate(options):
# 选项框架
frame = ttk.Frame(option_frame)
frame.pack(fill="x", padx=5, pady=5)
# 选项标签
ttk.Label(frame, text=f"{label}:").pack(side=tk.LEFT, padx=5)
# 单选按钮组
var = tk.StringVar(value=choices[0])
self.option_vars[label] = var
for choice in choices:
rb = ttk.Radiobutton(frame, text=choice, variable=var, value=choice)
rb.pack(side=tk.LEFT, padx=5)
# 输入框
ttk.Label(frame, text="值:").pack(side=tk.LEFT, padx=(15, 5))
entry_var = tk.StringVar()
self.entry_vars[label] = entry_var
entry = ttk.Entry(frame, textvariable=entry_var, width=20)
entry.pack(side=tk.LEFT)
# 导入按钮
import_btn = ttk.Button(option_frame, text="导入参数", command=self.import_parameters)
import_btn.pack(pady=5)
def create_optical_surface_ui(self):
"""创建光学表面输入界面"""
input_frame = ttk.LabelFrame(self.root, text="光学表面参数")
input_frame.pack(padx=10, pady=5, fill="x")
ttk.Label(input_frame, text="曲率半径 (mm):").grid(row=0, column=0, padx=5, pady=5, sticky="e")
ttk.Label(input_frame, text="厚度 (mm):").grid(row=0, column=2, padx=5, pady=5, sticky="e")
ttk.Label(input_frame, text="折射率 (nd):").grid(row=0, column=4, padx=5, pady=5, sticky="e")
ttk.Label(input_frame, text="阿贝数 (vd):").grid(row=0, column=6, padx=5, pady=5, sticky="e")
self.radius_entry = ttk.Entry(input_frame, width=10)
self.radius_entry.grid(row=0, column=1, padx=5, pady=5)
self.radius_entry.insert(0, "50")
self.thickness_entry = ttk.Entry(input_frame, width=10)
self.thickness_entry.grid(row=0, column=3, padx=5, pady=5)
self.thickness_entry.insert(0, "5")
self.nd_entry = ttk.Entry(input_frame, width=10)
self.nd_entry.grid(row=0, column=5, padx=5, pady=5)
self.nd_entry.insert(0, "1.5")
self.vd_entry = ttk.Entry(input_frame, width=10)
self.vd_entry.grid(row=0, column=7, padx=5, pady=5)
self.vd_entry.insert(0, "60")
button_frame = ttk.Frame(input_frame)
button_frame.grid(row=1, column=0, columnspan=8, pady=5)
add_btn = ttk.Button(button_frame, text="添加表面", command=self.add_surf)
add_btn.pack(side=tk.LEFT, padx=5)
remove_btn = ttk.Button(button_frame, text="删除表面", command=self.remove_surf)
remove_btn.pack(side=tk.LEFT, padx=5)
tree_frame = ttk.LabelFrame(self.root, text="光学系统表面")
tree_frame.pack(padx=10, pady=5, fill="both", expand=True)
columns = ("radius", "thickness", "nd", "vd")
self.tree = ttk.Treeview(tree_frame, columns=columns, show="headings")
self.tree.heading("radius", text="曲率半径 (mm)")
self.tree.heading("thickness", text="厚度 (mm)")
self.tree.heading("nd", text="折射率 (nd)")
self.tree.heading("vd", text="阿贝数 (vd)")
vsb = ttk.Scrollbar(tree_frame, orient="vertical", command=self.tree.yview)
self.tree.configure(yscrollcommand=vsb.set)
self.tree.pack(side=tk.LEFT, fill="both", expand=True)
vsb.pack(side=tk.RIGHT, fill="y")
# 计算按钮
calc_frame = ttk.Frame(self.root)
calc_frame.pack(pady=10)
calc_btn = ttk.Button(calc_frame, text="开始计算", command=self.run_calculation)
calc_btn.pack(side=tk.LEFT, padx=5)
# 结果显示框
result_frame = ttk.LabelFrame(self.root, text="计算结果")
result_frame.pack(padx=10, pady=5, fill="both", expand=True)
self.result_text = tk.Text(result_frame, wrap=tk.WORD)
result_scroll_y = ttk.Scrollbar(result_frame, orient="vertical", command=self.result_text.yview)
result_scroll_x = ttk.Scrollbar(result_frame, orient="horizontal", command=self.result_text.xview)
self.result_text.configure(yscrollcommand=result_scroll_y.set, xscrollcommand=result_scroll_x.set)
result_scroll_y.pack(side=tk.RIGHT, fill="y")
result_scroll_x.pack(side=tk.BOTTOM, fill="x")
self.result_text.pack(side=tk.LEFT, fill="both", expand=True)
def add_surf(self):
try:
r = self.radius_entry.get().strip()
d = self.thickness_entry.get().strip()
n = self.nd_entry.get().strip()
v = self.vd_entry.get().strip()
r = float(r) if r else float('inf')
d = float(d) if d else 0.0
n = float(n) if n else 1.0
v = float(v) if v else 0.0
self.tree.insert("", "end", values=(f"{r if r != float('inf') else '平面'}", d, n, v))
self.surfs.append(Surface(r, d, n, v))
self.radius_entry.delete(0, tk.END)
self.thickness_entry.delete(0, tk.END)
self.nd_entry.delete(0, tk.END)
self.vd_entry.delete(0, tk.END)
self.radius_entry.focus_set()
except ValueError:
messagebox.showerror("输入错误", "请输入有效的数字")
def remove_surf(self):
selected = self.tree.selection()
if selected:
for item in selected:
self.tree.delete(item)
if self.surfs:
self.surfs.pop()
def run_calculation(self):
"""执行计算"""
if not self.surfs:
messagebox.showerror("错误", "请至少添加一个光学表面")
return
# 检查变量是否已导入
if any(v is None for v in [self.var1, self.var2, self.var3, self.var4, self.var5, self.var6]):
messagebox.showwarning("警告", "请先导入所有参数")
return
try:
# 调用计算函数
result = calculate(
self.surfs,
self.var1, self.var2, self.var3,
self.var4, self.var5, self.var6
)
# 显示结果
self.result_text.delete(1.0, tk.END)
self.result_text.insert(tk.END, result)
except Exception as e:
messagebox.showerror("计算错误", f"计算过程中发生错误: {str(e)}")
def import_parameters(self):
"""导入参数按钮处理函数"""
try:
# 根据选项分配值
for label, var in self.option_vars.items():
entry_value = self.entry_vars[label].get().strip()
if not entry_value:
messagebox.showwarning("警告", f"{label}的输入值不能为空")
return
# 尝试转换为浮点数,如果失败则保留字符串
try:
entry_value = float(entry_value)
except ValueError:
pass
# 根据选项分配值
if label == "物距":
if var.get() == "有限":
self.var1 = entry_value
else:
self.var1 = 1e15 # 无限远
elif label == "有限":
if var.get() == "入瞳直径":
self.var2 = entry_value
elif var.get() == "半孔径角":
self.var3 = entry_value
else:
self.var4 = entry_value
elif label == "视场":
if var.get() == "半视场角":
self.var5 = entry_value
else:
self.var6 = entry_value
# 显示导入结果
self.log_message("参数导入成功:")
self.log_message(f"变量1: {self.var1}, 变量2: {self.var2}")
self.log_message(f"变量3: {self.var3}, 变量4: {self.var4},变量5: {self.var5}")
self.log_message(f"变量5: {self.var5}, 变量6: {self.var6}")
except Exception as e:
messagebox.showerror("导入错误", f"参数导入失败: {str(e)}")
def log_message(self, message):
"""在结果文本框中添加消息"""
self.result_text.insert(tk.END, message + "\n")
self.result_text.see(tk.END) # 滚动到末尾
def load_data(self):
"""加载数据按钮处理函数"""
file_path = self.load_path_entry.get()
if not file_path:
messagebox.showwarning("警告", "请输入文件路径")
return
data_dict = parse_file_to_dict(file_path)
if data_dict:
messagebox.showinfo("成功", f"成功加载 {len(data_dict)} 条数据")
self.data_dict = data_dict
self.log_message(f"已加载文件: {file_path}")
def save_data(self):
"""保存数据按钮处理函数"""
file_path = self.save_path_entry.get()
if not file_path:
messagebox.showwarning("警告", "请输入保存路径")
return
# 创建要保存的数据字典
save_dict = {}
# 添加光学表面数据
for i, surf in enumerate(self.surfs):
save_dict[f"surface_{i+1}_r"] = surf.r
save_dict[f"surface_{i+1}_d"] = surf.d
save_dict[f"surface_{i+1}_n"] = surf.n
save_dict[f"surface_{i+1}_vd"] = surf.vd
# 添加变量数据
save_dict["var1"] = self.var1
save_dict["var2"] = self.var2
save_dict["var3"] = self.var3
save_dict["var4"] = self.var4
save_dict["var5"] = self.var5
save_dict["var6"] = self.var6
globals.inputData['objectPosition']= self.var1
globals.inputData['entranceDiameter'] = self.var2
globals.inputData['entrancePupilAngle'] = self.var3
globals.inputData['objectHeight'] = self.var4
globals.inputData['objectAngle'] = self.var5
globals.inputData['entrancePupilAngle'] = self.var6
# 合并其他数据
save_dict.update(self.data_dict)
if write_dict_to_file(file_path, save_dict):
messagebox.showinfo("成功", "数据保存成功")
self.log_message(f"数据已保存到: {file_path}")
if __name__ == "__main__":
root = tk.Tk()
app = MainApplication(root)
root.mainloop()
这部分代码已经不够用了,现在我要做一个光学系统的计算程序,请编写一个框架可以文件读取系统参数和保存结果,可以直接输入参数并显示结果;输入的参数包括:各折射面的曲面半径r、厚度d、d光折射率nd、阿贝数vd;入曈直径及入曈位置(相对第一个面顶点);选择输入物在无穷远(此时需输入半视场角)或物在有限远(此时需输入物高,物距,孔径角)。显示可以保存为文件的结果,包括焦距f’、理想像距l’(以透镜最后一面为参考、实际像位置(以透镜最后一面为参考、像方主面位置lH’、出瞳距lp’、理想像高y0’、球差、位置色差、子午场曲xt’、弧矢场曲xs’、像散Δxts’、实际像高、相对畸变、绝对畸变、倍率色差、子午慧差(不考虑符号,绝对值正确即可)具体计算时每个都有对应的函数(留出来,我自己编写)
最新发布