修改问题:在子类界面(1.输入分析)里,用户点击刷新后,仍然没有把数据完整呈现出来,有空格。而用户点击按钮“删除”时,输入框里的数据又不能删除。。2.检查,保存和读取文件的路径[c:\用户 \administrator\桌面\saved_numbers.json]原代码import sys
import threading
import time
import logging
import json
import random
import os
from typing import List, Dict, Optional, Callable, Any
from tkinter import (Tk, Frame, Label, Button, Entry, StringVar, PanedWindow,
HORIZONTAL, VERTICAL, RAISED, Canvas, Scrollbar, messagebox,
Text, LabelFrame) # 添加LabelFrame
from tkinter.constants import VERTICAL, RAISED
from dataclasses import dataclass
from enum import Enum, auto
from queue import Queue
配置日志
logging.basicConfig(
level=logging.INFO,
format=‘%(asctime)s - %(name)s - %(levelname)s - %(message)s’,
datefmt=‘%Y-%m-%d %H:%M:%S’)
logger = logging.getLogger(‘DLT_Analysis’)
==================== 全局配置 ====================
class GlobalConfig:
VERSION = “大乐透智能分析平台 v5.2”
POOL_SAVE_PATH = os.path.join(os.path.expanduser(“~”), “Desktop”, “号码池.json”)
MODULE1_SAVE_PATH = os.path.join(os.path.expanduser(“~”), “Desktop”, “saved_numbers.json”)
MODULE1_ID = “module1.module1_id” # 新增模块ID
MODULE2_ID = “module2.module2_id” # 新增
MODULE3_ID = “module3.module3_id” # 新增
MODULE4_ID = “module4.module4_id” # 新增
MODULE5_ID = “module5.module5_id” # 新增
MODULES = [‘input_analysis’, ‘combination_analysis’, ‘follow_analysis’, ‘trend_analysis’, ‘number_generation’]
# 号码池UI配置
UI_CONFIG = [
(“前区:”, “front_area”, 1),
(“后区:”, “back_area”, 2),
(“前数字频:”, “front_freq”, 3),
(“前数字缺:”, “front_missing”, 4),
(“后数字频:”, “back_freq”, 5),
(“后数字缺:”, “back_missing”, 6),
(“前频繁推:”, “front_freq_50”, 7),
(“后低频推:”, “back_infreq_50”, 8),
(“生组合数:”, “comb_count”, 9),
(“未组合码:”, “uncombined”, 10),
(“前推荐多:”, “front_rec_more”, 11),
(“前推荐少:”, “front_rec_less”, 12),
(“后推荐多:”, “back_rec_more”, 13),
(“后推荐少:”, “back_rec_less”, 14),
(“和值:”, “sum_rec”, 15),
(“质合比:”, “prime_rec”, 16),
(“奇偶比:”, “odd_even_rec”, 17),
(“断区推荐:”, “zone_rec”, 18),
(“连号推荐:”, “consec_rec”, 19),
(“冷热推荐:”, “hot_cold_rec”, 20),
(“后区热号:”, “hot_rec”, 21),
(“后区冷号:”, “cold_rec”, 22),
(“趋势号:”, “trend_rec”, 23)
]
全局应用上下文
class AppContext:
def init(self):
self.dialog_manager = None
self.main_ui = None
self.loading_queue = Queue()
self.modules_loaded = {module: False for module in GlobalConfig.MODULES}
self.modules_completed =
app = AppContext()
==================== 事件类型 ====================
class EventType(Enum):
START_COMMAND = auto()
DATA_SUBMIT = auto()
ACK = auto()
MODULE_READY = auto()
MODULE_COMPLETE = auto()
UI_UPDATE = auto()
DIALOG_OPEN = auto()
DIALOG_CLOSE = auto()
DATA_FREEZE = auto()
DATA_ORGANIZE = auto() # 添加缺失的枚举值
MODULE_RUN = auto()
LOADING_PROGRESS = auto()
LOADING_COMPLETE = auto()
EXCLUDE_NUMBERS = auto()
POOL_UPDATE = auto()
==================== 事件系统 ====================
@dataclass
class Event:
event_id: int
type: EventType
source: str
target: str
timestamp: float = time.time()
data: Optional[Dict[str, Any]] = None
class EventEmitter:
def init(self):
self._lock: threading.Lock = threading.Lock()
self._subscribers: Dict[EventType, List[Callable[[Event], None]]] = {}
def subscribe(self, event_type: EventType, callback: Callable[[Event], None]): with self._lock: if event_type not in self._subscribers: self._subscribers[event_type] = [] self._subscribers[event_type].append(callback) def publish(self, event: Event): with self._lock: subscribers = self._subscribers.get(event.type, []) for callback in subscribers: try: callback(event) except Exception as e: logging.error(f"事件处理失败: {str(e)}", exc_info=True)
event_center = EventEmitter()
==================== 号码池实现 ====================
class NumberPool:
def init(self):
self.data_store: Dict[str, Any] = {
‘front_hot’: [], ‘back_hot’: [], ‘front_freq’: {}, ‘back_freq’: {},
‘front_missing’: [], ‘back_missing’: [], ‘recommendations’: {},
‘generated_numbers’: [], ‘frozen’: False,
‘front_numbers’: [], ‘back_numbers’: [], ‘special_data’: {},
‘organized_data’: None
}
self.lock = threading.Lock()
self.current_module: Optional[str] = None
self.module_status = {module: False for module in GlobalConfig.MODULES}
self.running = True
self._setup_subscriptions()
self._load_data()
def update(self, label: str, value: Any): """更新号码池数据""" with self.lock: # 根据标签名更新对应数据 if label == "前区:": self.data_store['front_numbers'] = value elif label == "后区:": self.data_store['back_numbers'] = value elif label == "前数字频:": self.data_store['front_freq'] = value elif label == "前数字缺:": self.data_store['front_missing'] = value elif label == "后数字频:": self.data_store['back_freq'] = value elif label == "后数字缺:": self.data_store['back_missing'] = value elif label == "前频繁推:": self.data_store['front_freq_50'] = value elif label == "后低频推:": self.data_store['back_infreq_50'] = value elif label == "生组合数:": self.data_store['comb_count'] = value elif label == "未组合码:": self.data_store['uncombined'] = value elif label == "前推荐多:": self.data_store['front_rec_more'] = value elif label == "前推荐少:": self.data_store['front_rec_less'] = value elif label == "后推荐多:": self.data_store['back_rec_more'] = value elif label == "后推荐少:": self.data_store['back_rec_less'] = value elif label == "和值:": self.data_store['sum_rec'] = value elif label == "质合比:": self.data_store['prime_rec'] = value elif label == "奇偶比:": self.data_store['odd_even_rec'] = value elif label == "断区推荐:": self.data_store['zone_rec'] = value elif label == "连号推荐:": self.data_store['consec_rec'] = value elif label == "冷热推荐:": self.data_store['hot_cold_rec'] = value elif label == "后区热号:": self.data_store['hot_rec'] = value elif label == "后区冷号:": self.data_store['cold_rec'] = value elif label == "趋势号:": self.data_store['trend_rec'] = value self._save_data() def _setup_subscriptions(self): event_center.subscribe(EventType.DATA_SUBMIT, self._handle_data_submit) event_center.subscribe(EventType.MODULE_READY, self._handle_module_ready) event_center.subscribe(EventType.MODULE_COMPLETE, self._handle_module_complete) event_center.subscribe(EventType.DATA_FREEZE, self._handle_freeze) event_center.subscribe(EventType.DATA_ORGANIZE, self._handle_organize) event_center.subscribe(EventType.MODULE_RUN, self._handle_module_run) event_center.subscribe(EventType.EXCLUDE_NUMBERS, self._handle_exclude_numbers) def _handle_exclude_numbers(self, event: Event): """处理排除号码事件""" if event.data: exclude_front = event.data.get('exclude_front', '').split() exclude_back = event.data.get('exclude_back', '').split() # 更新排除号码 self.data_store['excluded_front'] = [int(x) for x in exclude_front if x.isdigit()] self.data_store['excluded_back'] = [int(x) for x in exclude_back if x.isdigit()] # 日志记录 logging.info(f"更新排除号码: 前区 {exclude_front}, 后区 {exclude_back}") def _handle_module_ready(self, event: Event): if event.target == 'pool': logging.info(f"模块 {event.source} 已就绪") app.modules_loaded[event.source] = True def _handle_module_complete(self, event: Event): if event.target == 'pool': logging.info(f"模块 {event.source} 已完成运行") self.module_status[event.source] = False self.current_module = None app.modules_completed[event.source] = True def _handle_freeze(self, event: Event): if event.target == 'pool': with self.lock: self.data_store['frozen'] = True logging.info("号码池数据已冻结") def _handle_organize(self, event: Event): if event.target == 'pool': with self.lock: # 检查所有模块是否已完成 all_completed = all(app.modules_completed.values()) if not all_completed: logging.warning("无法整理数据: 还有模块未完成分析") return # 整理数据逻辑 self._organize_data() logging.info("号码池数据已整理") # 更新UI update_event = Event( event_id=int(time.time()), type=EventType.UI_UPDATE, source='pool', target='main_ui', data={'update_type': 'organized_data', 'data': self.data_store['organized_data']} ) event_center.publish(update_event) def _organize_data(self): """整理号码池数据到核心展示区""" organized = { 'front_numbers': self._organize_front_numbers(), 'back_numbers': self._organize_back_numbers(), 'front_hot': self._organize_front_hot(), 'front_cold': self._organize_front_cold(), 'back_hot': self._organize_back_hot(), 'back_cold': self._organize_back_cold() } self.data_store['organized_data'] = organized def _organize_front_numbers(self): """整理前区号码""" front_numbers = self.data_store.get('front_numbers', []) uncombined = self.data_store.get('recommendations', {}).get('uncombined', []) return sorted(list(set(front_numbers + uncombined))) def _organize_back_numbers(self): """整理后区号码""" return self.data_store.get('back_numbers', []) def _organize_front_hot(self): """整理前区热号""" front_freq = list(self.data_store.get('front_freq', {}).keys()) front_freq_rec = self.data_store.get('recommendations', {}).get('front极_freq_50', []) front_rec_more = self.data_store.get('recommendations', {}).get('front_rec_more', []) hot_cold_rec = self.data_store.get('recommendations', {}).get('hot_cold_rec', {}).get('hot', []) hot_numbers = list(set( [int(x) for x in front_freq] + front_freq_rec + front_rec_more + hot_cold_rec )) return sorted(hot_numbers) def _organize_front_cold(self): """整理前区冷号""" front_missing = self.data_store.get('front_missing', []) front_rec_less = self.data_store.get('recommendations', {}).get('front_rec_less', []) hot_cold_rec = self.data_store.get('recommendations', {}).get('hot_cold_rec', {}).get('cold', []) cold_numbers = list(set( front_missing + front_rec_less + hot_cold_rec )) return sorted(cold_numbers) def _organize_back_hot(self): """整理后区热号""" back_freq = list(self.data_store.get('back_freq', {}).keys()) back_rec_more = self.data_store.get('recommendations', {}).get('back_rec_more', []) hot_rec = self.data_store.get('recommendations', {}).get('hot_rec', []) hot_numbers = list(set( [int(x) for x in back_freq] + back_rec_more + hot_rec )) return sorted(hot_numbers) def _organize_back_cold(self): """整理后区冷号""" back_missing = self.data_store.get('back_missing', []) back_infreq_rec = self.data_store.get('recommendations', {}).get('back_infreq_50', []) back_rec_less = self.data_store.get('recommendations', {}).get('back_rec_less', []) cold_rec = self.data_store.get('recommendations', {}).get('cold_rec', []) cold_numbers = list(set( back_missing + back_infreq_rec + back_rec_less + cold_rec )) return sorted(cold_numbers) def _handle_module_run(self, event: Event): if event.target == 'pool' and event.source in GlobalConfig.MODULES: self.current_module = event.source self.module_status[event.source] = True logging.info(f"模块 {event.source} 开始运行") run_event = Event( event_id=int(time.time()), type=EventType.MODULE_RUN, source='pool', target=event.source ) event_center.publish(run_event) def _handle_data_submit(self, event: Event): if event.target == 'pool' and not self.data_store['frozen']: with self.lock: logger.info(f"收到来自 {event.source} 的数据提交") # 新增日志 if event.data: self.data_store.update(event.data) logger.debug(f"更新后的数据: {self.data_store}") # 新增日志 self.data_store.update(event.data) update_event = Event( event_id=int(time.time()), type=EventType.UI_UPDATE, source='pool', target='main_ui', data={'update_type': 'pool_update', 'data': self.data_store} ) event_center.publish(update_event) self._save_data() def _save_data(self): try: with open(GlobalConfig.POOL_SAVE_PATH, 'w', encoding='utf-8') as f: json.dump(self.data_store, f, ensure_ascii=False, indent=2) except IOError as e: logging.error(f"[号码池] 保存数据失败: {str(e)}") def _load_data(self): if os.path.exists(GlobalConfig.POOL_SAVE_PATH): try: with open(GlobalConfig.POOL_SAVE_PATH, 'r', encoding='utf-8') as f: data = json.load(f) with self.lock: self.data_store.update(data) logging.info("[号码池] 成功加载之前保存的数据") except (IOError, json.JSONDecodeError) as e: logging.error(f"[号码池] 加载数据失败: {str(e)}")
==================== 基础模块类 ====================
class BaseModule:
def init(self, module_name: str):
self.module_name = module_name
self._setup_subscriptions()
self._initialize()
self.dynamic_data = {}
self._dialog_opened = False
# 确保所有属性都被初始化
def _setup_subscriptions(self): def filtered_handler(event: Event): if event.target == self.module_name: self._handle_start_command(event) event_center.subscribe(EventType.START_COMMAND, filtered_handler) event_center.subscribe(EventType.MODULE_RUN, self._handle_module_run) def clear_dynamic_data(self): """清除动态区数据""" for key in self.dynamic_data: if isinstance(self.dynamic_data[key], list): self.dynamic_data[key] = [] elif isinstance(self.dynamic_data[key], dict): self.dynamic_data[key] = {} else: self.dynamic_data[key] = "" def save_dynamic_data(self, file_path): """保存动态区数据到指定位置""" with open(file_path, 'w') as f: json.dump(self.dynamic_data, f) def refresh_to_pool(self, number_pool): """将动态区数据传递到号码池对应标签""" for key, value in self.dynamic_data.items(): # 确保标签名与号码池标签名一致 pool_label = f"{key}:" if not key.endswith(":") else key number_pool.update(pool_label, value) def _initialize(self): ready_event = Event( event_id=int(time.time()), type=EventType.MODULE_READY, source=self.module_name, target='pool' ) event_center.publish(ready_event) def _handle_start_command(self, event: Event): if not self._dialog_opened: logger.info(f"正在打开模块 {self.module_name} 的界面") self._open_dialog() self._dialog_opened = True else: logging.warning(f"{self.module_name} 已打开,避免重复触发") def _open_dialog(self): # 使用主循环调度UI操作,确保在主线程执行 app.main_ui.root.after(0, lambda: event_center.publish(Event( event_id=int(time.time()), type=EventType.DIALOG_OPEN, source=self.module_name, target='dialog_manager', data={'dialog_type': self.module_name} ))) def _submit_data(self, data: Dict[str, Any]): submit_event = Event( event_id=int(time.time()), type=EventType.DATA_SUBMIT, source=self.module_name, target='pool', data=data ) event_center.publish(submit_event) def _handle_module_run(self, event: Event): """处理模块运行事件""" raise NotImplementedError(f"{self.__class__.__name__} 必须实现 _handle_module_run 方法") def run(self): raise NotImplementedError("子类必须实现run方法")
==================== 输入分析模块 ====================
class InputAnalysisModule(BaseModule):
def init(self, module_name: str):
super().init(module_name)
# 统一标签名格式(添加冒号)
self.dynamic_data = {
“排除号码”: {
“前区”: [],
“后区”: []
},
“推荐号码”: {
“前区”: [],
“后区”: []
}
}
def _handle_module_run(self, event: Event): """处理输入分析模块的运行事件""" logger.info(f"开始运行输入分析模块: {event}") self.run() def run(self): dialog = app.dialog_manager.active_dialogs.get(self.module_name) if not dialog: return # 获取排除号码 exclude_front = app.main_ui.exclude_front_var.get() exclude_back = app.main_ui.exclude_back_var.get() # 更新动态区显示 self._update_dynamic_text(f"排除号码 - 前区: {exclude_front}, 后区: {exclude_back}\n") # 模拟分析过程 time.sleep(1) # 生成分析结果(考虑排除号码) all_front = [x for x in range(1, 36) if str(x) not in exclude_front.split()] all_back = [x for x in range(1, 13) if str(x) not in exclude_back.split()] front_nums = sorted(random.sample(all_front, 5)) back_nums = sorted(random.sample(all_back, 2)) # 更新界面显示 result_text = f"分析结果:\n前区: {front_nums}\n后区: {back_nums}\n" self._update_dynamic_text(result_text) # 提交数据到号码池 self._submit_data({ 'front_numbers': front_nums, 'back_numbers': back_nums, 'excluded_numbers': { 'front': exclude_front.split(), 'back': exclude_back.split() } }) # 标记模块完成 complete_event = Event( event_id=int(time.time()), type=EventType.MODULE_COMPLETE, source=self.module_name, target='pool' ) event_center.publish(complete_event) def _update_dynamic_text(self, text: str): dialog = app.dialog_manager.active_dialogs.get(self.module_name) if dialog and hasattr(dialog, 'dynamic_text'): dialog.dynamic_text.insert('end', text)
==================== 组合分析模块 ====================
class CombinationAnalysisModule(BaseModule):
def init(self, module_name: str):
super().init(module_name)
# 统一标签名格式(添加冒号)
self.dynamic_data = {
“前数字频”: {},
“前数字缺”: [],
“后数字频”: {},
“后数字缺”: [],
“前频繁推”: [],
“后低频推”: [],
“生组合数”: 0,
“未组合码”: []
}
def _handle_module_run(self, event: Event): """处理组合分析模块的运行事件""" logger.info(f"开始运行组合分析模块: {event}") self.run() def run(self): dialog = app.dialog_manager.active_dialogs.get(self.module_name) if not dialog: return # 更新动态活动区显示 self._update_dynamic_text("开始组合分析...\n") # 模拟分析过程 time.sleep(1) # 生成分析结果 (模拟) front_hot = sorted(random.sample(range(1, 36), 5)) back_hot = sorted(random.sample(range(1, 13), 2)) front_freq = {str(i): random.randint(1, 100) for idx in range(1, 36)} back_freq = {str(i): random.randint(1, 100) for idx in range(1, 13)} front_missing = sorted(random.sample(range(1, 36), 5)) back_missing = sorted(random.sample(range(1, 13), 2)) front_freq_rec = sorted(random.sample(range(1, 36), 5)) back_infreq_rec = sorted(random.sample(range(1, 13), 2)) # 定义back_infreq_rec uncombined = [] # 定义uncombined变量 # 更新界面显示 result_text = f""" 组合分析完成: 前数字频: {front_freq} 前数字缺: {front_missing} 后数字频: {back_freq} 后数字缺: {back_missing} 前频繁推: {front_freq_rec} 后低频推: {back_infreq_rec} 生组合数: 0 未组合码: {uncombined} """ self._update_dynamic_text(result_text) # 提交数据到号码池 self._submit_data({ 'front_hot': front_hot, 'back_hot': back_hot, 'front_freq': front_freq, 'back_freq': back_freq, 'front_missing': front_missing, 'back_missing': back_missing, 'recommendations': { 'front_freq_50': front_freq_rec, 'back_infreq_50': back_infreq_rec, 'uncombined': uncombined } }) # 标记模块完成 complete_event = Event( event_id=int(time.time()), type=EventType.MODULE_COMPLETE, source=self.module_name, target='pool' ) event_center.publish(complete_event) def _update_dynamic_text(self, text: str): dialog = app.dialog_manager.active_dialogs.get(self.module_name) if dialog and hasattr(dialog, 'dynamic_text'): dialog.dynamic_text.insert('end', text)
==================== 跟随分析模块 ====================
class FollowAnalysisModule(BaseModule):
def init(self, module_name: str):
super().init(module_name)
# 统一标签名格式(添加冒号)
self.dynamic_data = {
“前推荐多”: [],
“前推荐少”: [],
“后推荐多”: [],
“后推荐极少”: []
}
def _handle_module_run(self, event: Event): """处理跟随分析模块的运行事件""" logger.info(f"开始运行跟随分析模块: {event}") self.run() def run(self): dialog = app.dialog_manager.active_dialogs.get(self.module_name) if not dialog: return # 更新动态活动区显示 self._update_dynamic_text("开始跟随分析...\n") # 模拟分析过程 time.sleep(1) # 生成分析结果 (模拟) front_rec_more = sorted(random.sample(range(1, 36), 5)) front_rec_less = sorted(random.sample(range(1, 36), 5)) back_rec_more = sorted(random.sample(range(1, 13), 2)) back_rec_less = sorted(random.sample(range(1, 13), 2)) # 更新界面显示 result_text = f""" 跟随分析完成: 前推荐多: {front_rec_more} 前推荐少: {front_rec_less} 后推荐多: {back_rec_more} 后推荐少: {back_rec_less} """ self._update_dynamic_text(result_text) # 提交数据到号码池 self._submit_data({ 'recommendations': { 'front_rec_more': front_rec_more, 'front_rec_less': front_rec_less, 'back_rec_more': back_rec_more, 'back_rec_less': back_rec_less, } }) # 标记模块完成 complete_event = Event( event_id=int(time.time()), type=EventType.MODULE_COMPLETE, source=self.module_name, target='pool' ) event_center.publish(complete_event) def _update_dynamic_text(self, text: str): dialog = app.dialog_manager.active_dialogs.get(self.module_name) if dialog and hasattr(dialog, 'dynamic_text'): dialog.dynamic_text.insert('end', text)
==================== 趋势分析模块 ====================
class TrendAnalysisModule(BaseModule):
def init(self, module_name: str):
super().init(module_name)
# 统一标签名格式(添加冒号)
self.dynamic_data = {
“和值”: “”,
“质合比”: “”,
“奇偶比”: “”,
“断区推荐”: [],
“连号推荐”: [],
“冷热推荐”: [],
“后区热号”: [],
“后区冷号”: [],
“趋势号”: []
}
def _handle_module_run(self, event: Event): """处理趋势分析模块的运行事件""" logger.info(f"开始运行趋势分析模块: {event}") self.run() def run(self): dialog = app.dialog_manager.active_dialogs.get(self.module_name) if not dialog: return # 更新动态活动区显示 self._update_dynamic_text("开始趋势分析...\n") # 模拟分析过程 time.sleep(1) # 生成分析结果 (模拟) sum_value = random.randint(60, 125) prime_ratio = f"{random.randint(1, 5)}:{random.randint(1, 5)}" odd_even_ratio = f"{random.randint(1, 5)}:{random.randint(1, 5)}" zone_rec = random.choice(["一区", "二区", "三区", "四区", "五区", "六区", "七区"]) consec_rec = random.sample(range(1, 36), 2) hot_rec = sorted(random.sample(range(1, 13), 2)) cold_rec = sorted(random.sample(range(1, 13), 2)) trend_rec = sorted(random.sample(range(1, 36), 5)) hot_cold_rec = { 'hot': sorted(random.sample(range(1, 36), 5)), 'cold': sorted(random.sample(range(1, 36), 5)) } # 更新界面显示 result_text = f""" 趋势分析完成: 和值推荐: {sum_value} 质合比: {prime_ratio} 奇偶比: {odd_even_ratio} 断区推荐: {zone_rec} 连号推荐: {consec_rec} 后区热号: {hot_rec} 后区冷号: {cold_rec} 趋势号: {trend_rec} """ self._update_dynamic_text(result_text) # 提交数据到号码池 self._submit_data({ 'recommendations': { 'sum_rec': sum_value, 'prime_rec': prime_ratio, 'odd_even_rec': odd_even_ratio, 'zone_rec': zone_rec, 'consec_rec': consec_rec, 'hot_rec': hot_rec, 'cold_rec': cold_rec, 'trend_rec': trend_rec, 'hot_cold_rec': hot_cold_rec }, 'trend_data': { 'hot_numbers': hot_rec, 'cold_numbers': cold_rec, 'trend_numbers': trend_rec } }) # 标记模块完成 complete_event = Event( event_id=int(time.time()), type=EventType.MODULE_COMPLETE, source=self.module_name, target='pool' ) event_center.publish(complete_event) def _update_dynamic_text(self, text: str): dialog = app.dialog_manager.active_dialogs.get(self.module_name) if dialog and hasattr(dialog, 'dynamic_text'): dialog.dynamic_text.insert('end', text)
==================== 数字生成模块 ====================
class NumberGenerationModule(BaseModule):
def init(self, module_name: str):
super().init(module_name)
# 统一标签名格式(添加冒号)
self.dynamic_data = {
“胆码”: {
“前区”: [],
“后区”: []
},
“推荐5注号码”: {
“1”: “”,
“2”: “”,
“3”: “”,
“4”: “”,
“5”: “”
}
}
def _handle_module_run(self, event: Event): """处理数字生成模块的运行事件""" logger.info(f"开始运行数字生成模块: {event}") self.run() def run(self): dialog = app.dialog_manager.active_dialogs.get(self.module_name) if not dialog: return # 获取胆码数据 front_dan = dialog.content_frame.front_dan_entry.get() back_dan = dialog.content_frame.back_dan_entry.get() # 在动态活动区显示分析过程 self._update_dynamic_text(f"开始数字生成...\n胆码数据: 前区:{front_dan}, 后区:{back_dan}\n") # 生成号码 generated_numbers = self._generate_numbers(front_dan, back_dan) # 更新动态活动区显示 result_text = "生成的5注号码:\n" for num, nums in enumerate(generated_numbers, 1): result_text += f"{num}: 前区:{nums['front']} 后区:{nums['back']}\n" self._update_dynamic_text(result_text) # 提交数据到号码池 self._submit_data({ 'generated_numbers': generated_numbers }) # 标记模块完成 complete_event = Event( event_id=int(time.time()), type=EventType.MODULE_COMPLETE, source=self.module_name, target='pool' ) event_center.publish(complete_event) def _update_dynamic_text(self, text: str): """更新动态区文本""" dialog = getattr(self, 'dialog', None) if dialog and hasattr(dialog, 'dynamic_text'): dialog.dynamic_text.insert('end', text) @staticmethod def _generate_numbers(front_dan: str, back_dan: str): """使用胆码生成号码""" # 这里实现具体的号码生成逻辑 # 返回生成的号码列表 generated_numbers = [] for _ in range(5): front_nums = sorted(random.sample(range(1, 36), 5)) back_nums = sorted(random.sample(range(1, 13), 2)) generated_numbers.append({ 'front': front_nums, 'back': back_nums }) return generated_numbers
==================== 主界面修改 ====================
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 = None
self.current_module = None
self._setup_ui()
self._setup_event_handlers()
self.module_instances = {}
self.exclude_front_entries = []
self.exclude_back_entries = []
self.front_dan_entries = []
self.back_dan_entries = []
# 初始化结果文本控件
self.result_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 = None
self.module_content_frame = None
# 新增模块ID属性
self.module_ids = {
‘input_analysis’: GlobalConfig.MODULE1_ID,
‘combination_analysis’: GlobalConfig.MODULE2_ID,
‘follow_analysis’: GlobalConfig.MODULE3_ID,
‘trend_analysis’: GlobalConfig.MODULE4_ID,
‘number_generation’: GlobalConfig.MODULE5_ID,
}
# 模块标签定义
self.labels = {
‘input_analysis’: [ # 修正为小写
“排除号码:”, “前区:”, “后区:”, “推荐号码:”, “前区:”, “后区:”,
],
‘combination_analysis’: [
“前数字频:”, “前数字缺:”, “后数字频:”, “后数字缺:”,
“前频繁推:”, “后低频推:”, “生组合数:”, “未组合码:”
],
‘follow_analysis’: [
“前推荐多:”, “前推荐少:”, “后推荐多:”, “后推荐少:”
],
‘trend_analysis’: [
“和值:”, “质合比:”, “奇偶比:”, “断区推荐:”, “连号推荐:”,
“冷热推荐:”, “后区热号:”, “后区冷号:”, “趋势号:”
],
‘number_generation’: [ # 修正为小写
“胆码:”, “前区:”, “后区:”, “推荐5注号码:”,
“1:”, “”, “2:”, “”, “3:”, “”, “4:”, “”, “5:”, “”
],
}
# 初始化所有模块的条目引用
self.front_dan_entry = None
self.back_dan_entry = None
self.result_text = None
self.exclude_front_entry = None
self.exclude_back_entry = None
self.front_entry = None
self.back_entry = None
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) 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 = 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 ) 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 _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): formatted_num = f"{int(num):02d}" if num.isdigit() else num self.exclude_front_entries[i].delete(0, 'end') self.exclude_front_entries[i].insert(0, formatted_num) # 恢复后区排除号码 if 'exclude_back' in saved_data: for i, num in enumerate(saved_data['exclude_back']): if i < len(self.exclude_back_entries): formatted_num = f"{int(num):02d}" if num.isdigit() else num self.exclude_back_entries[i].delete(0, 'end') self.exclude_back_entries[i].insert(0, formatted_num) except Exception as e: logging.error(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_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_infreq_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): """创建跟随分析模块的特定内容(修复版)""" content_frame = Frame(parent) content_frame.pack(fill='both', expand=True, padx=10, pady=10) # 使用预定义的labels(确保不重复创建按钮) for label in self.labels['follow_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) # 结果显示区(不包含按钮) 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.consec_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): """运行指定模块(增加模块ID标识)""" if module == "input_analysis": # 获取并格式化排除号码 exclude_front_list = [] for entry in self.exclude_front_entries: num = entry.get() if num: # 只处理非空输入 formatted = self._format_number(num) exclude_front_list.append(formatted) exclude_back_list = [] for entry in self.exclude_back_entries: num = entry.get() if num: # 只处理非空输入 formatted = self._format_number(num) exclude_back_list.append(formatted) exclude_front = ' '.join(exclude_front_list) exclude_back = ' '.join(exclude_back_list) # 发布排除号码事件(包含模块ID) 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, 'module_id': GlobalConfig.MODULE1_ID # 添加模块ID } ) 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, data={ 'exclude_front': exclude_front, 'exclude_back': exclude_back } ) event_center.publish(run_event) # 生成推荐号码 self._generate_recommend_numbers(exclude_front, exclude_back) 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": 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') 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_infreq_rec_entry') and self.back_infreq_rec_entry: self.back_infreq_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 = {} if module == "input_analysis": # 收集排除号码 exclude_front_list = [] for entry in self.exclude_front_entries: num = entry.get() if num: exclude_front_list.append(num) exclude_back_list = [] for entry in self.exclude_back_entries: num = entry.get() if num: exclude_back_list.append(num) 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 # 修复路径变量名 with open(filename, 'w', encoding='utf-8') as f: json.dump(data, f, indent=2, ensure_ascii=False) messagebox.showinfo("保存成功", f"排除号码已保存到{filename}") elif module == "combination_analysis": # 其他模块的保存逻辑... pass 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 = GlobalConfig.MODULE1_SAVE_PATH 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_exclude_numbers(self, event: Event): """处理排除号码事件""" if event.data: exclude_front = event.data.get('exclude_front', '') exclude_back = event.data.get('exclude_back', '') # 更新排除号码显示 self.exclude_front_entry.delete(0, 'end') self.exclude_front_entry.insert(0, exclude_front) self.exclude_back_entry.delete(0, 'end') self.exclude_back_entry.insert(0, exclude_back) # 在结果文本中记录 self.result_text.insert('end', f"收到排除号码: 前区 {exclude_front}, 后区 {exclude_back}\n") 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 _on_module_renovate(self, module: str): """刷新模块""" if module == self.current_module: self._on_module_button_click(module) 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', [])))
==================== 主程序 ====================
def main():
try:
root = Tk()
root.geometry(“1200x800”)
# 初始化核心组件 pool = NumberPool() app.main_ui = MainInterface(root, pool) # 初始化所有模块 modules = { 'input_analysis': InputAnalysisModule, 'combination_analysis': CombinationAnalysisModule, 'follow_analysis': FollowAnalysisModule, 'trend_analysis': TrendAnalysisModule, 'number_generation': NumberGenerationModule } # 先创建所有模块实例 module_instances = {} for name, cls in modules.items(): module_instances[name] = cls(name) time.sleep(0.1) # 确保顺序初始化 root.mainloop() except Exception as e: logging.error(f"系统启动失败: {str(e)}", exc_info=True) sys.exit(1)
if name == “main”:
main()
最新发布