重新修改,生成完整代码要求:结合用户的思路,进行改错,不要任意删除代码,只针对问题进行修改,生成完整代码。。问题 已重新声明上文定义的无用法的 'app'已重新声明上文定义的无用法的 '_handle_module_complete'已重新声明上文定义的无用法的 '_handle_exclude_numbers'已重新声明上文定义的无用法的 '_setup_ui'在 'EventType | EventType | EventType' 中找不到引用 'ORGANIZE_DATA'在 'EventType | EventType | EventType' 中找不到引用 'FREEZE_DATA'局部变量 'exclude_front' 可能在赋值前引用局部变量 'exclude_back' 可能在赋值前引用在 'GlobalConfig | GlobalConfig | GlobalConfig | GlobalConfig' 中找不到引用 'UI_CONFIG'在 'GlobalConfig | GlobalConfig | GlobalConfig | GlobalConfig' 中找不到引用 'MODULE1_ID'已重新声明上文定义的无用法的 '_handle_analysis_result'在 'GlobalConfig | GlobalConfig | GlobalConfig | GlobalConfig' 中找不到引用 'MODULE3_ID'在 'GlobalConfig | GlobalConfig | GlobalConfig | GlobalConfig' 中找不到引用 'MODULE3_ID'已重新声明上文定义的无用法的 '_run_module'局部变量 'exclude_front' 可能在赋值前引用局部变量 'exclude_back' 可能在赋值前引用类 'MainInterface' 的未解析的特性引用 '_update_pool_with_recommendations'在 'GlobalConfig | GlobalConfig | GlobalConfig | GlobalConfig' 中找不到引用 'MODULE1_ID'已重新声明上文定义的无用法的 '_handle_ui_update' # ==================== 主界面修改 ====================
class DialogManager:
def __init__(self):
self.active_dialogs = {} # 保存所有激活的对话框实例
import tkinter as tk
from tkinter import Tk, StringVar
from typing import Optional, Union, Any
from event_center import Event, EventType, event_center
from global_config import GlobalConfig
from dataclasses import dataclass
@dataclass
class DialogManager:
active_dialogs: dict = None
class AppContext:
def __init__(self):
self.dialog_manager = DialogManager()
self.main_ui = None
app = AppContext()
class MainInterface:
def __init__(self, root: Tk, pool: 'NumberPool'):
self.root = root
self.pool = pool
self.left_panel = None
self.center_paned = None
self.right_panel = None
self.core_vars = {}
self.pool_vars = {}
self.status_var = StringVar()
self.dynamic_text: Optional[tk.Text] = None
self.current_module: Optional[str] = None
self._setup_ui()
self._setup_event_handlers()
self.module_instances = {}
# 初始化控件列表
self.exclude_front_entries: list[tk.Entry] = []
self.exclude_back_entries: list[tk.Entry] = []
self.front_dan_entries: list[tk.Entry] = []
self.back_dan_entries: list[tk.Entry] = []
# 初始化结果文本控件
self.result_text: Optional[tk.Text] = None
# 初始化变量
self.exclude_front_var = StringVar()
self.exclude_back_var = StringVar()
self.recommend_front_var = StringVar()
self.recommend_back_var = StringVar()
# 初始化框架
self.dynamic_content: Optional[tk.Frame] = None
self.module_content_frame: Optional[tk.Frame] = None
# 初始化推荐控件
self.front_recommend_less = tk.Entry(self.root)
self.back_recommend_more = tk.Entry(self.root)
self.back_recommend_less = tk.Entry(self.root)
# 趋势分析控件
self.he_zhi_entry = tk.Entry(self.root)
self.zhi_he_bi_entry = tk.Entry(self.root)
self.ji_ou_bi_entry = tk.Entry(self.root)
self.duan_qu_entry = tk.Entry(self.root)
self.lian_hao_entry = tk.Entry(self.root)
self.len_gre_entry = tk.Entry(self.root)
self.hou_qu_re_hao_entry = tk.Entry(self.root)
self.hou_qu_len_hao_entry = tk.Entry(self.root)
self.qu_shi_entry = tk.Entry(self.root)
# 数字生成控件
self.dan_ma_entry = tk.Entry(self.root)
self.front_numbers_entry = tk.Entry(self.root)
self.back_numbers_entry = tk.Entry(self.root)
self.recommend_1 = tk.Entry(self.root)
self.recommend_2 = tk.Entry(self.root)
self.recommend_3 = tk.Entry(self.root)
self.recommend_4 = tk.Entry(self.root)
self.recommend_5 = tk.Entry(self.root)
# 模块ID映射
self.module_ids = {
'input_analysis': getattr(GlobalConfig, 'MODULE1_ID', 'input_analysis'),
'combination_analysis': getattr(GlobalConfig, 'MODULE2_ID', 'combination_analysis'),
'follow_analysis': getattr(GlobalConfig, 'MODULE3_ID', 'follow_analysis'),
'trend_analysis': getattr(GlobalConfig, 'MODULE4_ID', 'trend_analysis'),
'number_generation': getattr(GlobalConfig, 'MODULE5_ID', 'number_generation'),
}
# 模块标签定义
self.labels = {
'input_analysis': [
"排除号码:", "前区:", "后区:", "推荐号码:", "前区:", "后区:",
],
'combination_analysis': [
"前数字频:", "前数字缺:", "后数字频:", "后数字缺:",
"前频繁推:", "后低频推:", "生组合数:", "未组合码:"
],
'follow_analysis': [
"前推荐多:", "前推荐少:", "后推荐多:", "后推荐少:"
],
'trend_analysis': [
"和值:", "质合比:", "奇偶比:", "断区推荐:", "连号推荐:",
"冷热推荐:", "后区热号:", "后区冷号:", "趋势号:"
],
'number_generation': [
"胆码:", "前区:", "后区:", "推荐5注号码:",
"1:", "", "2:", "", "3:", "", "4:", "", "5:", ""
],
}
# 初始化条目引用
self.front_dan_entry: Optional[tk.Entry] = None
self.back_dan_entry: Optional[tk.Entry] = None
self.exclude_front_entry: Optional[tk.Entry] = None
self.exclude_back_entry: Optional[tk.Entry] = None
self.front_entry: Optional[tk.Entry] = None
self.back_entry: Optional[tk.Entry] = None
# 初始化 dialog_manager
app.dialog_manager = DialogManager()
app.main_ui = self
self.root.deiconify()
def _setup_ui(self):
"""设置界面布局"""
pass # 实际的UI设置代码
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)
event_center.subscribe(EventType.EXCLUDE_NUMBERS, self._handle_exclude_numbers)
event_center.subscribe(EventType.ANALYSIS_RESULT, self._handle_analysis_result)
# 添加缺失的事件处理器
event_center.subscribe("combination_analysis", self._handle_combination_event)
event_center.subscribe("follow_analysis", self._handle_follow_event)
event_center.subscribe("trend_analysis", self._handle_trend_event)
event_center.subscribe("number_generation", self._handle_number_generation_event)
def _handle_module_complete(self, event: Event):
"""处理模块完成事件"""
pass # 实际的处理代码
def _handle_ui_update(self, event: Event):
"""处理UI更新事件"""
pass # 实际的处理代码
def _handle_exclude_numbers(self, event: Event):
"""处理排除号码事件"""
pass # 实际的处理代码
def _handle_analysis_result(self, event: Event):
"""处理分析结果事件"""
pass # 实际的处理代码
def _handle_combination_event(self, event: Event):
"""处理组合分析事件"""
pass # 实际的处理代码
def _handle_follow_event(self, event: Event):
"""处理跟随分析事件"""
pass # 实际的处理代码
def _handle_trend_event(self, event: Event):
"""处理趋势分析事件"""
pass # 实际的处理代码
def _handle_number_generation_event(self, event: Event):
"""处理数字生成事件"""
pass # 实际的处理代码
def _handle_module_complete(self, event: Event):
"""处理模块完成事件"""
self.status_var.set(f"{event.source} 模块运行完成")
if event.source == "input_analysis" and hasattr(self, 'result_text') and self.result_text:
# 更新推荐号码显示
if 'recommend_front' in event.data:
self.recommend_front_var.set(event.data['recommend_front'])
if 'recommend_back' in event.data:
self.recommend_back_var.set(event.data['recommend_back'])
# 在结果文本中记录
self.result_text.insert('end', f"\n{event.source} 模块已完成分析\n")
self.result_text.insert('end',
f"推荐号码: 前区 {self.recommend_front_var.get()}, 后区 {self.recommend_back_var.get()}\n")
# 同步更新号码池
update_event = Event(
event_id=int(time.time()),
type=EventType.POOL_UPDATE,
source='input_analysis',
target='pool',
data={
'front_numbers': self.recommend_front_var.get(),
'back_numbers': self.recommend_back_var.get()
}
)
event_center.publish(update_event)
self.result_text.insert('end', "号码池已同步更新\n")
def _handle_exclude_numbers(self, event: Event):
"""处理排除号码更新事件"""
self.status_var.set(f"{event.source} 模块更新排除号码")
# 更新前区排除号码显示
if 'exclude_front' in event.data and hasattr(self, 'exclude_front_entries'):
for i, entry in enumerate(self.exclude_front_entries):
if i < len(event.data['exclude_front']):
entry.delete(0, 'end')
entry.insert(0, str(event.data['exclude_front'][i]))
# 更新后区排除号码显示
if 'exclude_back' in event.data and hasattr(self, 'exclude_back_entries'):
for i, entry in enumerate(self.exclude_back_entries):
if i < len(event.data['exclude_back']):
entry.delete(0, 'end')
entry.insert(0, str(event.data['exclude_back'][i]))
# 在结果区域记录
if hasattr(self, 'result_text'):
self.result_text.insert('end',
f"\n收到排除号码更新: 前区{event.data.get('exclude_front', [])}, 后区{event.data.get('exclude_back', [])}\n")
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)
# 主容器 - 三栏布局 (修复点:使用 'horizontal' 替代 HORIZONTAL)
main_container = PanedWindow(self.root, orient='horizontal', sashrelief=RAISED, sashwidth=5)
main_container.pack(fill='both', expand=True, padx=5, pady=(0, 5))
# 左侧面板
self.left_panel = Frame(main_container, width=200, bg="#eaeaea")
main_container.add(self.left_panel, minsize=150, stretch="never")
# 中间内容区
self.center_paned = PanedWindow(main_container, orient=VERTICAL, sashrelief=RAISED, sashwidth=5)
main_container.add(self.center_paned, minsize=500, stretch="always")
# 右侧面板
self.right_panel = Frame(main_container, width=700, bg="#f5f5f5")
main_container.add(self.right_panel, minsize=250, stretch="never")
# 初始化各区域
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):
"""设置中间区域布局,分为上下两部分"""
# 上半部分 - 核心区 (固定高度)
self.core_frame = Frame(self.center_paned, bd=1, relief='solid')
self.center_paned.add(self.core_frame, minsize=150, stretch="never")
# 核心区内容
Label(self.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(self.core_frame)
frame.pack(fill='x', padx=5, pady=2)
Label(frame, text=label, width=10, anchor='w').pack(side='left')
entry_container = Frame(frame)
entry_container.pack(side='left', fill='x', expand=True)
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)
# 下半部分 - 动态区
self.dynamic_frame = Frame(self.center_paned, bd=1, relief='solid')
self.center_paned.add(self.dynamic_frame, minsize=200, stretch="always")
# 主容器使用Grid布局
self.dynamic_container = Frame(self.dynamic_frame)
self.dynamic_container.pack(fill='both', expand=True)
self.dynamic_container.grid_rowconfigure(0, weight=1)
self.dynamic_container.grid_columnconfigure(0, weight=1)
# 操作按钮放在右下角
self.btn_frame = Frame(self.dynamic_container)
self.btn_frame.grid(row=1, column=0, sticky='se', pady=5, padx=5)
Button(self.btn_frame, text="运行", width=8, command=self._run_current_module).pack(side='left', padx=2)
Button(self.btn_frame, text="清除", width=8, command=self._clear_dynamic_content).pack(side='left', padx=2)
Button(self.btn_frame, text="保存", width=8, command=self._save_dynamic_content).pack(side='left', padx=2)
Button(self.btn_frame, text="刷新", width=8, command=self._refresh_dynamic).pack(side='left', padx=2)
# 模块内容容器 - 确保先创建
self.module_content_frame = Frame(self.dynamic_container)
self.module_content_frame.grid(row=0, column=0, sticky='nsew')
# 初始化默认内容
self._init_default_dynamic_content()
def _init_default_dynamic_content(self):
"""初始化默认动态区内容"""
# 清除现有内容
for widget in self.module_content_frame.winfo_children():
widget.destroy()
# 创建新内容
self.dynamic_content = Frame(self.module_content_frame)
self.dynamic_content.pack(fill='both', expand=True)
Label(self.dynamic_content,
text="请从左侧选择分析模块",
font=('微软雅黑', 12)).pack(expand=True, pady=50)
def _on_module_button_click(self, module: str):
"""模块按钮点击事件处理"""
self.status_var.set(f"打开 {module} 模块...")
self.current_module = module
# 确保 module_content_frame 存在且可操作
if not hasattr(self, 'module_content_frame') or self.module_content_frame is None:
self.module_content_frame = Frame(self.dynamic_container)
self.module_content_frame.grid(row=0, column=0, sticky='nsew')
self._init_default_dynamic_content()
logging.warning("module_content_frame 已紧急初始化")
try:
# 1️⃣ 彻底清除旧内容(包括残留按钮)
for widget in self.module_content_frame.winfo_children():
widget.destroy()
self.module_content_frame.update_idletasks() # 强制更新布局
# 2️⃣ 创建新内容容器
content_frame = Frame(self.module_content_frame)
content_frame.pack(fill='both', expand=True)
# 3️⃣ 根据模块类型创建具体内容
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)
# 4️⃣ 创建按钮容器(带唯一标识)
# 先销毁已存在的按钮容器(严格检查类型和标记)
for widget in self.module_content_frame.winfo_children():
if isinstance(widget, Frame) and hasattr(widget, 'is_button_container'):
widget.destroy()
# 创建新按钮容器并标记
btn_frame = Frame(self.module_content_frame)
btn_frame.is_button_container = True # 标记为按钮容器
btn_frame.pack(side='bottom', fill='x', pady=5)
btn_frame.pack_propagate(False) # 防止内部组件影响容器大小
# 按钮容器内部布局
btn_container = Frame(btn_frame)
btn_container.pack(side='right')
# 创建按钮(使用lambda时绑定当前模块状态)
Button(btn_container, text="运行", width=8,
command=lambda m=module: self._run_module(m)).pack(side='left', padx=2)
Button(btn_container, text="清除", width=8,
command=lambda m=module: self._clear_module_data(m)).pack(side='left', padx=2)
Button(btn_container, text="保存", width=8,
command=lambda m=module: self._save_module_data(m)).pack(side='left', padx=2)
Button(btn_container, text="刷新", width=8,
command=lambda m=module: self._on_module_button_click(m)).pack(side='left', padx=2)
except Exception as e:
# 5️⃣ 严重异常处理(强制重建界面)
logging.critical(f"模块切换异常: {str(e)}", exc_info=True)
if hasattr(self, 'module_content_frame'):
self.module_content_frame.destroy()
self.module_content_frame = Frame(self.dynamic_container)
self.module_content_frame.grid(row=0, column=0, sticky='nsew')
self._init_default_dynamic_content()
def _run_current_module(self):
"""运行当前模块"""
if self.current_module:
self._run_module(self.current_module)
def _clear_dynamic_content(self):
"""清除动态区内容"""
if self.current_module:
self._clear_module_data(self.current_module)
# 额外确保清除结果文本框(如果存在)
if hasattr(self, 'result_text') and self.result_text:
self.result_text.delete(1.0, 'end')
def _save_dynamic_content(self):
"""保存动态区内容"""
if self.current_module:
self._save_module_data(self.current_module)
else:
messagebox.showinfo("提示", "请先选择并运行一个模块")
def _refresh_dynamic(self):
"""刷新动态区内容"""
if self.current_module:
self._on_module_button_click(self.current_module)
else:
messagebox.showinfo("提示", "请先选择一个模块")
def _organize_data(self):
"""整理号码池数据"""
try:
# 发布整理事件
event = Event(
event_id=int(time.time()),
type=EventType.ORGANIZE_DATA,
source='main_ui',
target='pool'
)
event_center.publish(event)
self.status_var.set("号码池数据已整理")
except Exception as e:
messagebox.showerror("整理失败", str(e))
logging.error(f"整理数据失败: {str(e)}", exc_info=True)
def _freeze_data(self):
"""冻结号码池数据"""
try:
# 发布冻结事件
event = Event(
event_id=int(time.time()),
type=EventType.FREEZE_DATA,
source='main_ui',
target='pool'
)
event_center.publish(event)
self.status_var.set("号码池数据已冻结")
except Exception as e:
messagebox.showerror("冻结失败", str(e))
logging.error(f"冻结数据失败: {str(e)}", exc_info=True)
def _run_module(self, module: str):
"""运行指定模块"""
if module == "input_analysis":
# 获取排除号码
exclude_front = self.exclude_front_entry.get()
exclude_back = self.exclude_back_entry.get()
# 发布排除号码事件
exclude_event = Event(
event_id=int(time.time()),
type=EventType.EXCLUDE_NUMBERS,
source='main_ui',
target='pool',
data={
'exclude_front': exclude_front,
'exclude_back': exclude_back
}
)
event_center.publish(exclude_event)
# 在结果文本中记录
self.result_text.insert('end', f"已设置排除号码: 前区 {exclude_front}, 后区 {exclude_back}\n")
run_event = Event(
event_id=int(time.time()),
type=EventType.MODULE_RUN,
source='main_ui',
target=module, # 确保 target 是当前模块名
data={
'exclude_front': exclude_front,
'exclude_back': exclude_back
}
)
event_center.publish(run_event)
def _create_ui_element(self, parent, label_text):
"""创建统一的UI元素(与核心区对齐)"""
frame = Frame(parent)
frame.pack(fill='x', pady=2)
# 标签固定宽度与核心区对齐
Label(frame, text=label_text, width=10, anchor='w').pack(side='left')
# 条目容器 - 宽度与核心区对齐
entry_container = Frame(frame)
entry_container.pack(side='left', fill='x', expand=True)
return entry_container
def _setup_right_panel(self):
"""设置右侧号码池布局"""
# 号码池标题
pool_title_frame = Frame(self.right_panel)
pool_title_frame.pack(fill='x', pady=5)
Label(pool_title_frame, text="号码池", font=('微软雅黑', 12, 'bold')).pack(anchor='w')
# 号码池内容区(添加边框和2px内边距)
pool_content = Frame(self.right_panel, bd=1, relief='solid', padx=2, pady=2)
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)
# 号码池项目 - 优化布局和样式(带2px右边距)
for label, var_name, row_id in GlobalConfig.UI_CONFIG:
frame = Frame(scrollable_frame)
frame.grid(row=row_id, column=0, sticky='ew', padx=0, pady=1) # 移除水平padding
# 左侧标签(固定宽度为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 _validate_number(self, text: str, min_val: int, max_val: int) -> bool:
"""验证输入的数字是否在指定范围内"""
if text == "":
return True # 允许空输入(删除操作)
if not text.isdigit():
return False
num = int(text)
return min_val <= num <= max_val
def _create_input_analysis_content(self, parent: Frame):
"""创建输入分析模块内容 - 增加模块ID标识"""
# 主容器使用Grid布局
main_frame = Frame(parent)
main_frame.pack(fill='both', expand=True)
# 添加模块ID标识(右上角)
module_id_label = Label(main_frame, text=f"模块ID: {GlobalConfig.MODULE1_ID}",
font=('微软雅黑', 8), fg='gray')
module_id_label.pack(anchor='ne', padx=10, pady=5)
# === 排除号码区 ===
exclude_frame = LabelFrame(main_frame, text=" 排除号码 ", font=('微软雅黑', 12, 'bold'))
exclude_frame.pack(fill='x', padx=20, pady=10, ipady=5)
# 使用预定义的标签文本
labels = self.labels['input_analysis']
# 排除号码标签
Label(exclude_frame, text=labels[0], font=('微软雅黑', 10, 'bold')).pack(anchor='w', padx=10, pady=(5, 0))
# 前区排除
Label(exclude_frame, text=labels[1], font=('微软雅黑', 10)).pack(anchor='w', padx=10, pady=5)
front_entries_frame = Frame(exclude_frame)
front_entries_frame.pack(fill='x', padx=10, pady=5)
self.exclude_front_entries = []
for i in range(10): # 10个前区输入框
entry_frame = Frame(front_entries_frame)
entry_frame.pack(side='left', padx=2)
Label(entry_frame, text=f"{i + 1}:").pack(side='left')
entry = Entry(entry_frame, width=3, font=('微软雅黑', 10))
entry.pack(side='left')
# 添加验证函数 - 前区限制1-35
entry.config(validate="key", validatecommand=(
entry.register(lambda text: self._validate_number(text, 1, 35)), '%P'))
entry.bind("<KeyRelease>", self._auto_format_entry)
entry.bind("<Left>", lambda e, d=-1: self._navigate_entry(e, d))
entry.bind("<Right>", lambda e, d=1: self._navigate_entry(e, d))
self.exclude_front_entries.append(entry)
# 后区排除
Label(exclude_frame, text=labels[2], font=('微软雅黑', 10)).pack(anchor='w', padx=10, pady=(10, 5))
back_entries_frame = Frame(exclude_frame)
back_entries_frame.pack(fill='x', padx=10, pady=5)
self.exclude_back_entries = []
for i in range(10): # 10个后区输入框
entry_frame = Frame(back_entries_frame)
entry_frame.pack(side='left', padx=2)
Label(entry_frame, text=f"{i + 1}:").pack(side='left')
entry = Entry(entry_frame, width=3, font=('微软雅黑', 10))
entry.pack(side='left')
# 添加验证函数 - 后区限制1-12
entry.config(validate="key", validatecommand=(
entry.register(lambda text: self._validate_number(text, 1, 12)), '%P'))
entry.bind("<KeyRelease>", self._auto_format_entry)
entry.bind("<Left>", lambda e, d=-1: self._navigate_entry(e, d))
entry.bind("<Right>", lambda e, d=1: self._navigate_entry(e, d))
self.exclude_back_entries.append(entry)
# 加载保存的数据 - 确保正确处理数据格式
if os.path.exists(GlobalConfig.MODULE1_SAVE_PATH):
try:
with open(GlobalConfig.MODULE1_SAVE_PATH, 'r', encoding='utf-8') as f:
saved_data = json.load(f)
# 恢复前区排除号码 - 确保正确处理空值和格式
if 'exclude_front' in saved_data:
for i, num in enumerate(saved_data['exclude_front']):
if i < len(self.exclude_front_entries) and num: # 确保有值
try:
formatted_num = f"{int(num):02d}" # 确保两位数格式
self.exclude_front_entries[i].delete(0, 'end')
self.exclude_front_entries[i].insert(0, formatted_num)
except ValueError:
continue # 跳过无效数字
# 恢复后区排除号码 - 确保正确处理空值和格式
if 'exclude_back' in saved_data:
for i, num in enumerate(saved_data['exclude_back']):
if i < len(self.exclude_back_entries) and num: # 确保有值
try:
formatted_num = f"{int(num):02d}" # 确保两位数格式
self.exclude_back_entries[i].delete(0, 'end')
self.exclude_back_entries[i].insert(0, formatted_num)
except ValueError:
continue # 跳过无效数字
except Exception as e:
logging.error(f"加载保存数据失败: {str(e)}")
messagebox.showerror("加载失败", f"无法加载保存的数据: {str(e)}")
# 确保保存了排除号码输入框的引用
self.exclude_front_entry = self.exclude_front_entries[0] # 保存第一个前区排除输入框
self.exclude_back_entry = self.exclude_back_entries[0] # 保存第一个后区排除输入框
# === 推荐号码区 ===
recommend_frame = LabelFrame(main_frame, text=" 推荐号码 ", font=('微软雅黑', 12, 'bold'))
recommend_frame.pack(fill='x', padx=20, pady=10, ipady=5)
# 推荐号码标签
Label(recommend_frame, text=labels[3], font=('微软雅黑', 10, 'bold')).pack(anchor='w', padx=10, pady=(5, 0))
# 前区推荐
front_rec_frame = Frame(recommend_frame)
front_rec_frame.pack(fill='x', padx=10, pady=5)
Label(front_rec_frame, text=labels[4], font=('微软雅黑', 10)).pack(side='left')
self.recommend_front_var = StringVar()
Entry(front_rec_frame, textvariable=self.recommend_front_var,
state='readonly', font=('微软雅黑', 10),
readonlybackground='#f0f5f0').pack(side='left', fill='x', expand=True, padx=5)
# 后区推荐
back_rec_frame = Frame(recommend_frame)
back_rec_frame.pack(fill='x', padx=10, pady=5)
Label(back_rec_frame, text=labels[5], font=('微软雅黑', 10)).pack(side='left')
self.recommend_back_var = StringVar()
Entry(back_rec_frame, textvariable=self.recommend_back_var,
state='readonly', font=('微软雅黑', 10),
readonlybackground='#f0f5f0').pack(side='left', fill='x', expand=True, padx=5)
# === 结果区 ===
result_frame = LabelFrame(main_frame, text=" 分析结果 ", font=('微软雅黑', 12, 'bold'))
result_frame.pack(fill='both', expand=True, padx=20, pady=10, ipady=5)
scrollbar = Scrollbar(result_frame)
scrollbar.pack(side='right', fill='y')
self.result_text = Text(result_frame, yscrollcommand=scrollbar.set,
wrap='word', font=('微软雅黑', 10))
self.result_text.pack(fill='both', expand=True)
scrollbar.config(command=self.result_text.yview)
# 添加初始提示
self.result_text.insert('end', "请设置排除号码后点击'运行'按钮开始分析\n")
# 强制刷新界面
self.root.update_idletasks()
def _handle_analysis_result(self, event: Event):
if event.target == self.current_module:
result = event.data
self.recommend_front_var.set(' '.join(map(str, result.get('recommended_fronts', []))))
self.recommend_back_var.set(' '.join(map(str, result.get('recommended_backs', []))))
self.result_text.insert('end', f"前区推荐号码: {self.recommend_front_var.get()}\n")
self.result_text.insert('end', f"后区推荐号码: {self.recommend_back_var.get()}\n")
self.result_text.see('end')
def _handle_entry_input(self, event):
"""处理输入框相关事件的总入口"""
if event.keysym in ('Left', 'Right'):
# 处理方向键导航
self._navigate_entry(event, 1 if event.keysym == 'Right' else -1)
else:
# 处理输入自动格式化
self._auto_format_entry(event)
def _auto_format_entry(self, event):
"""
自动格式化输入框内容
功能:
1. 自动将1-9的数字补零显示为01-09
2. 输入满2位后自动跳到下一个输入框
"""
entry = event.widget
current = entry.get().strip()
if current.isdigit(): # 只处理数字输入
# 自动补零处理
formatted = self._format_number(current)
if formatted != current:
entry.delete(0, 'end')
entry.insert(0, formatted)
# 输入满2位后自动跳转
if len(current) == 2:
self._focus_adjacent_entry(event.widget, 1) # 正向跳转
def _focus_adjacent_entry(self, current_entry, direction):
"""
焦点跳转到相邻输入框
:param current_entry: 当前输入框控件
:param direction: 跳转方向 (1:下一个, -1:上一个)
"""
all_entries = self.exclude_front_entries + self.exclude_back_entries
try:
current_index = all_entries.index(current_entry)
target_index = current_index + direction
if 0 <= target_index < len(all_entries):
all_entries[target_index].focus()
except ValueError:
pass
def _navigate_entry(self, event, direction):
"""使用方向键在输入框间导航"""
self._focus_adjacent_entry(event.widget, direction)
def _format_number(self, num_str: str) -> str:
"""
格式化数字为两位数
:param num_str: 输入的数字字符串
:return: 格式化后的两位数字符串
"""
if not num_str.isdigit():
return num_str # 非数字不处理
num = int(num_str)
if 1 <= num <= 9: # 1-9的数字补零
return f"0{num}"
return str(num) if num > 0 else num_str # 保留0和负数原样
def _create_combination_analysis_content(self, parent: Frame):
"""创建组合分析模块的特定内容"""
content_frame = Frame(parent)
content_frame.pack(fill='both', expand=True, padx=10, pady=10)
# 使用预定义的labels
for label in self.labels['combination_analysis']:
frame = Frame(content_frame)
frame.pack(fill='x', pady=2)
Label(frame, text=label, width=12, anchor='w', font=('微软雅黑', 10, 'bold')).pack(side='left')
entry = Entry(frame, width=30, state='readonly', readonlybackground='#f0f0f0')
entry.pack(side='left', padx=5)
# 保存对控件的引用
var_name = label.replace(':', '').replace(' ', '')
setattr(self, f"{var_name}_entry", entry) # 直接保存到实例变量
if var_name == "前区热号":
self.front_hot_entry = entry
elif var_name == "前数字频":
self.front_freq_entry = entry
elif var_name == "前频繁推":
self.front_freq_rec_entry = entry
elif var_name == "后区热号":
self.back_hot_entry = entry
elif var_name == "后数字频":
self.back_freq_entry = entry
elif var_name == "后低频推":
self.back_in_freq_rec_entry = entry
# 结果显示区
result_frame = Frame(content_frame)
result_frame.pack(fill='both', expand=True)
scrollbar = Scrollbar(result_frame)
scrollbar.pack(side='right', fill='y')
self.result_text = Text(result_frame, yscrollcommand=scrollbar.set, wrap='word')
self.result_text.pack(fill='both', expand=True)
scrollbar.config(command=self.result_text.yview)
def _create_follow_analysis_content(self, parent: Frame):
"""创建跟随分析模块UI - 确保标签匹配"""
content_frame = Frame(parent)
content_frame.pack(fill='both', expand=True)
# 使用与数据字典相同的标签
labels = ["前推荐多", "前推荐少", "后推荐多", "后推荐少"]
# 创建显示区域
for label in labels:
frame = Frame(content_frame)
frame.pack(fill='x', pady=2)
Label(frame, text=f"{label}:", width=10).pack(side='left')
entry = Entry(frame, state='readonly')
entry.pack(side='left', fill='x', expand=True)
# 保存引用以便更新
setattr(self, f"{label}_entry", entry)
def _handle_module3_run(self, event: Event):
"""处理模块3运行事件"""
if event.token == GlobalConfig.MODULE3_ID:
# 确保只在模块3里界面处理
if self.current_module == GlobalConfig.MODULE3_ID:
# 更新UI状态
self.status_var.set("模块3分析中...")
# 在动态区显示状态
if hasattr(self, 'dynamic_text'):
self.dynamic_text.insert('end', f"收到模块3运行指令 [Token: {event.token}]\n")
# 结果显示区(不包含按钮)
result_frame = Frame(content_frame)
result_frame.pack(fill='both', expand=True)
scrollbar = Scrollbar(result_frame)
scrollbar.pack(side='right', fill='y')
self.result_text = Text(result_frame, yscrollcommand=scrollbar.set, wrap='word')
self.result_text.pack(fill='both', expand=True)
scrollbar.config(command=self.result_text.yview)
def _create_trend_analysis_content(self, parent: Frame):
"""创建趋势分析模块的特定内容"""
content_frame = Frame(parent)
content_frame.pack(fill='both', expand=True, padx=10, pady=10)
for label in self.labels['trend_analysis']:
frame = Frame(content_frame)
frame.pack(fill='x', pady=2)
Label(frame, text=label, width=12, anchor='w', font=('微软雅黑', 10, 'bold')).pack(side='left')
entry = Entry(frame, width=30, state='readonly', readonlybackground='#f0f0f0')
entry.pack(side='left', padx=5)
var_name = label.replace(':', '').replace(' ', '')
setattr(self, f"{var_name}_entry", entry) # 直接保存到实例变量
if var_name == "和值":
self.sum_value_entry = entry
elif var_name == "质合比":
self.prime_ratio_entry = entry
elif var_name == "奇偶比":
self.odd_even_ratio_entry = entry
elif var_name == "断区推荐":
self.zone_rec_entry = entry
elif var_name == "连号推荐":
self.con_sec_rec_entry = entry
elif var_name == "冷热推荐":
self.hot_cold_rec_entry = entry
elif var_name == "后区热号":
self.hot_rec_entry = entry
elif var_name == "后区冷号":
self.cold_rec_entry = entry
elif var_name == "趋势号":
self.trend_rec_entry = entry
# 结果显示区
result_frame = Frame(content_frame)
result_frame.pack(fill='both', expand=True)
scrollbar = Scrollbar(result_frame)
scrollbar.pack(side='right', fill='y')
self.result_text = Text(result_frame, yscrollcommand=scrollbar.set, wrap='word')
self.result_text.pack(fill='both', expand=True)
scrollbar.config(command=self.result_text.yview)
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_frame = Frame(dan_frame)
front_dan_frame.pack(fill='x')
Label(front_dan_frame, text="前区胆码:").pack(side='left')
self.front_dan_entries = []
for i in range(5):
entry = Entry(front_dan_frame, width=3)
entry.pack(side='left', padx=2)
self.front_dan_entries.append(entry)
self.front_dan_entry = self.front_dan_entries[0] # 保存第一个条目引用
# 后区胆码
back_dan_frame = Frame(dan_frame)
back_dan_frame.pack(fill='x')
Label(back_dan_frame, text="后区胆码:").pack(side='left')
self.back_dan_entries = []
for i in range(5):
entry = Entry(back_dan_frame, width=3)
entry.pack(side='left', padx=2)
self.back_dan_entries.append(entry)
self.back_dan_entry = self.back_dan_entries[0] # 保存第一个条目引用
# 生成的号码显示区
generated_frame = Frame(content_frame)
generated_frame.pack(fill='x', pady=5)
Label(generated_frame, text="生成号码:").pack(anchor='w')
self.generated_labels = []
for i in range(1, 6):
frame = Frame(generated_frame)
frame.pack(fill='x')
Label(frame, text=f"{i}. ").pack(side='left')
label = Label(frame, text="", width=30, anchor='w')
label.pack(side='left')
self.generated_labels.append(label)
# 结果显示区
result_frame = Frame(content_frame)
result_frame.pack(fill='both', expand=True)
scrollbar = Scrollbar(result_frame)
scrollbar.pack(side='right', fill='y')
self.result_text = Text(result_frame, yscrollcommand=scrollbar.set, wrap='word')
self.result_text.pack(fill='both', expand=True)
scrollbar.config(command=self.result_text.yview)
def _run_module(self, module: str):
try:
if module == "input_analysis":
# 获取并格式化排除号码
exclude_front_list = []
for entry in self.exclude_front_entries:
num = entry.get().strip()
if num: # 只处理非空输入
exclude_front_list.append(num)
exclude_back_list = []
for entry in self.exclude_back_entries:
num = entry.get().strip()
if num: # 只处理非空输入
exclude_back_list.append(num)
exclude_front = ' '.join(exclude_front_list)
exclude_back = ' '.join(exclude_back_list)
# 在结果文本中记录
self.result_text.insert('end',
f"正在运行分析...\n排除号码: 前区 {exclude_front}, 后区 {exclude_back}\n")
# 发布模块运行事件,确保target正确
run_event = Event(
event_id=int(time.time()),
type=EventType.MODULE_RUN,
source='main_ui',
target=module # 确保target是当前模块名
)
event_center.publish(run_event)
# 发布模块运行事件(包含完整数据)
run_event = Event(
event_id=int(time.time()),
type=EventType.MODULE_RUN,
source='main_ui',
target=module,
data={
'exclude_front': exclude_front,
'exclude_back': exclude_back
}
)
event_center.publish(run_event)
# 记录事件发布
self.result_text.insert('end', "已发送运行指令和排除号码数据\n")
except Exception as e:
logging.error(f"运行模块失败: {str(e)}", exc_info=True)
messagebox.showerror("运行失败", f"无法运行模块: {str(e)}")
def _generate_recommend_numbers(self, exclude_front: str, exclude_back: str):
"""生成推荐号码(示例逻辑)"""
# 实际应用中应调用分析模块生成推荐号码
# 这里简化为生成随机推荐号码
import random
# 前区号码范围1-35
all_front = [str(idx) for idx in range(1, 36)]
exclude_front_list = exclude_front.split() if exclude_front else []
available_front = [num for num in all_front if num not in exclude_front_list]
# 后区号码范围1-12
all_back = [str(idx) for idx in range(1, 13)]
exclude_back_list = exclude_back.split() if exclude_back else []
available_back = [num for num in all_back if num not in exclude_back_list]
# 随机选择5个前区号码
if len(available_front) >= 5:
recommend_front = random.sample(available_front, 5)
else:
recommend_front = random.sample(all_front, 5)
# 随机选择2个后区号码
if len(available_back) >= 2:
recommend_back = random.sample(available_back, 2)
else:
recommend_back = random.sample(all_back, 2)
# 更新推荐号码显示
self.recommend_front_var.set(' '.join(sorted(recommend_front, key=int)))
self.recommend_back_var.set(' '.join(sorted(recommend_back, key=int)))
# 在结果文本中记录
self.result_text.insert('end', f"生成推荐号码: 前区 {self.recommend_front_var.get()}, 后区 {self.recommend_back_var.get()}\n")
# 更新号码池
self._update_pool_with_recommendations(self.recommend_front_var.get(), self.recommend_back_var.get())
def update_recommendations(self, fronts: List[int], backs: List[int]):
"""更新推荐号码显示(使用号码池路径保存)"""
formatted_fronts = [str(num).zfill(2) for num in fronts]
formatted_backs = [str(num).zfill(2) for num in backs]
self.recommend_front_var.set(' '.join(formatted_fronts))
self.recommend_back_var.set(' '.join(formatted_backs))
# 保存到号码池文件
try:
pool_data = {
'recommended_fronts': formatted_fronts,
'recommended_backs': formatted_backs,
'module_id': GlobalConfig.MODULE1_ID,
'timestamp': time.strftime("%Y-%m-%d %H:%M:%S")
}
with open(GlobalConfig.POOL_SAVE_PATH, 'w', encoding='utf-8') as f:
json.dump(pool_data, f, indent=2, ensure_ascii=False)
logging.info(f"推荐号码已保存到号码池: {GlobalConfig.POOL_SAVE_PATH}")
except Exception as e:
logging.error(f"保存号码池失败: {str(e)}")
def _clear_module_data(self, module: str):
"""清除模块数据 - 确保清除所有输入框"""
if module == "input_analysis":
# 清除前区排除号码
for entry in self.exclude_front_entries:
entry.delete(0, 'end')
# 清除后区排除号码
for entry in self.exclude_back_entries:
entry.delete(0, 'end')
# 清除推荐号码显示
if hasattr(self, 'recommend_front_var'):
self.recommend_front_var.set('')
if hasattr(self, 'recommend_back_var'):
self.recommend_back_var.set('')
# 清除结果文本
if hasattr(self, 'result_text') and self.result_text:
self.result_text.delete(1.0, 'end')
elif module == "combination_analysis":
if hasattr(self, 'front_hot_entry') and self.front_hot_entry:
self.front_hot_entry.delete(0, 'end')
if hasattr(self, 'front_freq_entry') and self.front_freq_entry:
self.front_freq_entry.delete(0, 'end')
if hasattr(self, 'front_freq_rec_entry') and self.front_freq_rec_entry:
self.front_freq_rec_entry.delete(0, 'end')
if hasattr(self, 'back_hot_entry') and self.back_hot_entry:
self.back_hot_entry.delete(0, 'end')
if hasattr(self, 'back_freq_entry') and self.back_freq_entry:
self.back_freq_entry.delete(0, 'end')
if hasattr(self, 'back_in_freq_rec_entry') and self.back_in_freq_rec_entry:
self.back_in_freq_rec_entry.delete(0, 'end')
if hasattr(self, 'result_text') and self.result_text:
self.result_text.delete(1.0, 'end')
if hasattr(self, 'result_text') and self.result_text:
self.result_text.delete(1.0, 'end')
if hasattr(self, 'front_entry') and self.front_entry:
self.front_entry.delete(0, 'end')
if hasattr(self, 'back_entry') and self.back_entry:
self.back_entry.delete(0, 'end')
if hasattr(self, 'exclude_front_entry') and self.exclude_front_entry:
self.exclude_front_entry.delete(0, 'end')
if hasattr(self, 'exclude_back_entry') and self.exclude_back_entry:
self.exclude_back_entry.delete(0, 'end')
def _save_module_data(self, module: str):
"""保存模块数据 - 根据不同模块保存对应的数据到指定路径"""
try:
data = {}
filename = ""
if module == "input_analysis":
# 收集排除号码 - 只保存非空值
exclude_front_list = [entry.get().strip() for entry in self.exclude_front_entries if
entry.get().strip()]
exclude_back_list = [entry.get().strip() for entry in self.exclude_back_entries if entry.get().strip()]
data = {
'exclude_front': exclude_front_list,
'exclude_back': exclude_back_list,
'module_id': GlobalConfig.module1_id,
'timestamp': time.strftime("%Y-%m-%d %H:%M:%S")
}
filename = GlobalConfig.MODULE1_SAVE_PATH
elif module == "combination_analysis":
data = {
'front_hot': self.front_hot_entry.get(),
'front_freq': self.front_freq_entry.get(),
'front_freq_rec': self.front_freq_rec_entry.get(),
'back_hot': self.back_hot_entry.get(),
'back_freq': self.back_freq_entry.get(),
'back_in_freq_rec': self.back_in_freq_rec_entry.get(),
'result': self.result_text.get(1.0, 'end').strip(),
'timestamp': time.strftime("%Y-%m-%d %H:%M:%S")
}
filename = GlobalConfig.MODULE2_SAVE_PATH
elif module == "follow_analysis":
data = {
"前推荐多": self.front_recommend_more.get(),
"前推荐少": self.front_recommend_less.get(),
"后推荐多": self.back_recommend_more.get(),
"后推荐少": self.back_recommend_less.get(),
'timestamp': time.strftime("%Y-%m-%d %H:%M:%S")
}
filename = GlobalConfig.MODULE3_SAVE_PATH
elif module == "trend_analysis":
data = {
"和值": self.he_zhi_entry.get(),
"质合比": self.zhi_he_bi_entry.get(),
"奇偶比": self.ji_ou_bi_entry.get(),
"断区推荐": self.duan_qu_entry.get(),
"连号推荐": self.lian_hao_entry.get(),
"冷热推荐": self.len_gre_entry.get(),
"后区热号": self.hou_qu_re_hao_entry.get(),
"后区冷号": self.hou_qu_len_hao_entry.get(),
"趋势号": self.qu_shi_entry.get(),
'timestamp': time.strftime("%Y-%m-%d %H:%M:%S")
}
filename = GlobalConfig.MODULE4_SAVE_PATH
elif module == "number_generation":
data = {
"胆码": self.dan_ma_entry.get(),
"前区": self.front_numbers_entry.get(),
"后区": self.back_numbers_entry.get(),
"推荐5注号码": {
"1": self.recommend_1.get(),
"2": self.recommend_2.get(),
"3": self.recommend_3.get(),
"4": self.recommend_4.get(),
"5": self.recommend_5.get()
},
'timestamp': time.strftime("%Y-%m-%d %H:%M:%S")
}
filename = GlobalConfig.MODULE5_SAVE_PATH
# 确保目录存在
os.makedirs(os.path.dirname(filename), exist_ok=True)
# 保存数据
with open(filename, 'w', encoding='utf-8') as f:
json.dump(data, f, indent=2, ensure_ascii=False)
messagebox.showinfo("保存成功", f"数据已保存到:\n{filename}")
except Exception as e:
messagebox.showerror("保存失败", f"无法保存数据: {str(e)}")
logging.error(f"保存数据失败: {str(e)}", exc_info=True)
def _on_module_renovate(self, module: str):
"""刷新模块"""
if module == self.current_module:
self._on_module_button_click(module)
def _handle_ui_update(self, event: Event):
update_type = event.data.get('update_type') # 添加 update_type 的定义
data = event.data.get('data', {}) # 确保 data 被赋值,避免未定义问题
if event.data.get('update_type') == 'recommendations':
data = event.data.get('data', {})
front_rec = data.get('recommendations', {}).get('front_rec', [])
back_rec = data.get('recommendations', {}).get('back_rec', [])
self.recommend_front_var.set(' '.join(map(str, front_rec)))
self.recommend_back_var.set(' '.join(map(str, back_rec)))
# 处理核心变量更新
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', [])))