ON_UPDATE_COMMAND_UI_RANGE

本文介绍如何使用ON_UPDATE_COMMAND_UI_RANGE宏在MFC应用程序中为一系列连续的命令ID映射到同一个更新消息处理函数,从而实现批量更新菜单项和工具栏按钮的状态。这种方法在需要针对一组相关功能进行状态同步时特别有用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 ON_UPDATE_COMMAND_UI_RANGE( id1, id2, memberFxn )

参数:
id1一个连续的命令ID范围的起始ID。
id2一个连续的命令ID范围的结束ID。
memberFxn命令被映射到的更新消息处理函数的名字。


说明:
使用这个宏将一个连续范围的命令ID映射到一个更新消息处理函数。更新消息处理函数更新与命令相关的菜单项和工具条按钮的状态。ID 的范围从id1开始,到id2结束。
ClassWizard不支持消息映射范围,因此你必须自己加入这个宏。

 

头文件中手工添加afx_msg void OnUpdateMenu(CCmdUI *pCmdUI);
在cpp文件messgae map处添加ON_UPDATE_COMMAND_UI_RANGE( id1, id2, OnUpdateMenu),id1和id2是你的菜单项的起始和最终ID,在OnUpdateMenu(CCmdUI *pCmdUI)中通过判断pCmdUI的m_nID或m_nIndex来实现你自己的逻辑。

例:

void CDynMenuView::OnUpdateOptions(CCmdUI* pCmdUI)
{
 CMenu *pAddinMenu, *pTopMenu;
 pTopMenu = AfxGetMainWnd()->GetMenu();
 pAddinMenu = pTopMenu->GetSubMenu(1);

 switch (pCmdUI->m_nID)
 {
  case ID_EXPAND:
   pCmdUI->Enable(pAddinMenu->GetMenuItemCount() == 2);
   break;
  case ID_STANDARD:
   pCmdUI->Enable(pAddinMenu->GetMenuItemCount() != 2);
 }
}

//对于ID_EXPAND与ID_STANDARD菜单子项,在一定的条件下改变它们的状态

