import tkinter as tk from tkinter import ttk from core.logger import LogLevel, PrintLog, LogData from core.sfgrid.sfgrid_ui import TradeTargetUI from core.eventbus import event_bus, EventPrintLog class MainWindow: def __init__(self): self.root = tk.Tk() self.root.title("神之一手 - 交易系统") self.root.geometry("1400x700") # 当前选中的策略Tab索引 self.current_strategy_index = 0 # 存储各个Frame的引用 self.strategy_frames = {} # 日志面板可见性标志 self.log_visible = False # 创建界面 self.create_ui() # 订阅日志事件 event_bus.subscribe(EventPrintLog, self.on_log_event) def create_ui(self): """创建UI界面""" # 主容器 main_container = ttk.Frame(self.root) main_container.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # 中间主体区域(左右布局) content_area = ttk.Frame(main_container) content_area.pack(fill=tk.BOTH, expand=True) # 左侧Tab按钮栏(垂直排列) tab_bar_frame = ttk.Frame(content_area) tab_bar_frame.pack(side=tk.LEFT, fill=tk.Y, padx=(0, 10)) # 创建Tab按钮(垂直排列,文字垂直显示) self.tab_buttons = [] strategy_names = ["蒙派\n策略", "涨停\n分析"] for idx, name in enumerate(strategy_names): btn = ttk.Button( tab_bar_frame, text=name, command=lambda i=idx: self.switch_strategy_tab(i), width=4 ) btn.pack(side=tk.TOP, pady=2, fill=tk.X) self.tab_buttons.append(btn) # 在Tab按钮下方添加退出按钮和日志按钮(底部对齐) # 使用一个填充Frame将按钮推到底部 spacer = ttk.Frame(tab_bar_frame) spacer.pack(side=tk.TOP, fill=tk.X, ipady=10) # 清空日志按钮(底部第三个) clear_log_btn = ttk.Button( tab_bar_frame, text="🗑", # 垃圾桶图标 command=self.clear_logs, width=3 ) clear_log_btn.pack(side=tk.TOP, pady=2, fill=tk.X) # 日志显示按钮(退出按钮上方) self.log_toggle_btn = ttk.Button( tab_bar_frame, text="📋", # 日志图标 command=self.toggle_log_panel, width=3 ) self.log_toggle_btn.pack(side=tk.TOP, pady=2, fill=tk.X) # 退出按钮(最底部) exit_btn = ttk.Button( tab_bar_frame, text="⏻", # 电源图标 command=self.on_exit, width=3 ) exit_btn.pack(side=tk.TOP, pady=2, fill=tk.X) # 添加垂直分隔线 separator = ttk.Separator(content_area, orient='vertical') separator.pack(side=tk.LEFT, fill=tk.Y, padx=1) # 右侧内容区域容器(用于放置不同策略的Frame) self.content_container = ttk.Frame(content_area) self.content_container.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) # 创建各个策略的Frame self.create_strategy_frames(strategy_names) # 创建全局日志面板(默认隐藏) self.create_global_log_panel(main_container) # 默认显示第一个策略 self.switch_strategy_tab(0) def create_global_log_panel(self, parent): """创建全局日志面板""" # 日志区域(默认隐藏) self.log_frame = ttk.LabelFrame(parent, text="操作日志", padding=10) # 默认不显示,通过工具栏按钮控制 # 创建日志表格 columns = ("timestamp", "level", "message") self.log_table = ttk.Treeview(self.log_frame, columns=columns, show='headings', height=8) log_column_configs = { "timestamp": ("时间", 100), "level": ("级别", 50), "message": ("消息", 1150) # 调整宽度适应全局布局 } for col in columns: title, width = log_column_configs[col] self.log_table.heading(col, text=title) self.log_table.column(col, width=width, anchor=tk.W) # 添加初始日志 from datetime import datetime timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") self.log_table.insert('', tk.END, values=(timestamp, "INFO", "系统启动成功")) # 滚动条 scrollbar = ttk.Scrollbar(self.log_frame, orient=tk.VERTICAL, command=self.log_table.yview) self.log_table.configure(yscrollcommand=scrollbar.set) self.log_table.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) scrollbar.pack(side=tk.RIGHT, fill=tk.Y) def add_log(self, level:LogLevel, message): """添加日志记录 - 全局方法""" from datetime import datetime timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") self.log_table.insert('', 0, values=(timestamp, level.value, message)) def clear_logs(self): """清空日志记录""" # 删除所有日志项 for item in self.log_table.get_children(): self.log_table.delete(item) self.add_log(LogLevel.DEBUG, "日志已清空") def create_strategy_frames(self, strategy_names): """创建各个策略的Frame""" for idx, name in enumerate(strategy_names): if idx == 0: # 第一个Tab使用TradeTargetUI,传入main_window引用 frame = TradeTargetUI(self.content_container) self.strategy_frames[idx] = frame else: # 其他策略使用占位Frame frame = ttk.Frame(self.content_container) self.strategy_frames[idx] = frame # 添加占位内容 placeholder = ttk.Label( frame, text=f"{name} - 策略界面将在此实现", font=('Arial', 14), foreground='gray' ) placeholder.pack(expand=True) def switch_strategy_tab(self, index): """切换策略Tab""" # 隐藏当前Frame if self.current_strategy_index in self.strategy_frames: self.strategy_frames[self.current_strategy_index].pack_forget() # 更新当前索引 self.current_strategy_index = index # 显示选中的Frame if index in self.strategy_frames: self.strategy_frames[index].pack(fill=tk.BOTH, expand=True) # 更新Tab按钮样式(可选,用于视觉反馈) self.update_tab_button_styles() def update_tab_button_styles(self): """更新Tab按钮的样式以显示选中状态""" # 注意:ttk.Button的样式需要通过ttk.Style来设置 # 这里简化处理,仅作为接口预留 pass def toggle_log_panel(self): """切换日志面板的显示/隐藏""" if self.log_visible: # 隐藏日志面板 self.log_frame.pack_forget() self.log_visible = False self.log_toggle_btn.config(text="📋") # 日志图标 else: # 显示日志面板 self.log_frame.pack(side=tk.BOTTOM, fill=tk.X, pady=(5, 0)) self.log_visible = True self.log_toggle_btn.config(text="🔽") # 使用不同图标表示隐藏 def on_exit(self): """退出程序""" from tkinter import messagebox result = messagebox.askyesno("确认退出", "确定要退出系统吗?") if result: self.root.destroy() def on_log_event(self, log_data: LogData): """处理日志事件""" self.add_log(log_data.level, log_data.message) def run(self): """运行程序""" self.root.mainloop()