import tkinter as tk from tkinter import filedialog, messagebox, ttk import numpy as np import matplotlib.pyplot as plt from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk from matplotlib.widgets import Slider, TextBox import struct import os import re import logging # 配置日志系统 logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) # 设置matplotlib中文字体支持 plt.rcParams["font.family"] = ["SimHei"] plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题 class BinaryVisualizer: def __init__(self): self.root = None self.menubar = None # 显式引用菜单栏 self.files = {} # 存储已加载的文件数据 self.current_file_alias = None self.current_frame = 0 self.width = 512 # 默认宽度 self.height = 341 # 默认高度 self.block_size = self.width * self.height # 每帧的像素数 self.value_offset = 0 # 数据偏移值 self.display_mode = "固定范围" # 默认显示模式 self.custom_min = -1000 # 默认自定义最小值 self.custom_max = 1000 # 默认自定义最大值 self.operations = {} # 存储运算结果 self.current_display_source = "original" # 当前显示源: "original" 或 "operation" self.selected_operation = None # 当前选择的运算结果 # 允许的公式字符集合 self.allowed_formula_chars = set(['+', '-', '*', '/', '(', ')', 'numpy.', 'np.', '.', '_', ' ']) self.allowed_formula_chars.update([str(i) for i in range(10)]) # 初始化matplotlib设置 plt.rcParams["figure.figsize"] = (10, 7) plt.rcParams["image.cmap"] = "gray" def detect_possible_resolutions(self, pixel_count): """检测可能的分辨率""" possible_resolutions = [] max_width = int(np.sqrt(pixel_count)) * 2 for width in range(100, max_width, 2): # 步长为2,确保宽度是偶数 if pixel_count % width == 0: height = pixel_count // width possible_resolutions.append((width, height)) return possible_resolutions def load_data(self, file_path=None, alias=None): """加载二进制数据文件""" if not file_path: file_path = filedialog.askopenfilename( title="选择二进制数据文件", filetypes=[("二进制文件", "*.dat"), ("所有文件", "*.*")] ) if not file_path: return False # 自动生成别称(A, B, C, ...) if not alias: used_aliases = set(self.files.keys()) for c in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ': if c not in used_aliases: alias = c break else: messagebox.showerror("错误", "无法生成文件别称,已达到最大限制") return False try: with open(file_path, 'rb') as bin_file: data = bin_file.read() total_bytes = len(data) # 每像素2字节,计算可能的帧数 pixel_count = total_bytes // 2 possible_frames = pixel_count // self.block_size if possible_frames == 0: # 尝试检测可能的分辨率 possible_resolutions = self.detect_possible_resolutions(pixel_count) if not possible_resolutions: messagebox.showerror("错误", f"文件太小,无法包含一个完整的{self.width}x{self.height}帧") return False # 让用户选择分辨率 resolution_window = tk.Toplevel(self.root) resolution_window.title("选择分辨率") tk.Label(resolution_window, text="无法使用默认分辨率,请选择或输入:").pack(padx=10, pady=10) resolution_frame = tk.Frame(resolution_window) resolution_frame.pack(padx=10, pady=5) tk.Label(resolution_frame, text="宽度:").pack(side=tk.LEFT, padx=5) width_entry = tk.Entry(resolution_frame, width=10) width_entry.insert(0, str(self.width)) width_entry.pack(side=tk.LEFT, padx=5) tk.Label(resolution_frame, text="高度:").pack(side=tk.LEFT, padx=5) height_entry = tk.Entry(resolution_frame, width=10) height_entry.insert(0, str(self.height)) height_entry.pack(side=tk.LEFT, padx=5) def apply_resolution(): try: self.width = int(width_entry.get()) self.height = int(height_entry.get()) self.block_size = self.width * self.height resolution_window.destroy() self.load_data(file_path, alias) # 重新加载 except ValueError: messagebox.showerror("错误", "请输入有效的整数") tk.Button(resolution_window, text="应用", command=apply_resolution).pack(pady=10) return False logger.info(f"文件大小: {total_bytes} 字节") logger.info(f"可能的帧数: {possible_frames}") # 解析每一帧数据 frames = [] for frame_idx in range(possible_frames): start = frame_idx * self.block_size * 2 # 每像素2字节 end = start + self.block_size * 2 frame_data = data[start:end] # 确保帧大小是偶数 if len(frame_data) % 2 != 0: logger.warning(f"帧 {frame_idx+1} 字节数为奇数,最后一个字节将被忽略") frame_data = frame_data[:-1] # 解析为有符号整数并应用偏移 frame_values = [] for i in range(0, len(frame_data), 2): low_byte = frame_data[i] high_byte = frame_data[i+1] try: signed_value = struct.unpack('<h', bytes([low_byte, high_byte]))[0] except struct.error as e: logger.error(f"解析帧 {frame_idx+1} 时出错: {e}") signed_value = 0 # 默认值 adjusted_value = signed_value + self.value_offset frame_values.append((signed_value, adjusted_value)) # 转换为二维数组 try: signed_array = np.array([x[0] for x in frame_values]).reshape((self.height, self.width)) adjusted_array = np.array([x[1] for x in frame_values]).reshape((self.height, self.width)) frames.append((signed_array, adjusted_array)) except ValueError as e: logger.error(f"重塑帧 {frame_idx+1} 时出错: {e}") # 添加空白帧作为替代 frames.append((np.zeros((self.height, self.width)), np.zeros((self.height, self.width)))) # 存储文件数据 self.files[alias] = { 'path': file_path, 'data': data, 'frames': frames } # 如果是第一个文件或明确指定了当前文件 if not self.current_file_alias or alias == self.current_file_alias: self.current_file_alias = alias self.current_frame = 0 # 更新UI if self.slider_frame: self.slider_frame.valmax = len(frames) - 1 self.slider_frame.set_val(0) self.slider_frame.set_active(True) # 启用滑块 if self.textbox_frame: self.textbox_frame.set_val("1") self.update_display_range() # 更新文件选择菜单 self.update_file_menu() logger.info(f"成功加载文件 {alias}: {os.path.basename(file_path)}") return True except Exception as e: messagebox.showerror("错误", f"加载文件时出错: {str(e)}") logger.error(f"加载文件时出错: {e}", exc_info=True) return False def load_multiple_files(self): """加载多个二进制数据文件""" file_paths = filedialog.askopenfilenames( title="选择多个二进制数据文件", filetypes=[("二进制文件", "*.dat"), ("所有文件", "*.*")] ) if not file_paths: return for file_path in file_paths: self.load_data(file_path) def select_file(self, alias): """选择当前文件""" if alias in self.files: self.current_file_alias = alias self.current_frame = 0 # 更新UI if self.slider_frame: self.slider_frame.valmax = len(self.files[alias]['frames']) - 1 self.slider_frame.set_val(0) if self.textbox_frame: self.textbox_frame.set_val("1") self.update_display_range() def on_frame_change(self, val): """帧滑块值改变时调用""" frame_idx = int(val) if self.current_file_alias and self.current_file_alias in self.files: max_frame = len(self.files[self.current_file_alias]['frames']) - 1 if frame_idx > max_frame: frame_idx = max_frame self.slider_frame.set_val(frame_idx) self.current_frame = frame_idx self.textbox_frame.set_val(str(frame_idx + 1)) self.update_display_range() def on_frame_number_submit(self, text): """帧号输入提交时调用""" try: frame_num = int(text) if self.current_file_alias and self.current_file_alias in self.files: max_frame = len(self.files[self.current_file_alias]['frames']) if frame_num < 1 or frame_num > max_frame: messagebox.showinfo("提示", f"请输入1到{max_frame}之间的帧号") frame_num = min(max(frame_num, 1), max_frame) self.current_frame = frame_num - 1 self.slider_frame.set_val(self.current_frame) self.update_display_range() except ValueError: messagebox.showerror("错误", "请输入有效的整数") def set_display_mode(self, mode): """设置显示模式""" self.display_mode = mode self.update_display_range() def set_custom_range(self): """设置自定义显示范围""" range_window = tk.Toplevel(self.root) range_window.title("设置自定义范围") tk.Label(range_window, text="最小值:").pack(padx=10, pady=5) min_entry = tk.Entry(range_window, width=10) min_entry.insert(0, str(self.custom_min)) min_entry.pack(padx=10) tk.Label(range_window, text="最大值:").pack(padx=10, pady=5) max_entry = tk.Entry(range_window, width=10) max_entry.insert(0, str(self.custom_max)) max_entry.pack(padx=10) def apply_range(): try: self.custom_min = int(min_entry.get()) self.custom_max = int(max_entry.get()) if self.custom_min >= self.custom_max: messagebox.showerror("错误", "最小值必须小于最大值") return self.display_mode = "自定义" self.update_display_range() range_window.destroy() except ValueError: messagebox.showerror("错误", "请输入有效的整数") tk.Button(range_window, text="应用", command=apply_range).pack(pady=10) def update_display_range(self): """更新显示范围""" if not self.current_file_alias or self.current_file_alias not in self.files: return frames = self.files[self.current_file_alias]['frames'] if not frames or self.current_frame >= len(frames): return current_frame_data = frames[self.current_frame][1] # 使用偏移后的数据 try: if self.display_mode == "固定范围": vmin = self.custom_min vmax = self.custom_max elif self.display_mode == "帧平均±1000": frame_mean = np.mean(current_frame_data) vmin = max(frame_mean - 1000, np.min(current_frame_data)) vmax = min(frame_mean + 1000, np.max(current_frame_data)) elif self.display_mode == "帧平均±200": frame_mean = np.mean(current_frame_data) vmin = max(frame_mean - 200, np.min(current_frame_data)) vmax = min(frame_mean + 200, np.max(current_frame_data)) else: # 自定义 vmin = self.custom_min vmax = self.custom_max # 更新图像显示 self.current_image.set_data(current_frame_data) self.current_image.set_clim(vmin, vmax) # 更新直方图 self.ax_hist.clear() self.ax_hist.hist(current_frame_data.flatten(), bins=50, range=(vmin, vmax), alpha=0.7) self.ax_hist.set_title("像素值分布直方图") self.ax_hist.set_xlabel("像素值") self.ax_hist.set_ylabel("频次") self.ax_hist.grid(True) # 更新标题 frame_mean = np.mean(current_frame_data) frame_std = np.std(current_frame_data) # 安全处理文件名 try: if self.current_file_alias in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ': file_name = f"文件 {self.current_file_alias}" else: file_name = self.current_file_alias except Exception as e: logger.error(f"处理文件名时出错: {e}") file_name = "未知文件" self.fig.suptitle(f"{file_name} - 帧 {self.current_frame+1}/{len(frames)} - 均值: {frame_mean:.2f}, 标准差: {frame_std:.2f}") self.canvas.draw() except Exception as e: logger.error(f"更新显示范围时出错: {e}") messagebox.showerror("显示错误", f"更新显示时出错: {str(e)}") def export_to_txt(self): """导出当前帧为TXT文件""" if not self.current_file_alias or self.current_file_alias not in self.files: messagebox.showinfo("提示", "请先加载文件") return frames = self.files[self.current_file_alias]['frames'] if not frames or self.current_frame >= len(frames): messagebox.showinfo("提示", "无效的帧") return current_frame_data = frames[self.current_frame][1] # 使用偏移后的数据 file_path = filedialog.asksaveasfilename( title="保存当前帧为文本文件", defaultextension=".txt", filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")] ) if not file_path: return try: with open(file_path, 'w') as txt_file: # 写入头部信息 txt_file.write(f"# 数据导出 - 文件: {self.current_file_alias}\n") txt_file.write(f"# 帧号: {self.current_frame+1}/{len(frames)}\n") txt_file.write(f"# 分辨率: {self.width}x{self.height}\n") txt_file.write(f"# 像素值范围: {np.min(current_frame_data)} - {np.max(current_frame_data)}\n") txt_file.write(f"# 均值: {np.mean(current_frame_data):.2f}, 标准差: {np.std(current_frame_data):.2f}\n") txt_file.write("#\n") # 写入数据 for row in current_frame_data: row_str = ' '.join([f"{float(val):.6f}" for val in row]) txt_file.write(row_str + '\n') messagebox.showinfo("成功", f"帧数据已保存到 {file_path}") except Exception as e: messagebox.showerror("错误", f"保存文件时出错: {str(e)}") def set_resolution(self): """设置图像分辨率""" resolution_window = tk.Toplevel(self.root) resolution_window.title("设置分辨率") tk.Label(resolution_window, text="宽度:").pack(padx=10, pady=5) width_entry = tk.Entry(resolution_window, width=10) width_entry.insert(0, str(self.width)) width_entry.pack(padx=10) tk.Label(resolution_window, text="高度:").pack(padx=10, pady=5) height_entry = tk.Entry(resolution_window, width=10) height_entry.insert(0, str(self.height)) height_entry.pack(padx=10) def apply_resolution(): try: new_width = int(width_entry.get()) new_height = int(height_entry.get()) if new_width <= 0 or new_height <= 0: messagebox.showerror("错误", "宽度和高度必须为正整数") return self.width = new_width self.height = new_height self.block_size = self.width * self.height # 重新加载当前文件以应用新的分辨率 if self.current_file_alias and self.current_file_alias in self.files: file_path = self.files[self.current_file_alias]['path'] self.load_data(file_path, self.current_file_alias) resolution_window.destroy() except ValueError: messagebox.showerror("错误", "请输入有效的整数") tk.Button(resolution_window, text="应用", command=apply_resolution).pack(pady=10) def set_offset(self): """设置数据偏移值""" offset_window = tk.Toplevel(self.root) offset_window.title("设置偏移值") tk.Label(offset_window, text="偏移值:").pack(padx=10, pady=5) offset_entry = tk.Entry(offset_window, width=10) offset_entry.insert(0, str(self.value_offset)) offset_entry.pack(padx=10) def apply_offset(): try: self.value_offset = int(offset_entry.get()) # 重新加载当前文件以应用新的偏移值 if self.current_file_alias and self.current_file_alias in self.files: file_path = self.files[self.current_file_alias]['path'] self.load_data(file_path, self.current_file_alias) offset_window.destroy() except ValueError: messagebox.showerror("错误", "请输入有效的整数") tk.Button(offset_window, text="应用", command=apply_offset).pack(pady=10) def create_formula(self): """创建公式窗口""" if len(self.files) < 2: messagebox.showinfo("提示", "请先加载至少两个文件") return formula_window = tk.Toplevel(self.root) formula_window.title("公式计算") formula_window.geometry("600x400") # 可用文件列表 tk.Label(formula_window, text="可用文件:").pack(padx=10, pady=5, anchor="w") files_frame = tk.Frame(formula_window) files_frame.pack(padx=10, fill="x") file_listbox = tk.Listbox(files_frame, width=50) file_listbox.pack(side=tk.LEFT, fill="both", expand=True) scrollbar = tk.Scrollbar(files_frame, orient="vertical", command=file_listbox.yview) scrollbar.pack(side=tk.RIGHT, fill="y") file_listbox.config(yscrollcommand=scrollbar.set) for alias in sorted(self.files.keys()): file_listbox.insert(tk.END, f"文件 {alias}: {os.path.basename(self.files[alias]['path'])}") # 公式输入 tk.Label(formula_window, text="公式输入 (使用文件别称如 A,B,C 进行 +-*/ 运算):").pack(padx=10, pady=5, anchor="w") formula_frame = tk.Frame(formula_window) formula_frame.pack(padx=10, fill="x") formula_entry = tk.Entry(formula_frame, width=50) formula_entry.pack(side=tk.LEFT, fill="x", expand=True) # 插入文件按钮 def insert_file_alias(): selection = file_listbox.curselection() if selection: alias = sorted(self.files.keys())[selection[0]] formula_entry.insert(tk.INSERT, alias) tk.Button(formula_frame, text="插入文件", command=insert_file_alias).pack(side=tk.LEFT, padx=5) # 帧选择 tk.Label(formula_window, text="选择帧:").pack(padx=10, pady=5, anchor="w") frame_frame = tk.Frame(formula_window) frame_frame.pack(padx=10, fill="x") frame_var = tk.StringVar(value="same") frame_options = [ ("所有文件使用相同帧", "same"), ("为每个文件指定帧", "different") ] for text, value in frame_options: tk.Radiobutton(frame_frame, text=text, variable=frame_var, value=value).pack(anchor="w") # 相同帧选择 same_frame_frame = tk.Frame(formula_window) same_frame_frame.pack(padx=10, pady=5, fill="x") tk.Label(same_frame_frame, text="帧号:").pack(side=tk.LEFT) same_frame_entry = tk.Entry(same_frame_frame, width=10) same_frame_entry.insert(0, "1") same_frame_entry.pack(side=tk.LEFT, padx=5) # 结果名称 tk.Label(formula_window, text="结果名称:").pack(padx=10, pady=5, anchor="w") result_name_frame = tk.Frame(formula_window) result_name_frame.pack(padx=10, fill="x") result_name_entry = tk.Entry(result_name_frame, width=20) result_name_entry.insert(0, "Result") result_name_entry.pack(side=tk.LEFT, padx=5) # 计算按钮 def calculate_formula(): formula = formula_entry.get().strip() if not formula: messagebox.showerror("错误", "请输入公式") return # 验证公式 valid_aliases = set(self.files.keys()) used_aliases = set(re.findall(r'[A-Z]', formula)) if not used_aliases.issubset(valid_aliases): invalid_aliases = used_aliases - valid_aliases messagebox.showerror("错误", f"公式中包含无效的文件别称: {', '.join(invalid_aliases)}") return # 额外验证公式安全性 if not self._validate_formula(formula): return try: frame_mode = frame_var.get() if frame_mode == "same": try: frame_num = int(same_frame_entry.get()) except ValueError: messagebox.showerror("错误", "请输入有效的帧号") return # 检查所有文件是否有该帧 for alias in used_aliases: if frame_num < 1 or frame_num > len(self.files[alias]['frames']): messagebox.showerror("错误", f"文件 {alias} 没有帧 {frame_num}") return # 创建变量字典 variables = {} for alias in used_aliases: variables[alias] = self.files[alias]['frames'][frame_num-1][1] # 使用偏移后的数据 # 计算结果 try: result = self.safe_eval(formula, variables) if result is None: raise ValueError("公式计算失败") except Exception as e: messagebox.showerror("错误", f"公式计算出错: {str(e)}") return # 保存结果 result_name = result_name_entry.get().strip() if not result_name: result_name = "Result" # 检查结果名称是否已存在 if result_name in self.operations: if not messagebox.askyesno("确认", f"结果名称 '{result_name}' 已存在,是否覆盖?"): return # 保存结果 self.operations[result_name] = { 'formula': formula, 'frame_mode': frame_mode, 'frame_num': frame_num if frame_mode == "same" else None, 'result': result } messagebox.showinfo("成功", f"公式计算成功,结果已保存为 '{result_name}'") formula_window.destroy() # 更新操作菜单 self.update_operations_menu() except Exception as e: messagebox.showerror("错误", f"执行计算时出错: {str(e)}") logger.error(f"执行计算时出错: {e}", exc_info=True) tk.Button(formula_window, text="计算", command=calculate_formula).pack(pady=10) def safe_eval(self, formula, variables): """安全执行公式计算""" # 验证公式 for char in formula: if char not in self.allowed_formula_chars: logger.warning(f"公式包含不允许的字符: {char}") return None # 禁用所有内置函数,只允许numpy return eval(formula, {'__builtins__': None, 'np': np, 'numpy': np}, variables) def _validate_formula(self, formula): """验证公式安全性""" for char in formula: if char not in self.allowed_formula_chars: messagebox.showerror("错误", f"公式包含不允许的字符: {char}") logger.error(f"非法公式: {formula}") return False return True def show_operation_result(self, name): """显示运算结果""" if name in self.operations: self.selected_operation = name result = self.operations[name]['result'] # 更新图像显示 self.current_image.set_data(result) # 更新显示范围 vmin = np.min(result) vmax = np.max(result) self.current_image.set_clim(vmin, vmax) # 更新直方图 self.ax_hist.clear() self.ax_hist.hist(result.flatten(), bins=50, range=(vmin, vmax), alpha=0.7) self.ax_hist.set_title("运算结果像素值分布") self.ax_hist.set_xlabel("像素值") self.ax_hist.set_ylabel("频次") self.ax_hist.grid(True) # 更新标题 formula = self.operations[name]['formula'] self.fig.suptitle(f"运算结果 - {name}: {formula}") self.canvas.draw() self.current_display_source = "operation" self.source_var.set("运算结果") # 更新数据源菜单 self._update_source_menu() def save_operation_result(self): """保存当前运算结果为TXT文件""" if not self.operations: messagebox.showinfo("提示", "没有可用的运算结果") return # 获取当前显示的运算结果名称 current_name = None if self.current_display_source == "operation" and self.selected_operation: current_name = self.selected_operation # 如果没有当前显示的结果,让用户选择 if not current_name or current_name not in self.operations: if len(self.operations) == 1: current_name = list(self.operations.keys())[0] else: # 创建选择窗口 select_window = tk.Toplevel(self.root) select_window.title("选择运算结果") tk.Label(select_window, text="请选择要保存的运算结果:").pack(padx=10, pady=10) result_listbox = tk.Listbox(select_window, width=50) result_listbox.pack(padx=10, fill="both", expand=True) for name in sorted(self.operations.keys()): result_listbox.insert(tk.END, f"{name}: {self.operations[name]['formula']}") def on_select(): selection = result_listbox.curselection() if selection: selected_name = sorted(self.operations.keys())[selection[0]] select_window.destroy() self._save_result_to_txt(selected_name) button_frame = tk.Frame(select_window) button_frame.pack(pady=10) tk.Button(button_frame, text="确定", command=on_select).pack(side=tk.LEFT, padx=10) tk.Button(button_frame, text="取消", command=select_window.destroy).pack(side=tk.LEFT, padx=10) return else: self._save_result_to_txt(current_name) def _save_result_to_txt(self, name): """实际保存运算结果到TXT文件,支持多种格式""" result = self.operations[name]['result'] file_path = filedialog.asksaveasfilename( title="保存运算结果为文本文件", defaultextension=".txt", filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")] ) if not file_path: return # 选择保存格式 format_window = tk.Toplevel(self.root) format_window.title("选择保存格式") format_var = tk.StringVar(value="decimal") format_frame = tk.Frame(format_window) format_frame.pack(padx=10, pady=10) format_options = [ ("带符号十进制数", "signed"), ("十进制数", "decimal"), ("十六进制", "hex") ] for text, value in format_options: tk.Radiobutton(format_frame, text=text, variable=format_var, value=value).pack(anchor="w", pady=2) def save_with_format(): try: format_type = format_var.get() format_window.destroy() with open(file_path, 'w') as txt_file: # 写入公式信息 txt_file.write(f"# 运算公式: {self.operations[name]['formula']}\n") txt_file.write(f"# 保存格式: {dict(format_options).get(format_type, format_type)}\n") txt_file.write("#\n") # 写入数据 for row in result: if format_type == "hex": # 转换为十六进制格式 row_str = ' '.join([f"{int(val):04X}" for val in row]) elif format_type == "signed": # 带符号十进制 row_str = ' '.join([f"{int(val):d}" for val in row]) else: # decimal # 十进制 row_str = ' '.join([f"{int(val):d}" for val in row]) txt_file.write(row_str + '\n') messagebox.showinfo("成功", f"运算结果已保存到 {file_path}") except Exception as e: messagebox.showerror("错误", f"保存文件时出错: {str(e)}") tk.Button(format_window, text="保存", command=save_with_format).pack(pady=10) tk.Button(format_window, text="取消", command=format_window.destroy).pack(pady=10) def export_to_txt(self): """导出当前帧为TXT文件,支持多种格式""" if not self.current_file_alias or self.current_file_alias not in self.files: messagebox.showinfo("提示", "请先加载文件") return frames = self.files[self.current_file_alias]['frames'] if not frames or self.current_frame >= len(frames): messagebox.showinfo("提示", "无效的帧") return current_frame_data = frames[self.current_frame][1] # 使用偏移后的数据 file_path = filedialog.asksaveasfilename( title="保存当前帧为文本文件", defaultextension=".txt", filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")] ) if not file_path: return # 选择保存格式 format_window = tk.Toplevel(self.root) format_window.title("选择保存格式") format_var = tk.StringVar(value="decimal") format_frame = tk.Frame(format_window) format_frame.pack(padx=10, pady=10) format_options = [ ("带符号十进制数", "signed"), ("十进制数", "decimal"), ("十六进制", "hex") ] for text, value in format_options: tk.Radiobutton(format_frame, text=text, variable=format_var, value=value).pack(anchor="w", pady=2) def save_with_format(): try: format_type = format_var.get() format_window.destroy() with open(file_path, 'w') as txt_file: # 写入头部信息 txt_file.write(f"# 数据导出 - 文件: {self.current_file_alias}\n") txt_file.write(f"# 帧号: {self.current_frame+1}/{len(frames)}\n") txt_file.write(f"# 分辨率: {self.width}x{self.height}\n") txt_file.write(f"# 像素值范围: {np.min(current_frame_data)} - {np.max(current_frame_data)}\n") txt_file.write(f"# 均值: {np.mean(current_frame_data):.2f}, 标准差: {np.std(current_frame_data):.2f}\n") txt_file.write("#\n") # 写入数据 for row in current_frame_data: if format_type == "hex": # 转换为十六进制格式 row_str = ' '.join([f"{int(val):04X}" for val in row]) elif format_type == "signed": # 带符号十进制 row_str = ' '.join([f"{int(val):d}" for val in row]) else: # decimal # 十进制 row_str = ' '.join([f"{int(val):d}" for val in row]) txt_file.write(row_str + '\n') messagebox.showinfo("成功", f"帧数据已保存到 {file_path}") except Exception as e: messagebox.showerror("错误", f"保存文件时出错: {str(e)}") tk.Button(format_window, text="保存", command=save_with_format).pack(pady=10) tk.Button(format_window, text="取消", command=format_window.destroy).pack(pady=10) def set_display_source(self, source): """设置显示源""" self.current_display_source = source if source == "original": # 显示原始数据 if self.current_file_alias and self.current_file_alias in self.files: frames = self.files[self.current_file_alias]['frames'] if frames and self.current_frame < len(frames): current_frame_data = frames[self.current_frame][1] # 使用偏移后的数据 # 更新图像显示 self.current_image.set_data(current_frame_data) # 更新显示范围 self.update_display_range() elif source == "operation" and self.selected_operation and self.selected_operation in self.operations: # 显示运算结果 self.show_operation_result(self.selected_operation) def on_source_changed(self, event=None): """数据源选择变化时调用""" source = self.source_var.get() if source == "原始数据": self.set_display_source("original") elif source == "运算结果" and self.operations: if not self.selected_operation or self.selected_operation not in self.operations: # 如果没有选择运算结果,选择第一个 self.selected_operation = list(self.operations.keys())[0] self.set_display_source("operation") def _get_or_create_menu(self, menu_name): """获取或创建菜单""" try: if not self.menubar: self.menubar = tk.Menu(self.root) self.root.config(menu=self.menubar) # 检查菜单是否已存在 for i in range(self.menubar.index('end') + 1): menu_label = self.menubar.entrycget(i, 'label') if menu_label == menu_name: return self.menubar.nametowidget(self.menubar.entrycget(i, 'menu')) # 创建新菜单 new_menu = tk.Menu(self.menubar, tearoff=0) self.menubar.add_cascade(label=menu_name, menu=new_menu) return new_menu except Exception as e: logger.error(f"获取或创建菜单时出错: {e}") # 不返回任何内容,让调用者处理None值 return None def update_display_menu(self): """更新显示菜单""" try: display_menu = self._get_or_create_menu("显示") if not display_menu: return display_menu.delete(0, 'end') # 创建显示模式变量 if not hasattr(self, 'display_mode_var'): self.display_mode_var = tk.StringVar(value=self.display_mode) # 显示模式 display_mode_menu = tk.Menu(display_menu, tearoff=0) display_menu.add_cascade(label="显示模式", menu=display_mode_menu) display_modes = ["固定范围", "帧平均±1000", "帧平均±200", "自定义"] for mode in display_modes: display_mode_menu.add_radiobutton( label=mode, variable=self.display_mode_var, # 修正为变量对象 value=mode, command=lambda m=mode: self.set_display_mode(m) ) file_menu.add_separator() file_menu.add_command(label="导出当前帧为TXT...", command=self.export_to_txt) file_menu.add_separator() file_menu.add_command(label="退出", command=self.root.quit) except Exception as e: logger.error(f"更新文件菜单时出错: {e}") def _update_source_menu(self): """更新数据源菜单""" try: if not self.menubar: return # 查找显示菜单 display_menu = None for i in range(self.menubar.index('end') + 1): if self.menubar.entrycget(i, 'label') == "显示": menu_name = self.menubar.entrycget(i, 'menu') display_menu = self.menubar.nametowidget(menu_name) break if not display_menu: return # 查找数据源菜单项 source_menu = None for i in range(display_menu.index('end') + 1): if display_menu.entrycget(i, 'label') == "数据源": menu_name = display_menu.entrycget(i, 'menu') source_menu = display_menu.nametowidget(menu_name) break if not source_menu: return # 清除并重新添加菜单项 source_menu.delete(0, 'end') source_menu.add_radiobutton( label="原始数据", variable=self.source_var, value="原始数据", command=self.on_source_changed ) if self.operations: source_menu.add_radiobutton( label="运算结果", variable=self.source_var, value="运算结果", command=self.on_source_changed ) except Exception as e: logger.error(f"更新数据源菜单时出错: {e}") def update_formula_menu(self): """更新公式菜单""" try: formula_menu = self._get_or_create_menu("公式") formula_menu.delete(0, 'end') formula_menu.add_command(label="创建公式...", command=self.create_formula) if self.operations: formula_menu.add_separator() operations_menu = tk.Menu(formula_menu, tearoff=0) formula_menu.add_cascade(label="运算结果", menu=operations_menu) for name in sorted(self.operations.keys()): operations_menu.add_command( label=f"{name}: {self.operations[name]['formula']}", command=lambda n=name: self.show_operation_result(n) ) formula_menu.add_separator() formula_menu.add_command(label="保存当前运算结果", command=self.save_operation_result) except Exception as e: logger.error(f"更新公式菜单时出错: {e}") def update_operations_menu(self): """更新运算结果菜单""" try: operations_menu = self._get_or_create_menu("运算结果") operations_menu.delete(0, 'end') if self.operations: for name in sorted(self.operations.keys()): operations_menu.add_command( label=f"{name}: {self.operations[name]['formula']}", command=lambda n=name: self.show_operation_result(n) ) operations_menu.add_separator() operations_menu.add_command( label="保存当前运算结果", command=self.save_operation_result ) except Exception as e: logger.error(f"更新运算结果菜单时出错: {e}") def _update_source_menu(self): """更新数据源菜单""" try: if not self.menubar: return # 查找显示菜单 display_menu_idx = None for i in range(self.menubar.index('end') + 1): if self.menubar.entrycget(i, 'label') == "显示": display_menu_idx = i break if display_menu_idx is None: return display_menu = self.menubar.entrycget(display_menu_idx, 'menu') # 查找数据源菜单项 source_menu_idx = None for i in range(display_menu.index('end') + 1): if display_menu.entrycget(i, 'label') == "数据源": source_menu_idx = i break if source_menu_idx is None: return source_menu = display_menu.entrycget(source_menu_idx, 'menu') # 清除并重新添加菜单项 source_menu.delete(0, 'end') source_menu.add_radiobutton( label="原始数据", variable=self.source_var, value="原始数据", command=self.on_source_changed ) if self.operations: source_menu.add_radiobutton( label="运算结果", variable=self.source_var, value="运算结果", command=self.on_source_changed ) except Exception as e: logger.error(f"更新数据源菜单时出错: {e}") def initialize_ui(self): """初始化用户界面""" self.root = tk.Tk() self.root.title("二进制数据可视化工具") self.root.geometry("1200x800") # 创建主框架 main_frame = tk.Frame(self.root) main_frame.pack(fill=tk.BOTH, expand=True) # 创建控制框架 control_frame = tk.Frame(main_frame, height=50) control_frame.pack(fill=tk.X, side=tk.TOP, padx=10, pady=5) # 数据源切换控件 source_frame = tk.Frame(control_frame) source_frame.pack(fill=tk.X, side=tk.RIGHT, padx=(10, 0), pady=5) tk.Label(source_frame, text="显示源:").pack(side=tk.LEFT, padx=5) self.source_var = tk.StringVar(value="original") source_combo = ttk.Combobox(source_frame, textvariable=self.source_var, width=15) source_combo['values'] = ("原始数据", "运算结果") source_combo.pack(side=tk.LEFT, padx=5) source_combo.bind("<<ComboboxSelected>>", self.on_source_changed) # 创建Matplotlib图形 self.fig, (self.ax_image, self.ax_hist) = plt.subplots(2, 1, figsize=(10, 7), gridspec_kw={'height_ratios': [4, 1]}) self.fig.subplots_adjust(hspace=0.3) # 初始图像 self.current_image = self.ax_image.imshow(np.zeros((self.height, self.width)), cmap='gray') self.ax_image.axis('off') # 初始直方图 self.ax_hist.hist(np.zeros(self.height * self.width), bins=50, alpha=0.7) self.ax_hist.set_title("像素值分布直方图") self.ax_hist.set_xlabel("像素值") self.ax_hist.set_ylabel("频次") self.ax_hist.grid(True) # 创建Canvas self.canvas = FigureCanvasTkAgg(self.fig, master=main_frame) self.canvas.draw() self.canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True, padx=10, pady=5) # 添加Matplotlib工具栏 toolbar = NavigationToolbar2Tk(self.canvas, main_frame) toolbar.update() # 创建帧控制滑块 slider_frame = tk.Frame(main_frame, height=50) slider_frame.pack(fill=tk.X, side=tk.BOTTOM, padx=10, pady=5) # 帧号标签和输入框 tk.Label(slider_frame, text="帧号:").pack(side=tk.LEFT, padx=5) # 创建Matplotlib文本框用于输入帧号 self.textbox_frame = TextBox( plt.axes([0.15, 0.01, 0.05, 0.04]), '', initial="1", color='white', hovercolor='lightgoldenrodyellow' ) self.textbox_frame.on_submit(self.on_frame_number_submit) # 创建Matplotlib滑块用于控制帧 self.slider_frame = Slider( plt.axes([0.25, 0.01, 0.65, 0.04]), '帧', 0, 100, # 初始范围,会在加载文件后更新 valinit=0, valstep=1 ) self.slider_frame.on_changed(self.on_frame_change) self.slider_frame.set_active(False) # 初始禁用,直到加载文件 # 初始化菜单 self.initialize_menus() # 更新菜单状态 self.update_file_menu() self.update_display_menu() self.update_formula_menu() # 设置数据源菜单 self._update_source_menu() # 显示欢迎信息 self.fig.suptitle("欢迎使用二进制数据可视化工具\n请从文件菜单打开二进制数据文件") self.canvas.draw() def initialize_menus(self): """初始化菜单栏""" if not self.menubar: self.menubar = tk.Menu(self.root) self.root.config(menu=self.menubar) def run(self): """运行应用程序""" self.initialize_ui() self.root.mainloop() if __name__ == "__main__": app = BinaryVisualizer() app.run() 提示Traceback (most recent call last): File "E:\zlt_work\zlt_work\DATA\读取多文件测试.py", line 1185, in <module> app.run() File "E:\zlt_work\zlt_work\DATA\读取多文件测试.py", line 1180, in run self.initialize_ui() File "E:\zlt_work\zlt_work\DATA\读取多文件测试.py", line 1161, in initialize_ui self.update_file_menu() AttributeError: 'BinaryVisualizer' object has no attribute 'update_file_menu'
06-25
把代码完整写出来,(在写代码过程中要注意:模块1里有内容改动)。修改后强调写出完整代码。class MainInterface: def init(self, root: Tk, pool: NumberPool): self.root = root self.pool = pool self.left_panel = None self.center_frame = None self.right_panel = None self.core_vars = {} self.pool_vars = {} self.status_var = StringVar() self.dynamic_text = None self.current_module = None self._setup_ui() self._setup_event_handlers() self.dynamic_content = None self.module_instances = {} # 添加模块实例存储 self._init_modules() # 初始化所有模块 def _init_modules(self): """初始化所有分析模块""" modules = { 'input_analysis': InputAnalysisModule, 'combination_analysis': CombinationAnalysisModule, 'follow_analysis': FollowAnalysisModule, 'trend_analysis': TrendAnalysisModule, 'number_generation': NumberGenerationModule } for name, cls in modules.items(): self.module_instances[name] = cls(name) def _setup_event_handlers(self): """初始化事件处理器""" event_center.subscribe(EventType.MODULE_COMPLETE, self._handle_module_complete) event_center.subscribe(EventType.UI_UPDATE, self._handle_ui_update) def _setup_ui(self): self.root.title(f"大乐透智能分析平台 - {GlobalConfig.VERSION}") self.root.geometry("1400x800") # 添加主标题(居中显示在最上面)title_frame = Frame(self.root) title_frame.pack(fill='x', pady=5) Label(title_frame, text="大乐透智能分析平台", font=('微软雅黑', 16, 'bold')).pack(expand=True) # 主容器 main_container = Frame(self.root) main_container.pack(fill='both', expand=True, padx=5, pady=(0, 5)) # 左侧面板 self.left_panel = Frame(main_container, width=200, bg="#eaeaea") self.left_panel.pack(side='left', fill='y', padx=(0, 5)) # 中间内容区 self.center_frame = Frame(main_container, width=600) self.center_frame.pack(side='left', fill='both', expand=True) # 右侧面板 self.right_panel = Frame(main_container, width=600, bg="#f5f5f5") self.right_panel.pack(side='right', fill='y') # 初始化各区域 self._setup_left_panel() self._setup_center_area() self._setup_right_panel() def _setup_left_panel(self): """初始化左侧模块按钮区""" module_names = { 'input_analysis': '1. 输入分析', 'combination_analysis': '2. 组合分析', 'follow_analysis': '3. 跟随分析', 'trend_analysis': '4. 趋势分析', 'number_generation': '5. 数字生成' } for module in GlobalConfig.MODULES: Button( self.left_panel, text=module_names[module], width=18, command=lambda m=module: self._on_module_button_click(m) ).pack(pady=3, padx=5, ipady=3) def _setup_center_area(self): """设置中间区域布局""" # 期号区 period_frame = Frame(self.center_frame, height=30, bd=1, relief='solid') period_frame.pack(fill='x', pady=(0, 5)) Label(period_frame, text="期号: ", font=('微软雅黑', 10)).pack(side='left') self.period_var = StringVar(value="2023001") Label(period_frame, textvariable=self.period_var, font=('微软雅黑', 10, 'bold')).pack(side='left') # 核心区 core_frame = Frame(self.center_frame, bd=1, relief='solid') core_frame.pack(fill='both', expand=True, pady=(0, 5)) # 核心区标题 Label(core_frame, text="核心区", font=('微软雅黑', 12, 'bold')).pack(anchor='w', padx=5, pady=2) # 核心数据展示 self.core_vars = { 'front_area': StringVar(), 'back_area': StringVar(), 'front_hot': StringVar(), 'front_cold': StringVar(), 'back_hot': StringVar(), 'back_cold': StringVar() } for label, var_name in [ ("前区:", 'front_area'), ("后区:", 'back_area'), ("前区热号:", 'front_hot'), ("前区冷号:", 'front_cold'), ("后区热号:", 'back_hot'), ("后区冷号:", 'back_cold') ]: frame = Frame(core_frame) frame.pack(fill='x', padx=5, pady=2) Label(frame, text=label, width=10, anchor='w').pack(side='left') # 添加容器Frame实现右边距2px entry_container = Frame(frame) entry_container.pack(side='left', fill='x', expand=True, padx=(0, 2)) entry = Entry(entry_container, textvariable=self.core_vars[var_name], font=('微软雅黑', 10), state='readonly', readonlybackground='#f0f0f0', relief='sunken', bd=1) entry.pack(fill='x', expand=True) # 动态区 dynamic_frame = Frame(self.center_frame, bd=1, relief='solid') dynamic_frame.pack(fill='both', expand=True) # 动态区标题框架 dynamic_header = Frame(dynamic_frame) dynamic_header.pack(fill='x', padx=5, pady=5) Label(dynamic_header, text="动态区", font=('微软雅黑', 12, 'bold')).pack(side='left') # 模块内容容器 self.module_content_frame = Frame(dynamic_frame) self.module_content_frame.pack(fill='both', expand=True, padx=5, pady=5) def _setup_right_panel(self): """设置右侧号码池布局""" # 号码池标题 pool_title_frame = Frame(self.right_panel) pool_title_frame.pack(f极ill='x', pady=5) Label(pool_title_frame, text="号码池", font=('微软雅黑', 12, 'bold')).pack(anchor='w') # 号码池内容区 pool_content = Frame(self.right_panel, bd=1, relief='solid') pool_content.pack(fill='both', expand=True, padx=5, pady=5) # 创建Canvas和Scrollbar canvas = Canvas(pool_content, highlightthickness=0) scrollbar = Scrollbar(pool_content, orient="vertical", command=canvas.yview) scrollable_frame = Frame(canvas) scrollable_frame.bind( "<Configure>", lambda e: canvas.configure(scrollregion=canvas.bbox("all"))) canvas.create_window((0, 0), window=scrollable_frame, anchor="nw") canvas.configure(yscrollcommand=scrollbar.set) # 号码池项目 - 优化布局和样式 for label, var_name, row_id in GlobalConfig.UI_CONFIG: frame = Frame(scrollable_frame) frame.grid(row=row_id, column=极0, sticky='ew', padx=5, pady=2) # 左侧标签(固定宽度8字符)lbl = Label(frame, text=label, width=8, anchor='w') lbl.pack(side='left', padx=(0, 5)) # 标签右侧留5px间距 # 右侧输入框容器(带2px右边距)entry_container = Frame(frame) entry_container.pack(side='left', fill='x', expand=True, padx=(0, 2)) var = StringVar() self.pool_vars[var_name] = var entry = Entry(entry_container, textvariable=var, font=('微软雅黑', 9), state='readonly', readonlybackground='#f0f0f0', relief='sunken', bd=1) entry.pack(fill='x', expand=True) canvas.pack(side="left", fill="both", expand=True) scrollbar.pack(side="right", fill="y") # 底部按钮区 btn_frame = Frame(self.right_panel) btn_frame.pack(fill='x', pady=5) Button(btn_frame, text="整理", width=10, command=self._organize_data).pack(side='left', padx=5) Button(btn_frame, text="冻结", width=10, command=self._freeze_data).pack(side='left', padx=5) Button(btn_frame, text="导出", width=10).pack(side='left', padx=5) def _organize_data(self): """整理号码池数据""" organize_event = Event( event_id=int(time.time()), type=EventType.DATA_ORGANIZE, source='main_ui', target='pool' ) event_center.publish(organize_event) def _freeze_data(self): """冻结号码池数据""" freeze_event = Event( event_id=int(time.time()), type=EventType.DATA_FREEZE, source='main_ui', target='pool' ) event_center.publish(freeze_event) # 以下是新增/修改的方法 def _on_module_button_click(self, module: str): """完全重构的模块显示方法 - 嵌入主界面动态区""" self.status_var.set(f"打开 {module} 模块...") self.current_module = module # 清除之前的动态内容 if self.dynamic_content: self.dynamic_content.destroy() # 创建模块专属容器 self.dynamic_content = Frame(self.module_content_frame) self.dynamic_content.pack(fill='both', expand=True, padx=5, pady=5) # 顶部模块标签区 top_label_frame = Frame(self.dynamic_content) top_label_frame.pack(fill='x', pady=5) module_labels = { 'input_analysis': '1. 输入分析', 'combination_analysis': '2. 组合分析', 'follow_analysis': '3. 跟随分析', 'trend_analysis': '4. 趋势分析', 'number_generation': '5. 数字生成' } Label(top_label_frame, text=module_labels.get(module, module), font=('微软雅黑', 14, 'bold')).pack() # 内容区容器 content_frame = Frame(self.dynamic_content, bd=1, relief='solid') content_frame.pack(fill='both', expand=True, padx=5, pady=5) # 根据模块类型创建特定内容 if module == "input_analysis": self._create_input_analysis_content(content_frame) elif module == "combination_analysis": self._create_combination_analysis_content(content_frame) elif module == "follow_analysis": self._create_follow_analysis_content(content_frame) elif module == "trend_analysis": self._create_trend_analysis_content(content_frame) elif module == "number_generation": self._create_number_generation_content(content_frame) # 底部按钮区 bottom_frame = Frame(self.dynamic_content) bottom_frame.pack(pady=5, fill='x') Button(bottom_frame, text="运行", command=lambda: self._run_module(module)).pack(side='left', padx=5) Button(bottom_frame, text="清除", command=lambda: self._clear_module_data(module)).pack(side='left', padx=5) Button(bottom_frame, text="保存", command=lambda: self._save_module_data(module)).pack(side='left', padx=5) Button(bottom_frame, text="刷新", command=lambda: self._on_module_renovate(module)).pack(side='right', padx=5) def _create_ui_element(self, parent, label_text): """创建统一的UI元素(带右边距2px)""" frame = Frame(parent) frame.pack(fill='x', pady=2) # 标签固定宽度 Label(frame, text=label_text, width=12, anchor='w').pack(side='left') # 添加容器Frame实现右边距2px entry_container = Frame(frame) entry_container.pack(side='left', fill='x', expand=True, padx=(0, 2)) return entry_container def _create_input_analysis_content(self, parent: Frame): """创建输入分析模块的特定内容""" # 使用统一方法创建UI元素(带右边距2px) 这里修改 排除号码:(用户手动输入的号码) 前区: 后区: 推荐号码:(模块1收到主界面模块1传输过来“排除号码”的信息后,按照设计要求进行排除,生成推荐号码,在下面的对应的对话框里呈现出来,其号码池的前区和后区也要同步进行)) 前区: 后区: front_container = self._create_ui_element(parent, "前区号码 (1-35)😊 front_entry = Entry(front_container) front_entry.pack(fill=‘x’) back_container = self._create_ui_element(parent, "后区号码 (1-12):") back_entry = Entry(back_container) back_entry.pack(fill='x') # 结果显示区 result_frame = Frame(parent) result_frame.pack(fill='both', expand=True, pady=5) scrollbar = Scrollbar(result_frame) scrollbar.pack(side='right', fill='y') result_text = Text(result_frame, yscrollcommand=scrollbar.set, wrap='word') result_text.pack(fill='both', expand=True) scrollbar.config(command=result_text.yview) # 保存对控件的引用 self.front_entry = front_entry self.back_entry = back_entry self.result_text = result_text def _create_combination_analysis_content(self, parent: Frame): """创建组合分析模块的特定内容""" content_frame = Frame(parent) content_frame.pack(fill='both', expand=True, padx=10, pady=10) # 使用统一方法创建UI元素(带右边距2px)front_hot_container = self._create_ui_element(content_frame, "前区热号:") front_hot_entry = Entry(front_hot_container) front_hot_entry.pack(fill='x') front_freq_container = self._create_ui_element(content_frame, "前数字频:") front_freq_entry = Entry(front_freq_container) front_freq_entry.pack(fill='x') front_freq_rec_container = self._create_ui_element(content_frame, "前频繁推:") front_freq_rec_entry = Entry(front_freq_rec_container) front极_freq_rec_entry.pack(fill='x') back_hot_container = self._create_ui_element(content_frame, "后区热号:") back_hot_entry = Entry(back_hot_container) back_hot_entry.pack(fill='x') back_freq_container = self._create_ui_element(content_frame, "后数字频:") back_freq_entry = Entry(back_freq_container) back_freq_entry.pack(fill='x') back_infreq_rec_container = self._create_ui_element(content_frame, "后低频推:") back_infreq_rec_entry = Entry(back_infreq_rec_container) back_infreq_rec_entry.pack(fill='x') # 结果显示区 result_frame = Frame(content_frame) result_frame.pack(fill='both', expand=True) scrollbar = Scrollbar(result_frame) scrollbar.pack(side='right', fill='y') result_text = Text(result_frame, yscrollcommand=scrollbar.set, wrap='word') result_text.pack(fill='both', expand=True) scrollbar.config(command=result_text.yview) # 保存对控件的引用 self.front_hot_entry = front_hot_entry self.front_freq_entry = front_freq_entry self.front_freq_rec_entry = front_freq_rec_entry self.back_hot_entry = back_hot_entry self.back_freq_entry = back_freq_entry self.back_infreq_rec_entry = back_infreq_rec_entry self.result_text = result_text def _create_follow_analysis_content(self, parent: Frame): """创建跟随分析模块的特定内容""" content_frame = Frame(parent) content_frame.pack(fill='both', expand=True, padx=10, pady=10) # 使用统一方法创建UI元素(带右边距2px)front_more_container = self._create_ui_element(content_frame, "前推荐多:") front_more_entry = Entry(front_more_container) front_more_entry.pack(fill='x') front_less_container = self._create_ui_element(content_frame, "前推荐少:") front_less_entry = Entry(front_less_container) front_less_entry.pack(fill='x') back_more_container = self._create_ui_element(content_frame, "后推荐多:") back_more_entry = Entry(back_more_container) back_more_entry.pack(fill='x') back_less_container = self._create_ui_element(content_frame, "后推荐少:") back_less_entry = Entry(back_less_container) back_less_entry.pack(fill='x') # 结果显示区 result_frame = Frame(content_frame) result_frame.pack(fill='both', expand=True) scrollbar = Scrollbar(result_frame) scrollbar.pack(side='right', fill='y') result_text = Text(result_frame, yscrollcommand=scrollbar.set, wrap='word') result_text.pack(fill='both', expand=True) scrollbar.config(command=result_text.yview) # 保存对控件的引用 self.front_more_entry = front_more_entry self.front_less_entry = front_less_entry self.back_more_entry = back_more_entry self.back_less_entry = back_less_entry self.result_text = result_text def _create_trend_analysis_content(self, parent: Frame): """创建趋势分析模块的特定内容""" content_frame = Frame(parent) content_frame.pack(fill='both', expand=True, padx=10, pady=10) # 使用统一方法创建UI元素(带右边距2px)sum_value_container = self._create_ui_element(content_frame, "和值:") sum_value_entry = Entry(sum_value_container) sum_value_entry.pack(fill='x') prime_ratio_container = self._create_ui_element(content_frame, "质合比:") prime_ratio_entry = Entry(prime_ratio_container) prime_ratio_entry.pack(fill='x') odd_even_ratio_container = self._create_ui_element(content_frame, "奇偶比:") odd_even_ratio_entry = Entry(odd_even_ratio_container) odd_even_ratio_entry.pack(fill='x') zone_rec_container = self._create_ui_element(content_frame, "断区推荐:") zone_rec_entry = Entry(zone_rec_container) zone_rec_entry.pack(fill='x') consec_rec_container = self._create_ui_element(content_frame, "连号推荐:") consec_rec_entry = Entry(consec_rec_container) consec_rec_entry.pack(fill='x') hot_cold_rec_container = self._create_ui_element(content_frame, "冷热推荐:") hot_cold_rec_entry = Entry(hot_cold_rec_container) hot_cold_rec_entry.pack(fill='x') hot_rec_container = self._create_ui_element(content_frame, "后区热号:") hot_rec_entry = Entry(hot_rec_container) hot_rec_entry.pack(fill='x') cold_rec_container = self._create_ui_element(content_frame, "后区冷号:") cold_rec_entry = Entry(cold_rec_container) cold_rec_entry.pack(fill='x') trend_rec_container = self._create_ui_element(content_frame, "趋势号:") trend_rec_entry = Entry(trend_rec_container) trend_rec_entry.pack(fill='x') # 结果显示区 result_frame = Frame(content_frame) result_frame.pack(fill='both', expand=True) scrollbar = Scrollbar(result_frame) scrollbar.pack(side='right', fill='y') result_text = Text(result_frame, yscrollcommand=scrollbar.set, wrap='word') result_text.pack(fill='both', expand=True) scrollbar.config(command=result_text.yview) # 保存对控件的引用 self.sum_value_entry = sum_value_entry self.prime_ratio_entry = prime_ratio_entry self.odd_even_ratio_entry = odd_even_ratio_entry self.zone_rec_entry = zone_rec_entry self.consec_rec_entry = consec_rec_entry self.hot_cold_rec_entry = hot_cold_rec_entry # 修复变量名拼写错误 self.hot_rec_entry = hot_rec_entry self.cold_rec_entry = cold_rec_entry self.trend_rec_entry = trend_rec_entry self.result_text = result_text def _create_number_generation_content(self, parent: Frame): """创建数字生成模块的特定内容""" content_frame = Frame(parent) content_frame.pack(fill='both', expand=True, padx=10, pady=10) # 胆码输入区 dan_frame = Frame(content_frame) dan_frame.pack(fill='x', pady=5) front_dan_container = self._create_ui_element(dan_frame, "前区胆码:") front_dan_entry = Entry(front_dan_container) front_dan_entry.pack(fill='x') back_dan_container = self._create_ui_element(dan_frame, "后区胆码:") back_dan_entry = Entry(back_dan_container) back_dan_entry.pack(fill='x') # 结果显示区 result_frame = Frame(content_frame) result_frame.pack(fill='both', expand=True) scrollbar = Scrollbar(result_frame) scrollbar.pack(side='right', fill='y') result_text = Text(result_frame, yscrollcommand=scrollbar.set, wrap='word') result_text.pack(fill='both', expand=True) scrollbar.config(command=result_text.yview) # 保存对控件的引用 self.front_dan_entry = front_dan_entry self.back_dan_entry = back_dan_entry self.result_text = result_text def _run_module(self, dialog_type: str): """运行模块""" run_event = Event( event_id=int(time.time()), type=EventType.MODULE_RUN, source='dialog_manager', target=dialog_type ) event_center.publish(run_event) def _clear_module_data(self, module: str): """清除模块数据""" if module == "input_analysis": self.front_entry.delete(0, 'end') self.back_entry.delete(0, 'end') self.result_text.delete(1.0, 'end') elif module == "combination_analysis": self.front_hot_entry.delete(0, 'end') self.front_freq_entry.delete(0, 'end') self.front_freq_rec_entry.delete(0, 'end') self.back_hot_entry.delete(0, 'end') self.back_freq_entry.delete(0, 'end') self.back_infreq_rec_entry.delete(0, 'end') self.result_text.delete(1.0, 'end') # 其他模块清除逻辑类似... def _save_module_data(self, module: str): """保存模块数据""" try: data = {} if module == "input_analysis": data['front'] = self.front_entry.get() data['back'] = self.back_entry.get() data['result'] = self.result_text.get(1.0, 'end') elif module == "combination_analysis": data['front_hot'] = self.front_hot_entry.get() data['front_freq'] = self.front_freq_entry.get() data['front_freq_rec'] = self.front_freq_rec_entry.get() data['back_hot'] = self.back_hot_entry.get() data['back_freq'] = self.back_freq_entry.get() data['back_infreq_rec'] = self.back_infreq_rec_entry.get() data['result'] = self.result_text.get(1.0, 'end') # 其他模块数据收集... filename = f"{module}_data.json" with open(filename, 'w', encoding='utf-8') as f: json.dump(data, f, indent=2, ensure_ascii=False) messagebox.showinfo("保存成功", f"数据已保存到{filename}") except Exception as e: messagebox.showerror("保存失败", str(e)) logging.error(f"保存数据失败: {str(e)}", exc_info=True) def _handle_module_complete(self, event: Event): self.status_var.set(f"{event.source} 模块运行完成") if hasattr(self, 'dynamic_text') and self.dynamic_text: self.dynamic_text.insert('end', f"\n{event.source} 模块已完成分析\n") def _run_module(self): """运行动态区模块""" if hasattr(self, 'current_module') and self.current_module: run_event = Event( event_id=int(time.time()), type=EventType.MODULE_RUN, source='main_ui', target=self.current_module ) event_center.publish(run_event) else: messagebox.showinfo("提示", "请先打开一个模块") def _clear_dynamic_content(self): """清除动态区内容""" if hasattr(self, 'dynamic_text') and self.dynamic_text: self.dynamic_text.delete(1.0, 'end') def _save_dynamic_content(self): """保存动态区内容""" if hasattr(self, 'dynamic_text') and self.dynamic_text: content = self.dynamic_text.get(1.0, 'end') try: with open("dynamic_content.txt", "w", encoding="utf-8") as f: f.write(content) messagebox.showinfo("保存成功", "动态区内容已保存到dynamic_content.txt") except Exception as e: messagebox.showerror("保存失败", str(e)) def _refresh_dynamic(self): """刷新动态区""" if self.current_module: self._on_module_button_click(self.current_module) # 添加动态内容创建方法 def _create_input_analysis_content(self): """创建输入分析模块的动态内容""" 这里修改 排除号码:(用户手动输入的号码) 前区: 后区: 推荐号码:(模块1收到主界面模块1传输过来“排除号码”的信息后,按照设计要求进行排除,生成推荐号码,在下面的对应的对话框里呈现出来,其号码池的前区和后区也要同步进行)) 前区: 后区: self.dynamic_content = Frame(self.module_content_frame) self.dynamic_content.pack(fill=‘both’, expand=True) # 前区号码输入 front_frame = Frame(self.dynamic_content) front_frame.pack(fill='x', pady=5) Label(front_frame, text="前区号码 (1-35):").pack(side='left') self.front_entry = Entry(front_frame, width=30) self.front_entry.pack(side='left', padx=5) # 后区号码输入 back_frame = Frame(self.dynamic_content) back_frame.pack(fill='x', pady=5) Label(back_frame, text="后区号码 (1-12):").pack(side='left') self.back_entry = Entry(back_frame, width=30) self.back_entry.pack(side='left', padx=5) # 结果显示区 result_frame = Frame(self.dynamic_content) result_frame.pack(fill='both', expand=True) scrollbar = Scrollbar(result_frame) scrollbar.pack(side='right', fill='y') self.dynamic_text = Text(result_frame, yscrollcommand=scrollbar.set, wrap='word') self.dynamic_text.pack(fill='both', expand=True) scrollbar.config(command=self.dynamic_text.yview) def _create_combination_analysis_content(self): """创建组合分析模块的动态内容""" self.dynamic_content = Frame(self.module_content_frame) self.dynamic_content.pack(fill='both', expand=True) # 组合分析内容 labels = [ "前数字频:", "前数字缺:", "后数字频:", "后数字缺:", "前频繁推:", "后低频推:", "生组合数:", "未组合码:" ] for label in labels: frame = Frame(self.dynamic_content) frame.pack(fill='x', pady=2) Label(frame, text=label, width=12, anchor='w').pack(side='left') entry = Entry(frame, width=30) entry.pack(side='left', padx=5) setattr(self, f"{label.replace(':', '')}_entry", entry) # 结果显示区 result_frame = Frame(self.dynamic_content) result_frame.pack(fill='both', expand=True) scrollbar = Scrollbar(result_frame) scrollbar.pack(side='right', fill='y') self.dynamic_text = Text(result_frame, yscrollcommand=scrollbar.set, wrap='word') self.dynamic_text.pack(fill='both', expand=True) scrollbar.config(command=self.dynamic_text.yview) def _create_follow_analysis_content(self): """创建跟随分析模块的动态内容""" self.dynamic_content = Frame(self.module_content_frame) self.dynamic_content.pack(fill='both', expand=True) # 跟随分析内容 labels = [ "前推荐多:", "前推荐少:", "后推荐多:", "后推荐少:" ] for label in labels: frame = Frame(self.dynamic_content) frame.pack(fill='x', pady=2) Label(frame, text=label, width=12, anchor='w').pack(side='left') entry = Entry(frame, width=30) entry.pack(side='left', padx=5) setattr(self, f"{label.replace(':', '')}_entry", entry) # 结果显示区 result_frame = Frame(self.dynamic_content) result_frame.pack(fill='both', expand=True) scrollbar = Scrollbar(result_frame) scrollbar.pack(side='right', fill='y') self.dynamic_text = Text(result_frame, yscrollcommand=scrollbar.set, wrap='word') self.dynamic_text.pack(fill='both', expand=True) scrollbar.config(command=self.dynamic_text.yview) def _create_trend_analysis_content(self): """创建趋势分析模块的动态内容""" self.dynamic_content = Frame(self.module_content_frame) self.dynamic_content.pack(fill='both', expand=True) # 趋势分析内容 labels = [ "和值:", "质合比:", "奇偶比:", "断区推荐:", "连号推荐:", "冷热推荐:", "后区热号:", "后区冷号:", "趋势号:" ] for label in labels: frame = Frame(self.dynamic_content) frame.pack(fill='x', pady=2) Label(frame, text=label, width=12, anchor='w').pack(side='left') entry = Entry(frame, width=30) entry.pack(side='left', padx=5) setattr(self, f"{label.replace(':', '')}_entry", entry) # 结果显示区 result_frame = Frame(self.dynamic_content) result_frame.pack(fill='both', expand=True) scrollbar = Scrollbar(result_frame) scrollbar.pack(side='right', fill='y') self.dynamic_text = Text(result_frame, yscrollcommand=scrollbar.set, wrap='word') self.dynamic_text.pack(fill='both', expand=True) scrollbar.config(command=self.dynamic_text.yview) def _create_number_generation_content(self): """创建数字生成模块的动态内容""" self.dynamic_content = Frame(self.module_content_frame) self.dynamic_content.pack(fill='both', expand=True) # 数字生成内容 # 胆码输入区 dan_frame = Frame(self.dynamic_content) dan_frame.pack(fill='x', pady=5) Label(dan_frame, text="前区胆码:").pack(side='left') self.front_dan_entry = Entry(dan_frame, width=15) self.front_dan_entry.pack(side='left', padx=5) Label(dan_frame, text="后区胆码:").pack(side='left') self.back_dan_entry = Entry(dan_frame, width=15) self.back_dan_entry.pack(side='left', padx=5) # 结果显示区 result_frame = Frame(self.dynamic_content) result_frame.pack(fill='both', expand=True) scrollbar = Scrollbar(result_frame) scrollbar.pack(side='right', fill='y') self.dynamic_text = Text(result_frame, yscrollcommand=scrollbar.set, wrap='word') self.dynamic_text.pack(fill='both', expand=True) scrollbar.config(command=self.dynamic_text.yview) # 添加事件处理方法 def _handle_ui_update(self, event: Event): """处理UI更新事件""" if not event.data or 'update_type' not in event.data: return update_type = event.data['update_type'] data = event.data.get('data', {}) # 处理核心变量更新 if update_type == 'organized_data': # 确保所有核心变量已初始化 if not hasattr(self, 'core_vars'): self.core_vars = { 'front_area': StringVar(), 'back_area': StringVar(), 'front_hot': StringVar(), 'front_cold': StringVar(), 'back_hot': StringVar(), 'back_cold': StringVar() } # 更新界面变量 self.core_vars['front_area'].set(str(data.get('front_numbers', []))) self.core_vars['back_area'].set(str(data.get('back_numbers', []))) self.core_vars['front_hot'].set(str(data.get('front_hot', []))) self.core_vars['front_cold'].set(str(data.get('front_cold', []))) self.core_vars['back_hot'].set(str(data.get('back_hot', []))) self.core_vars['back_cold'].set(str(data.get('back_cold', [])))
最新发布
07-15
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值