打造现代化雷达电子对抗仿真界面 第三篇:综合电子战指挥控制台——多视图协同与插件化架构

摘要

本文将构建一个功能完整的综合电子战指挥控制台,重点展示tkinter/ttk在多视图协同、实时数据流处理、插件化架构和高级主题引擎方面的能力。通过实现一个具有多个功能视图、可动态加载插件、支持实时数据可视化的现代化指挥控制台,展示如何利用Python标准库构建专业级、可扩展的复杂应用系统。

目录

  1. 引言:综合电子战指挥控制台的需求与挑战

  2. 系统架构设计

  3. 多视图协同显示系统实现

  4. 实时数据流处理框架

  5. 插件化架构设计与实现

  6. 高级主题引擎与皮肤系统

  7. 分布式系统架构概念

  8. 系统集成与测试

  9. 性能优化与部署

  10. 总结与展望


1. 引言:综合电子战指挥控制台的需求与挑战

1.1 需求分析

综合电子战指挥控制台是现代电子战系统的核心,需要满足以下关键需求:

1.2 技术挑战

  1. 复杂布局管理:多个视图的布局、拖拽调整、最大化/最小化

  2. 实时性能:保证大量数据实时刷新时的界面流畅性

  3. 模块化设计:实现高内聚、低耦合的插件系统

  4. 可扩展性:方便未来功能扩展和定制

  5. 数据一致性:多视图间的数据同步和一致性维护

2. 系统架构设计

2.1 整体架构

python 复制代码
"""
ewcc_architecture.py

综合电子战指挥控制台架构设计
"""
from abc import ABC, abstractmethod
from typing import Dict, List, Any, Optional, Callable, Set
from enum import Enum
from dataclasses import dataclass, field
import threading
import queue
import time
from datetime import datetime

class ComponentType(Enum):
    """组件类型"""
    CORE = "core"           # 核心组件
    PLUGIN = "plugin"       # 插件组件
    VIEW = "view"          # 视图组件
    SERVICE = "service"    # 服务组件
    WIDGET = "widget"      # 控件组件

class ComponentState(Enum):
    """组件状态"""
    UNINITIALIZED = "uninitialized"  # 未初始化
    INITIALIZING = "initializing"    # 初始化中
    RUNNING = "running"              # 运行中
    PAUSED = "paused"                # 已暂停
    STOPPED = "stopped"              # 已停止
    ERROR = "error"                  # 错误状态

@dataclass
class ComponentInfo:
    """组件信息"""
    id: str
    name: str
    type: ComponentType
    version: str
    description: str
    author: str
    dependencies: List[str] = field(default_factory=list)
    state: ComponentState = ComponentState.UNINITIALIZED
    config: Dict[str, Any] = field(default_factory=dict)
    
class EventType(Enum):
    """事件类型"""
    SYSTEM_START = "system_start"
    SYSTEM_STOP = "system_stop"
    DATA_UPDATE = "data_update"
    VIEW_CREATE = "view_create"
    VIEW_DESTROY = "view_destroy"
    PLUGIN_LOAD = "plugin_load"
    PLUGIN_UNLOAD = "plugin_unload"
    ALERT = "alert"
    COMMAND = "command"

@dataclass
class Event:
    """事件对象"""
    id: str
    type: EventType
    source: str
    target: str = ""
    timestamp: float = field(default_factory=time.time)
    data: Dict[str, Any] = field(default_factory=dict)
    priority: int = 1  # 优先级: 1-最低, 5-最高
    
class BaseComponent(ABC):
    """组件基类"""
    
    def __init__(self, info: ComponentInfo):
        self.info = info
        self.event_handlers: Dict[EventType, List[Callable]] = {}
        self.message_queue = queue.Queue()
        self.running = False
        self.thread: Optional[threading.Thread] = None
        
    @abstractmethod
    def initialize(self, config: Dict[str, Any]) -> bool:
        """初始化组件"""
        pass
        
    @abstractmethod
    def start(self) -> bool:
        """启动组件"""
        pass
        
    @abstractmethod
    def stop(self) -> bool:
        """停止组件"""
        pass
        
    @abstractmethod
    def process_message(self, message: Any):
        """处理消息"""
        pass
        
    def register_handler(self, event_type: EventType, handler: Callable):
        """注册事件处理函数"""
        if event_type not in self.event_handlers:
            self.event_handlers[event_type] = []
        self.event_handlers[event_type].append(handler)
        
    def emit_event(self, event: Event):
        """发送事件"""
        if event.type in self.event_handlers:
            for handler in self.event_handlers[event.type]:
                try:
                    handler(event)
                except Exception as e:
                    print(f"事件处理错误: {e}")
                    
    def run_loop(self):
        """运行循环"""
        while self.running:
            try:
                # 处理消息
                if not self.message_queue.empty():
                    message = self.message_queue.get_nowait()
                    self.process_message(message)
                    
                # 执行组件特定逻辑
                self.update()
                
                # 休眠以避免CPU占用过高
                time.sleep(0.01)
                
            except Exception as e:
                print(f"组件 {self.info.name} 运行错误: {e}")
                
    def update(self):
        """更新组件状态(子类可重写)"""
        pass
        
class EWCCSystem:
    """综合电子战指挥控制台系统"""
    
    def __init__(self):
        self.components: Dict[str, BaseComponent] = {}
        self.event_bus = EventBus()
        self.plugin_manager = PluginManager(self)
        self.view_manager = ViewManager(self)
        self.data_bus = DataBus(self)
        self.theme_engine = ThemeEngine()
        self.command_dispatcher = CommandDispatcher(self)
        
        # 系统状态
        self.system_state = ComponentState.UNINITIALIZED
        self.start_time: Optional[float] = None
        self.performance_metrics: Dict[str, Any] = {}
        
    def initialize(self, config: Dict[str, Any]) -> bool:
        """初始化系统"""
        try:
            self.system_state = ComponentState.INITIALIZING
            
            # 1. 初始化核心组件
            core_components = [
                self.event_bus,
                self.plugin_manager,
                self.view_manager,
                self.data_bus,
                self.theme_engine,
                self.command_dispatcher
            ]
            
            for component in core_components:
                component.initialize(config)
                self.register_component(component)
                
            # 2. 加载插件
            self.plugin_manager.load_plugins()
            
            # 3. 创建默认视图
            self.view_manager.create_default_views()
            
            # 4. 启动所有组件
            for component in self.components.values():
                component.start()
                
            self.system_state = ComponentState.RUNNING
            self.start_time = time.time()
            
            return True
            
        except Exception as e:
            print(f"系统初始化失败: {e}")
            self.system_state = ComponentState.ERROR
            return False
            
    def register_component(self, component: BaseComponent):
        """注册组件"""
        self.components[component.info.id] = component
        
    def get_component(self, component_id: str) -> Optional[BaseComponent]:
        """获取组件"""
        return self.components.get(component_id)
        
    def shutdown(self):
        """关闭系统"""
        # 停止所有组件
        for component in reversed(list(self.components.values())):
            try:
                component.stop()
            except Exception as e:
                print(f"停止组件 {component.info.name} 失败: {e}")
                
        self.system_state = ComponentState.STOPPED
        
    def get_system_info(self) -> Dict[str, Any]:
        """获取系统信息"""
        return {
            "state": self.system_state.value,
            "uptime": time.time() - self.start_time if self.start_time else 0,
            "component_count": len(self.components),
            "active_plugins": len(self.plugin_manager.get_active_plugins()),
            "active_views": len(self.view_manager.get_active_views()),
            "performance": self.performance_metrics
        }
        
class EventBus(BaseComponent):
    """事件总线"""
    
    def __init__(self):
        super().__init__(ComponentInfo(
            id="event_bus",
            name="事件总线",
            type=ComponentType.CORE,
            version="1.0.0",
            description="系统事件分发中心",
            author="EWCC Team"
        ))
        self.subscribers: Dict[EventType, Set[str]] = {}
        
    def initialize(self, config: Dict[str, Any]) -> bool:
        self.subscribers = {event_type: set() for event_type in EventType}
        return True
        
    def publish(self, event: Event):
        """发布事件"""
        # 这里简化实现,实际中会发送给所有订阅者
        pass
        
    def subscribe(self, event_type: EventType, component_id: str):
        """订阅事件"""
        if event_type in self.subscribers:
            self.subscribers[event_type].add(component_id)
            
    def unsubscribe(self, event_type: EventType, component_id: str):
        """取消订阅"""
        if event_type in self.subscribers:
            self.subscribers[event_type].discard(component_id)
            
class DataBus(BaseComponent):
    """数据总线"""
    
    def __init__(self, system: EWCCSystem):
        super().__init__(ComponentInfo(
            id="data_bus",
            name="数据总线",
            type=ComponentType.CORE,
            version="1.0.0",
            description="系统数据交换中心",
            author="EWCC Team"
        ))
        self.system = system
        self.data_channels: Dict[str, List[Callable]] = {}
        
    def initialize(self, config: Dict[str, Any]) -> bool:
        return True
        
    def register_channel(self, channel_id: str, handler: Callable):
        """注册数据通道"""
        if channel_id not in self.data_channels:
            self.data_channels[channel_id] = []
        self.data_channels[channel_id].append(handler)
        
    def send_data(self, channel_id: str, data: Any):
        """发送数据"""
        if channel_id in self.data_channels:
            for handler in self.data_channels[channel_id]:
                try:
                    handler(data)
                except Exception as e:
                    print(f"数据处理错误: {e}")

# 其他核心组件的简化定义
class PluginManager(BaseComponent):
    """插件管理器"""
    def __init__(self, system: EWCCSystem):
        super().__init__(ComponentInfo(
            id="plugin_manager",
            name="插件管理器",
            type=ComponentType.CORE,
            version="1.0.0",
            description="管理插件加载和卸载",
            author="EWCC Team"
        ))
        self.system = system
        self.plugins: Dict[str, BaseComponent] = {}
        
    def load_plugins(self):
        """加载插件"""
        pass
        
    def get_active_plugins(self) -> List[str]:
        """获取活动插件列表"""
        return list(self.plugins.keys())
        
class ViewManager(BaseComponent):
    """视图管理器"""
    def __init__(self, system: EWCCSystem):
        super().__init__(ComponentInfo(
            id="view_manager",
            name="视图管理器",
            type=ComponentType.CORE,
            version="1.0.0",
            description="管理视图创建和布局",
            author="EWCC Team"
        ))
        self.system = system
        self.views: Dict[str, Any] = {}
        
    def create_default_views(self):
        """创建默认视图"""
        pass
        
    def get_active_views(self) -> List[str]:
        """获取活动视图列表"""
        return list(self.views.keys())
        
class ThemeEngine(BaseComponent):
    """主题引擎"""
    def __init__(self):
        super().__init__(ComponentInfo(
            id="theme_engine",
            name="主题引擎",
            type=ComponentType.CORE,
            version="1.0.0",
            description="管理界面主题和皮肤",
            author="EWCC Team"
        ))
        self.current_theme = "default"
        
class CommandDispatcher(BaseComponent):
    """命令分发器"""
    def __init__(self, system: EWCCSystem):
        super().__init__(ComponentInfo(
            id="command_dispatcher",
            name="命令分发器",
            type=ComponentType.CORE,
            version="1.0.0",
            description="处理系统命令",
            author="EWCC Team"
        ))
        self.system = system

2.2 架构图示

3. 多视图协同显示系统实现

3.1 视图管理器完整实现

python 复制代码
"""
view_manager.py

多视图协同显示系统
"""
import tkinter as tk
from tkinter import ttk
from typing import Dict, List, Any, Optional, Tuple, Callable
from enum import Enum
from dataclasses import dataclass, field
import json
import pickle
from abc import ABC, abstractmethod

class ViewType(Enum):
    """视图类型"""
    BATTLEFIELD = "battlefield"      # 战场态势
    SPECTRUM = "spectrum"            # 频谱监测
    RESOURCE = "resource"            # 资源管理
    LOG = "log"                      # 日志信息
    ALERT = "alert"                  # 告警显示
    ANALYSIS = "analysis"            # 分析视图
    CUSTOM = "custom"                # 自定义视图

class ViewState(Enum):
    """视图状态"""
    HIDDEN = "hidden"      # 隐藏
    NORMAL = "normal"      # 正常
    MAXIMIZED = "maximized"  # 最大化
    MINIMIZED = "minimized"  # 最小化
    DOCKED = "docked"      # 停靠
    FLOATING = "floating"  # 浮动

@dataclass
class ViewConfig:
    """视图配置"""
    id: str
    type: ViewType
    title: str
    position: Tuple[int, int] = (0, 0)  # (x, y)
    size: Tuple[int, int] = (400, 300)  # (width, height)
    state: ViewState = ViewState.NORMAL
    z_order: int = 0
    visible: bool = True
    dock_area: Optional[str] = None
    config: Dict[str, Any] = field(default_factory=dict)
    
class BaseView(ABC):
    """视图基类"""
    
    def __init__(self, config: ViewConfig):
        self.config = config
        self.frame: Optional[ttk.Frame] = None
        self.widgets: Dict[str, tk.Widget] = {}
        self.data_sources: List[str] = []
        self.event_handlers: Dict[str, List[Callable]] = {}
        
    @abstractmethod
    def create_ui(self, parent: tk.Widget):
        """创建UI界面"""
        pass
        
    @abstractmethod
    def update_data(self, data: Dict[str, Any]):
        """更新数据"""
        pass
        
    def show(self):
        """显示视图"""
        if self.frame:
            self.frame.pack(fill=tk.BOTH, expand=True)
            
    def hide(self):
        """隐藏视图"""
        if self.frame:
            self.frame.pack_forget()
            
    def destroy(self):
        """销毁视图"""
        if self.frame:
            self.frame.destroy()
            
    def register_event_handler(self, event_type: str, handler: Callable):
        """注册事件处理函数"""
        if event_type not in self.event_handlers:
            self.event_handlers[event_type] = []
        self.event_handlers[event_type].append(handler)
        
    def emit_event(self, event_type: str, data: Any = None):
        """触发事件"""
        if event_type in self.event_handlers:
            for handler in self.event_handlers[event_type]:
                try:
                    handler(data)
                except Exception as e:
                    print(f"事件处理错误: {e}")
                    
class ViewManager:
    """视图管理器"""
    
    def __init__(self, parent: tk.Widget):
        self.parent = parent
        self.views: Dict[str, BaseView] = {}
        self.view_frames: Dict[str, tk.Widget] = {}
        self.layout_engine = LayoutEngine()
        self.current_layout = "default"
        self.dock_manager = DockManager(parent)
        
        # 视图注册表
        self.view_registry: Dict[ViewType, type] = {}
        
        # 注册内置视图类型
        self.register_view_type(ViewType.BATTLEFIELD, BattlefieldView)
        self.register_view_type(ViewType.SPECTRUM, SpectrumView)
        self.register_view_type(ViewType.RESOURCE, ResourceView)
        self.register_view_type(ViewType.LOG, LogView)
        self.register_view_type(ViewType.ALERT, AlertView)
        self.register_view_type(ViewType.ANALYSIS, AnalysisView)
        
    def register_view_type(self, view_type: ViewType, view_class: type):
        """注册视图类型"""
        self.view_registry[view_type] = view_class
        
    def create_view(self, config: ViewConfig) -> BaseView:
        """创建视图"""
        if config.type not in self.view_registry:
            raise ValueError(f"未注册的视图类型: {config.type}")
            
        # 创建视图实例
        view_class = self.view_registry[config.type]
        view = view_class(config)
        
        # 创建容器框架
        container = self._create_view_container(view.config)
        view.frame = container
        
        # 创建UI
        view.create_ui(container)
        
        # 存储视图
        self.views[config.id] = view
        self.view_frames[config.id] = container
        
        return view
        
    def _create_view_container(self, config: ViewConfig) -> tk.Widget:
        """创建视图容器"""
        if config.state == ViewState.DOCKED and config.dock_area:
            # 创建停靠容器
            return self.dock_manager.create_dock_container(
                config.id, config.title, config.dock_area
            )
        elif config.state == ViewState.FLOATING:
            # 创建浮动窗口
            return self._create_floating_window(config)
        else:
            # 创建普通框架
            frame = ttk.Frame(self.parent)
            
            # 添加标题栏
            self._add_title_bar(frame, config.title, config.id)
            
            return frame
            
    def _add_title_bar(self, parent: tk.Widget, title: str, view_id: str):
        """添加标题栏"""
        title_bar = ttk.Frame(parent)
        title_bar.pack(fill=tk.X, padx=1, pady=(1, 0))
        
        # 标题
        ttk.Label(title_bar, text=title, font=("微软雅黑", 10)).pack(side=tk.LEFT, padx=5)
        
        # 控制按钮
        btn_frame = ttk.Frame(title_bar)
        btn_frame.pack(side=tk.RIGHT)
        
        buttons = [
            ("🗕", lambda: self.minimize_view(view_id)),
            ("🗖", lambda: self.maximize_view(view_id)),
            ("✕", lambda: self.close_view(view_id))
        ]
        
        for text, command in buttons:
            btn = ttk.Button(btn_frame, text=text, width=3, command=command)
            btn.pack(side=tk.LEFT, padx=1)
            
    def _create_floating_window(self, config: ViewConfig) -> tk.Toplevel:
        """创建浮动窗口"""
        window = tk.Toplevel(self.parent)
        window.title(config.title)
        window.geometry(f"{config.size[0]}x{config.size[1]}+{config.position[0]}+{config.position[1]}")
        
        # 设置窗口属性
        window.transient(self.parent)
        window.grab_set()
        
        return window
        
    def close_view(self, view_id: str):
        """关闭视图"""
        if view_id in self.views:
            view = self.views[view_id]
            view.destroy()
            del self.views[view_id]
            del self.view_frames[view_id]
            
    def minimize_view(self, view_id: str):
        """最小化视图"""
        if view_id in self.view_frames:
            frame = self.view_frames[view_id]
            frame.pack_forget()
            
    def maximize_view(self, view_id: str):
        """最大化视图"""
        if view_id in self.views:
            view = self.views[view_id]
            if view.config.state == ViewState.MAXIMIZED:
                # 恢复原大小
                self._restore_view(view)
            else:
                # 最大化
                self._maximize_view(view)
                
    def _maximize_view(self, view: BaseView):
        """最大化视图"""
        # 保存原状态
        view.config.state = ViewState.MAXIMIZED
        
        # 隐藏其他视图
        for other_id, other_view in self.views.items():
            if other_id != view.config.id:
                other_view.hide()
                
        # 最大化当前视图
        if view.frame:
            view.frame.pack(fill=tk.BOTH, expand=True)
            
    def _restore_view(self, view: BaseView):
        """恢复视图"""
        view.config.state = ViewState.NORMAL
        self.apply_layout(self.current_layout)
        
    def apply_layout(self, layout_name: str):
        """应用布局"""
        layout = self.layout_engine.load_layout(layout_name)
        if layout:
            self.current_layout = layout_name
            self._apply_layout_config(layout)
            
    def _apply_layout_config(self, layout: Dict[str, Any]):
        """应用布局配置"""
        # 清除现有布局
        for frame in self.view_frames.values():
            frame.pack_forget()
            
        # 应用新布局
        for view_config in layout.get("views", []):
            view_id = view_config.get("id")
            if view_id in self.views:
                view = self.views[view_id]
                config = view_config.get("config", {})
                
                # 更新视图位置和大小
                if "position" in config:
                    view.config.position = tuple(config["position"])
                if "size" in config:
                    view.config.size = tuple(config["size"])
                    
                # 应用布局
                self._place_view(view, config)
                
    def _place_view(self, view: BaseView, config: Dict[str, Any]):
        """放置视图"""
        if view.frame:
            pack_config = config.get("pack", {})
            grid_config = config.get("grid", {})
            place_config = config.get("place", {})
            
            if pack_config:
                view.frame.pack(**pack_config)
            elif grid_config:
                view.frame.grid(**grid_config)
            elif place_config:
                view.frame.place(**place_config)
                
    def save_layout(self, layout_name: str):
        """保存布局"""
        layout = {
            "name": layout_name,
            "timestamp": time.time(),
            "views": []
        }
        
        for view_id, view in self.views.items():
            view_config = {
                "id": view_id,
                "type": view.config.type.value,
                "config": {
                    "position": view.config.position,
                    "size": view.config.size,
                    "state": view.config.state.value
                }
            }
            layout["views"].append(view_config)
            
        self.layout_engine.save_layout(layout_name, layout)
        
    def get_view(self, view_id: str) -> Optional[BaseView]:
        """获取视图"""
        return self.views.get(view_id)
        
    def get_all_views(self) -> List[BaseView]:
        """获取所有视图"""
        return list(self.views.values())
        
    def update_all_views(self, data: Dict[str, Any]):
        """更新所有视图"""
        for view in self.views.values():
            try:
                view.update_data(data)
            except Exception as e:
                print(f"更新视图 {view.config.id} 失败: {e}")
                
class LayoutEngine:
    """布局引擎"""
    
    def __init__(self):
        self.layouts: Dict[str, Dict] = {}
        self.load_builtin_layouts()
        
    def load_builtin_layouts(self):
        """加载内置布局"""
        self.layouts["default"] = {
            "name": "default",
            "description": "默认布局",
            "views": [
                {
                    "id": "battlefield",
                    "type": "battlefield",
                    "config": {
                        "grid": {"row": 0, "column": 0, "sticky": "nsew", "rowspan": 2}
                    }
                },
                {
                    "id": "spectrum",
                    "type": "spectrum", 
                    "config": {
                        "grid": {"row": 0, "column": 1, "sticky": "nsew"}
                    }
                },
                {
                    "id": "resource",
                    "type": "resource",
                    "config": {
                        "grid": {"row": 1, "column": 1, "sticky": "nsew"}
                    }
                }
            ]
        }
        
    def load_layout(self, layout_name: str) -> Optional[Dict]:
        """加载布局"""
        if layout_name in self.layouts:
            return self.layouts[layout_name]
        return None
        
    def save_layout(self, layout_name: str, layout: Dict):
        """保存布局"""
        self.layouts[layout_name] = layout
        
class DockManager:
    """停靠管理器"""
    
    def __init__(self, parent: tk.Widget):
        self.parent = parent
        self.dock_areas: Dict[str, ttk.PanedWindow] = {}
        self.dock_widgets: Dict[str, List[str]] = {}
        
    def create_dock_area(self, area_id: str, orientation: str = "horizontal"):
        """创建停靠区域"""
        paned = ttk.PanedWindow(self.parent, orient=orientation)
        self.dock_areas[area_id] = paned
        self.dock_widgets[area_id] = []
        return paned
        
    def create_dock_container(self, view_id: str, title: str, area_id: str) -> tk.Widget:
        """创建停靠容器"""
        if area_id not in self.dock_areas:
            self.create_dock_area(area_id)
            
        # 创建可停靠框架
        frame = ttk.Frame(self.dock_areas[area_id])
        
        # 添加标题栏
        title_bar = ttk.Frame(frame)
        title_bar.pack(fill=tk.X, padx=1, pady=(1, 0))
        
        ttk.Label(title_bar, text=title).pack(side=tk.LEFT, padx=5)
        
        # 添加拖拽手柄
        ttk.Label(title_bar, text="⋮⋮", cursor="fleur").pack(side=tk.RIGHT, padx=5)
        
        # 添加到停靠区域
        self.dock_areas[area_id].add(frame)
        self.dock_widgets[area_id].append(view_id)
        
        return frame
        
# 具体视图实现示例
class BattlefieldView(BaseView):
    """战场态势视图"""
    
    def create_ui(self, parent: tk.Widget):
        # 创建主画布
        self.canvas = tk.Canvas(parent, bg="#1C2833", highlightthickness=0)
        self.canvas.pack(fill=tk.BOTH, expand=True)
        
        # 添加控制工具栏
        self._create_toolbar(parent)
        
    def _create_toolbar(self, parent: tk.Widget):
        toolbar = ttk.Frame(parent)
        toolbar.pack(fill=tk.X, padx=5, pady=5)
        
        tools = ["选择", "平移", "缩放", "测量", "标记"]
        for tool in tools:
            ttk.Button(toolbar, text=tool, width=8).pack(side=tk.LEFT, padx=2)
            
    def update_data(self, data: Dict[str, Any]):
        # 更新战场态势显示
        if "battlefield" in data:
            self._draw_battlefield(data["battlefield"])
            
    def _draw_battlefield(self, data: Dict[str, Any]):
        """绘制战场态势"""
        self.canvas.delete("all")
        
        width = self.canvas.winfo_width()
        height = self.canvas.winfo_height()
        
        if width < 10 or height < 10:
            return
            
        # 绘制网格
        self._draw_grid()
        
        # 绘制单位
        if "units" in data:
            for unit in data["units"]:
                self._draw_unit(unit)
                
        # 绘制轨迹
        if "tracks" in data:
            for track in data["tracks"]:
                self._draw_track(track)
                
    def _draw_grid(self):
        """绘制网格"""
        width = self.canvas.winfo_width()
        height = self.canvas.winfo_height()
        
        grid_size = 50
        for x in range(0, width, grid_size):
            self.canvas.create_line(x, 0, x, height, fill="#2C3E50", width=1)
        for y in range(0, height, grid_size):
            self.canvas.create_line(0, y, width, y, fill="#2C3E50", width=1)
            
    def _draw_unit(self, unit: Dict[str, Any]):
        """绘制单位"""
        x = unit.get("x", 0)
        y = unit.get("y", 0)
        unit_type = unit.get("type", "unknown")
        
        colors = {
            "friendly": "#2ECC71",
            "hostile": "#E74C3C", 
            "neutral": "#3498DB",
            "unknown": "#95A5A6"
        }
        
        color = colors.get(unit_type, "#95A5A6")
        
        # 绘制单位符号
        size = 10
        self.canvas.create_oval(x-size, y-size, x+size, y+size,
                              fill=color, outline="white", width=2)
                              
    def _draw_track(self, track: Dict[str, Any]):
        """绘制轨迹"""
        points = track.get("points", [])
        if len(points) >= 2:
            # 绘制轨迹线
            for i in range(len(points)-1):
                x1, y1 = points[i]
                x2, y2 = points[i+1]
                self.canvas.create_line(x1, y1, x2, y2,
                                      fill="#F39C12", width=2, dash=(4, 2))
                                      
class SpectrumView(BaseView):
    """频谱监测视图"""
    
    def create_ui(self, parent: tk.Widget):
        # 创建频谱显示区域
        self.canvas = tk.Canvas(parent, bg="#0F1C2E", highlightthickness=0)
        self.canvas.pack(fill=tk.BOTH, expand=True)
        
        # 创建控制面板
        self._create_control_panel(parent)
        
    def _create_control_panel(self, parent: tk.Widget):
        control_frame = ttk.Frame(parent)
        control_frame.pack(fill=tk.X, padx=5, pady=5)
        
        # 频率范围控制
        ttk.Label(control_frame, text="频率(MHz):").pack(side=tk.LEFT, padx=5)
        
        self.freq_start = ttk.Entry(control_frame, width=10)
        self.freq_start.insert(0, "1000")
        self.freq_start.pack(side=tk.LEFT, padx=2)
        
        ttk.Label(control_frame, text="-").pack(side=tk.LEFT)
        
        self.freq_end = ttk.Entry(control_frame, width=10)
        self.freq_end.insert(0, "3000")
        self.freq_end.pack(side=tk.LEFT, padx=2)
        
        # 更新按钮
        ttk.Button(control_frame, text="更新", command=self.update_spectrum).pack(side=tk.LEFT, padx=10)
        
    def update_data(self, data: Dict[str, Any]):
        if "spectrum" in data:
            self._draw_spectrum(data["spectrum"])
            
    def _draw_spectrum(self, data: Dict[str, Any]):
        """绘制频谱"""
        self.canvas.delete("all")
        
        width = self.canvas.winfo_width()
        height = self.canvas.winfo_height()
        
        if width < 10 or height < 10:
            return
            
        frequencies = data.get("frequencies", [])
        amplitudes = data.get("amplitudes", [])
        
        if not frequencies or not amplitudes:
            return
            
        # 计算坐标映射
        x_scale = width / (max(frequencies) - min(frequencies))
        y_scale = height / (max(amplitudes) - min(amplitudes)) if max(amplitudes) > min(amplitudes) else 1
        
        # 绘制频谱曲线
        points = []
        for i, (freq, amp) in enumerate(zip(frequencies, amplitudes)):
            x = (freq - min(frequencies)) * x_scale
            y = height - (amp - min(amplitudes)) * y_scale
            points.extend([x, y])
            
        if len(points) >= 4:
            self.canvas.create_line(points, fill="#2ECC71", width=2, smooth=True)
            
        # 绘制频率网格
        self._draw_frequency_grid(frequencies, width, height)
        
    def _draw_frequency_grid(self, frequencies, width, height):
        """绘制频率网格"""
        if not frequencies:
            return
            
        freq_min = min(frequencies)
        freq_max = max(frequencies)
        
        # 计算主要频率刻度
        freq_range = freq_max - freq_min
        major_step = 10 ** (int(freq_range / 10))
        
        for freq in range(int(freq_min), int(freq_max) + 1, major_step):
            if freq_min <= freq <= freq_max:
                x = (freq - freq_min) / (freq_max - freq_min) * width
                self.canvas.create_line(x, 0, x, height, fill="#2C3E50", width=1)
                self.canvas.create_text(x, height-15, text=f"{freq}MHz",
                                       fill="#7F8C8D", font=("Arial", 8))
                                       
    def update_spectrum(self):
        """更新频谱显示"""
        # 这里可以触发数据更新
        self.emit_event("spectrum_update", {
            "start": float(self.freq_start.get()),
            "end": float(self.freq_end.get())
        })

# 其他视图的简化定义
class ResourceView(BaseView):
    """资源管理视图"""
    def create_ui(self, parent: tk.Widget):
        self.tree = ttk.Treeview(parent, columns=("状态", "类型", "位置"), show="tree headings")
        self.tree.pack(fill=tk.BOTH, expand=True)
        
    def update_data(self, data: Dict[str, Any]):
        pass
        
class LogView(BaseView):
    """日志信息视图"""
    def create_ui(self, parent: tk.Widget):
        self.text = tk.Text(parent, bg="#1C2833", fg="#ECF0F1", font=("Consolas", 10))
        scrollbar = ttk.Scrollbar(parent, orient=tk.VERTICAL, command=self.text.yview)
        self.text.configure(yscrollcommand=scrollbar.set)
        
        self.text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
    def update_data(self, data: Dict[str, Any]):
        if "log" in data:
            self.text.insert(tk.END, f"{data['log']}\n")
            self.text.see(tk.END)
            
class AlertView(BaseView):
    """告警显示视图"""
    def create_ui(self, parent: tk.Widget):
        self.listbox = tk.Listbox(parent, bg="#1C2833", fg="#ECF0F1", font=("Consolas", 10))
        scrollbar = ttk.Scrollbar(parent, orient=tk.VERTICAL, command=self.listbox.yview)
        self.listbox.configure(yscrollcommand=scrollbar.set)
        
        self.listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
    def update_data(self, data: Dict[str, Any]):
        if "alert" in data:
            self.listbox.insert(0, f"[{data.get('time', '')}] {data['alert']}")
            
class AnalysisView(BaseView):
    """分析视图"""
    def create_ui(self, parent: tk.Widget):
        self.canvas = tk.Canvas(parent, bg="#1C2833", highlightthickness=0)
        self.canvas.pack(fill=tk.BOTH, expand=True)
        
    def update_data(self, data: Dict[str, Any]):
        pass

3.2 视图协同与通信机制

python 复制代码
"""
view_coordination.py

视图协同与通信机制
"""
import threading
import queue
import time
from typing import Dict, List, Any, Optional, Set
from enum import Enum
from dataclasses import dataclass

class CoordinationMode(Enum):
    """协同模式"""
    INDEPENDENT = "independent"  # 独立
    LINKED = "linked"            # 链接
    SYNC = "sync"               # 同步
    MASTER_SLAVE = "master_slave"  # 主从

@dataclass
class ViewLink:
    """视图链接"""
    source_view: str
    target_view: str
    link_type: str
    data_fields: List[str]
    update_mode: str = "push"  # push, pull, both
    
class ViewCoordinator:
    """视图协调器"""
    
    def __init__(self):
        self.links: Dict[str, List[ViewLink]] = {}
        self.coordination_groups: Dict[str, Set[str]] = {}
        self.data_cache: Dict[str, Any] = {}
        self.message_queue = queue.Queue()
        self.running = False
        
    def add_link(self, link: ViewLink):
        """添加视图链接"""
        if link.source_view not in self.links:
            self.links[link.source_view] = []
        self.links[link.source_view].append(link)
        
    def remove_link(self, source_view: str, target_view: str):
        """移除视图链接"""
        if source_view in self.links:
            self.links[source_view] = [
                link for link in self.links[source_view] 
                if link.target_view != target_view
            ]
            
    def create_coordination_group(self, group_id: str, view_ids: List[str]):
        """创建协同组"""
        self.coordination_groups[group_id] = set(view_ids)
        
    def coordinate_views(self, source_view_id: str, data: Dict[str, Any]):
        """协调视图"""
        if source_view_id in self.links:
            for link in self.links[source_view_id]:
                self._propagate_data(link, data)
                
    def _propagate_data(self, link: ViewLink, data: Dict[str, Any]):
        """传播数据"""
        filtered_data = {}
        for field in link.data_fields:
            if field in data:
                filtered_data[field] = data[field]
                
        if filtered_data:
            # 在实际应用中,这里会调用目标视图的更新方法
            self.message_queue.put({
                "target": link.target_view,
                "data": filtered_data,
                "link_type": link.link_type
            })
            
    def start(self):
        """启动协调器"""
        self.running = True
        self.thread = threading.Thread(target=self._run, daemon=True)
        self.thread.start()
        
    def stop(self):
        """停止协调器"""
        self.running = False
        
    def _run(self):
        """运行协调器"""
        while self.running:
            try:
                message = self.message_queue.get(timeout=0.1)
                self._process_message(message)
            except queue.Empty:
                continue
                
    def _process_message(self, message: Dict[str, Any]):
        """处理消息"""
        # 这里会调用具体的视图更新方法
        target_view = message["target"]
        data = message["data"]
        link_type = message["link_type"]
        
        # 在实际系统中,这里会分发到具体的视图
        print(f"协调器: 向视图 {target_view} 发送 {link_type} 数据: {data}")
        
class ViewSyncManager:
    """视图同步管理器"""
    
    def __init__(self):
        self.sync_groups: Dict[str, Dict] = {}
        self.view_states: Dict[str, Dict] = {}
        
    def create_sync_group(self, group_id: str, config: Dict[str, Any]):
        """创建同步组"""
        self.sync_groups[group_id] = {
            "config": config,
            "views": set(),
            "sync_data": {}
        }
        
    def add_view_to_sync(self, group_id: str, view_id: str):
        """添加视图到同步组"""
        if group_id in self.sync_groups:
            self.sync_groups[group_id]["views"].add(view_id)
            
    def sync_view_state(self, view_id: str, state: Dict[str, Any]):
        """同步视图状态"""
        self.view_states[view_id] = state
        
        # 找到视图所在的同步组
        for group_id, group in self.sync_groups.items():
            if view_id in group["views"]:
                self._propagate_sync(group_id, view_id, state)
                
    def _propagate_sync(self, group_id: str, source_view: str, state: Dict[str, Any]):
        """传播同步"""
        group = self.sync_groups[group_id]
        sync_config = group["config"]
        
        for view_id in group["views"]:
            if view_id != source_view:
                # 根据配置同步状态
                sync_data = self._prepare_sync_data(state, sync_config)
                
                # 发送同步数据
                self._send_sync_data(view_id, sync_data)
                
    def _prepare_sync_data(self, state: Dict[str, Any], config: Dict[str, Any]) -> Dict[str, Any]:
        """准备同步数据"""
        sync_data = {}
        
        # 根据配置过滤和转换数据
        sync_fields = config.get("sync_fields", [])
        if sync_fields:
            for field in sync_fields:
                if field in state:
                    sync_data[field] = state[field]
        else:
            # 同步所有字段
            sync_data = state.copy()
            
        return sync_data
        
    def _send_sync_data(self, view_id: str, data: Dict[str, Any]):
        """发送同步数据"""
        # 在实际系统中,这里会调用视图的同步方法
        print(f"同步管理器: 向视图 {view_id} 发送同步数据")

4. 实时数据流处理框架

4.1 数据流水线架构

python 复制代码
"""
data_pipeline.py

实时数据流处理框架
"""
import asyncio
import threading
import queue
import time
from typing import Dict, List, Any, Optional, Callable, Set
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from enum import Enum
import numpy as np
from collections import deque
import json

class DataType(Enum):
    """数据类型"""
    TELEMETRY = "telemetry"      # 遥测数据
    SPECTRUM = "spectrum"        # 频谱数据
    TARGET = "target"           # 目标数据
    ALERT = "alert"             # 告警数据
    LOG = "log"                 # 日志数据
    COMMAND = "command"         # 命令数据
    STATUS = "status"           # 状态数据

class ProcessingStage(Enum):
    """处理阶段"""
    RAW = "raw"                 # 原始数据
    FILTERED = "filtered"       # 滤波后
    ENHANCED = "enhanced"       # 增强后
    ANALYZED = "analyzed"       # 分析后
    VISUALIZED = "visualized"   # 可视化

@dataclass
class DataPacket:
    """数据包"""
    id: str
    type: DataType
    source: str
    timestamp: float = field(default_factory=time.time)
    data: Any = None
    metadata: Dict[str, Any] = field(default_factory=dict)
    processing_stage: ProcessingStage = ProcessingStage.RAW
    
@dataclass
class PipelineConfig:
    """流水线配置"""
    name: str
    stages: List[str]
    buffer_size: int = 1000
    processing_rate: float = 100.0  # Hz
    parallel_workers: int = 1
    
class DataSource(ABC):
    """数据源基类"""
    
    def __init__(self, source_id: str, config: Dict[str, Any]):
        self.source_id = source_id
        self.config = config
        self.callbacks: List[Callable] = []
        self.running = False
        self.data_count = 0
        
    @abstractmethod
    def start(self):
        """启动数据源"""
        pass
        
    @abstractmethod
    def stop(self):
        """停止数据源"""
        pass
        
    def register_callback(self, callback: Callable):
        """注册回调函数"""
        self.callbacks.append(callback)
        
    def emit_data(self, data: Any, metadata: Optional[Dict] = None):
        """发射数据"""
        packet = DataPacket(
            id=f"{self.source_id}_{self.data_count}",
            type=DataType.TELEMETRY,
            source=self.source_id,
            data=data,
            metadata=metadata or {}
        )
        
        for callback in self.callbacks:
            try:
                callback(packet)
            except Exception as e:
                print(f"数据源 {self.source_id} 回调错误: {e}")
                
        self.data_count += 1
        
class ProcessingStageBase(ABC):
    """处理阶段基类"""
    
    def __init__(self, stage_id: str, config: Dict[str, Any]):
        self.stage_id = stage_id
        self.config = config
        self.input_queue = queue.Queue(maxsize=1000)
        self.output_queue = queue.Queue(maxsize=1000)
        self.running = False
        self.processing_time = 0.0
        self.processed_count = 0
        
    @abstractmethod
    def process(self, packet: DataPacket) -> DataPacket:
        """处理数据包"""
        pass
        
    def start(self):
        """启动处理阶段"""
        self.running = True
        self.thread = threading.Thread(target=self._run, daemon=True)
        self.thread.start()
        
    def stop(self):
        """停止处理阶段"""
        self.running = False
        
    def _run(self):
        """运行处理循环"""
        while self.running:
            try:
                packet = self.input_queue.get(timeout=0.1)
                
                start_time = time.time()
                processed_packet = self.process(packet)
                processing_time = time.time() - start_time
                
                self.processing_time += processing_time
                self.processed_count += 1
                
                self.output_queue.put(processed_packet)
                
            except queue.Empty:
                continue
            except Exception as e:
                print(f"处理阶段 {self.stage_id} 错误: {e}")
                
    def get_stats(self) -> Dict[str, Any]:
        """获取统计信息"""
        avg_time = self.processing_time / self.processed_count if self.processed_count > 0 else 0
        queue_size = self.input_queue.qsize()
        
        return {
            "processed_count": self.processed_count,
            "avg_processing_time": avg_time,
            "input_queue_size": queue_size,
            "throughput": self.processed_count / (time.time() - self.start_time) 
                         if hasattr(self, 'start_time') else 0
        }
        
class FilterStage(ProcessingStageBase):
    """滤波阶段"""
    
    def __init__(self, stage_id: str, config: Dict[str, Any]):
        super().__init__(stage_id, config)
        self.filter_type = config.get("filter_type", "lowpass")
        self.filter_params = config.get("filter_params", {})
        
    def process(self, packet: DataPacket) -> DataPacket:
        # 应用滤波器
        if isinstance(packet.data, np.ndarray):
            filtered_data = self._apply_filter(packet.data)
        else:
            filtered_data = packet.data
            
        return DataPacket(
            id=packet.id + "_filtered",
            type=packet.type,
            source=packet.source,
            timestamp=packet.timestamp,
            data=filtered_data,
            metadata={**packet.metadata, "filter_type": self.filter_type},
            processing_stage=ProcessingStage.FILTERED
        )
        
    def _apply_filter(self, data: np.ndarray) -> np.ndarray:
        """应用滤波器"""
        if self.filter_type == "lowpass":
            return self._lowpass_filter(data)
        elif self.filter_type == "highpass":
            return self._highpass_filter(data)
        elif self.filter_type == "bandpass":
            return self._bandpass_filter(data)
        else:
            return data
            
    def _lowpass_filter(self, data: np.ndarray) -> np.ndarray:
        """低通滤波"""
        # 简化实现
        window_size = self.filter_params.get("window_size", 5)
        if len(data) > window_size:
            kernel = np.ones(window_size) / window_size
            return np.convolve(data, kernel, mode='same')
        return data
        
class EnhancementStage(ProcessingStageBase):
    """增强阶段"""
    
    def process(self, packet: DataPacket) -> DataPacket:
        # 数据增强处理
        enhanced_data = self._enhance_data(packet.data)
        
        return DataPacket(
            id=packet.id + "_enhanced",
            type=packet.type,
            source=packet.source,
            timestamp=packet.timestamp,
            data=enhanced_data,
            metadata={**packet.metadata, "enhancement": "applied"},
            processing_stage=ProcessingStage.ENHANCED
        )
        
    def _enhance_data(self, data: Any) -> Any:
        """增强数据"""
        if isinstance(data, np.ndarray):
            # 归一化
            if np.max(data) > np.min(data):
                return (data - np.min(data)) / (np.max(data) - np.min(data))
        return data
        
class AnalysisStage(ProcessingStageBase):
    """分析阶段"""
    
    def process(self, packet: DataPacket) -> DataPacket:
        # 数据分析
        analysis_results = self._analyze_data(packet.data)
        
        return DataPacket(
            id=packet.id + "_analyzed",
            type=packet.type,
            source=packet.source,
            timestamp=packet.timestamp,
            data=analysis_results,
            metadata={**packet.metadata, "analysis": "completed"},
            processing_stage=ProcessingStage.ANALYZED
        )
        
    def _analyze_data(self, data: Any) -> Dict[str, Any]:
        """分析数据"""
        if isinstance(data, np.ndarray):
            return {
                "mean": float(np.mean(data)),
                "std": float(np.std(data)),
                "max": float(np.max(data)),
                "min": float(np.min(data)),
                "rms": float(np.sqrt(np.mean(data**2))),
                "peak_to_peak": float(np.max(data) - np.min(data))
            }
        elif isinstance(data, dict):
            return data
        else:
            return {"value": data}
            
class DataPipeline:
    """数据流水线"""
    
    def __init__(self, config: PipelineConfig):
        self.config = config
        self.stages: Dict[str, ProcessingStageBase] = {}
        self.sources: Dict[str, DataSource] = {}
        self.sinks: Dict[str, List[Callable]] = {}
        self.running = False
        
    def add_stage(self, stage: ProcessingStageBase):
        """添加处理阶段"""
        self.stages[stage.stage_id] = stage
        
    def add_source(self, source: DataSource):
        """添加数据源"""
        self.sources[source.source_id] = source
        
    def register_sink(self, sink_id: str, callback: Callable):
        """注册数据接收器"""
        if sink_id not in self.sinks:
            self.sinks[sink_id] = []
        self.sinks[sink_id].append(callback)
        
    def start(self):
        """启动流水线"""
        self.running = True
        
        # 启动所有处理阶段
        for stage in self.stages.values():
            stage.start()
            
        # 启动所有数据源
        for source in self.sources.values():
            source.start()
            # 将数据源连接到第一个处理阶段
            if self.config.stages:
                first_stage = self.stages.get(self.config.stages[0])
                if first_stage:
                    source.register_callback(first_stage.input_queue.put)
                    
        # 连接处理阶段
        self._connect_stages()
        
        # 启动监控线程
        self.monitor_thread = threading.Thread(target=self._monitor, daemon=True)
        self.monitor_thread.start()
        
    def stop(self):
        """停止流水线"""
        self.running = False
        
        for source in self.sources.values():
            source.stop()
            
        for stage in self.stages.values():
            stage.stop()
            
    def _connect_stages(self):
        """连接处理阶段"""
        for i in range(len(self.config.stages) - 1):
            current_stage = self.stages.get(self.config.stages[i])
            next_stage = self.stages.get(self.config.stages[i + 1])
            
            if current_stage and next_stage:
                # 连接输出队列到输入队列
                threading.Thread(
                    target=self._forward_data,
                    args=(current_stage.output_queue, next_stage.input_queue),
                    daemon=True
                ).start()
                
        # 连接最后一个阶段到接收器
        if self.config.stages:
            last_stage = self.stages.get(self.config.stages[-1])
            if last_stage and self.sinks:
                threading.Thread(
                    target=self._deliver_to_sinks,
                    args=(last_stage.output_queue,),
                    daemon=True
                ).start()
                
    def _forward_data(self, source_queue: queue.Queue, target_queue: queue.Queue):
        """转发数据"""
        while self.running:
            try:
                data = source_queue.get(timeout=0.1)
                target_queue.put(data)
            except queue.Empty:
                continue
                
    def _deliver_to_sinks(self, source_queue: queue.Queue):
        """分发数据到接收器"""
        while self.running:
            try:
                data = source_queue.get(timeout=0.1)
                
                for sink_callbacks in self.sinks.values():
                    for callback in sink_callbacks:
                        try:
                            callback(data)
                        except Exception as e:
                            print(f"数据接收器错误: {e}")
                            
            except queue.Empty:
                continue
                
    def _monitor(self):
        """监控流水线"""
        while self.running:
            stats = self.get_pipeline_stats()
            
            # 这里可以添加监控逻辑,如告警、日志等
            if stats["throughput"] < self.config.processing_rate * 0.5:
                print(f"警告: 流水线吞吐量低于预期: {stats['throughput']:.1f} packets/s")
                
            time.sleep(5.0)
            
    def get_pipeline_stats(self) -> Dict[str, Any]:
        """获取流水线统计信息"""
        total_processed = 0
        total_time = 0.0
        stage_stats = {}
        
        for stage_id, stage in self.stages.items():
            stats = stage.get_stats()
            stage_stats[stage_id] = stats
            total_processed += stats.get("processed_count", 0)
            total_time += stats.get("avg_processing_time", 0) * stats.get("processed_count", 0)
            
        avg_time = total_time / total_processed if total_processed > 0 else 0
        
        return {
            "total_processed": total_processed,
            "avg_processing_time": avg_time,
            "stage_stats": stage_stats,
            "source_count": len(self.sources),
            "sink_count": sum(len(callbacks) for callbacks in self.sinks.values()),
            "throughput": total_processed / (time.time() - self.start_time) 
                         if hasattr(self, 'start_time') else 0
        }
        
class TelemetrySource(DataSource):
    """遥测数据源"""
    
    def start(self):
        self.running = True
        self.thread = threading.Thread(target=self._generate_data, daemon=True)
        self.thread.start()
        
    def stop(self):
        self.running = False
        
    def _generate_data(self):
        """生成遥测数据"""
        import random
        
        while self.running:
            # 生成模拟遥测数据
            telemetry_data = {
                "timestamp": time.time(),
                "position": {
                    "x": random.uniform(-1000, 1000),
                    "y": random.uniform(-1000, 1000),
                    "z": random.uniform(0, 10000)
                },
                "velocity": {
                    "vx": random.uniform(-100, 100),
                    "vy": random.uniform(-100, 100),
                    "vz": random.uniform(-10, 10)
                },
                "attitude": {
                    "roll": random.uniform(-180, 180),
                    "pitch": random.uniform(-90, 90),
                    "yaw": random.uniform(0, 360)
                },
                "system_status": {
                    "power": random.uniform(0, 100),
                    "temperature": random.uniform(20, 80),
                    "cpu_usage": random.uniform(0, 100)
                }
            }
            
            self.emit_data(telemetry_data)
            
            # 控制数据生成速率
            time.sleep(1.0 / self.config.get("rate", 10.0))
            
class SpectrumSource(DataSource):
    """频谱数据源"""
    
    def start(self):
        self.running = True
        self.thread = threading.Thread(target=self._generate_spectrum, daemon=True)
        self.thread.start()
        
    def _generate_spectrum(self):
        """生成频谱数据"""
        import random
        
        while self.running:
            # 生成模拟频谱数据
            frequencies = np.linspace(1000, 3000, 1000)
            
            # 添加一些信号
            amplitudes = np.random.randn(len(frequencies)) * 0.1
            
            # 添加几个信号峰值
            peaks = [
                (1500, 1.0, 10),
                (2200, 0.8, 15),
                (2800, 0.6, 8)
            ]
            
            for freq, amp, width in peaks:
                idx = np.argmin(np.abs(frequencies - freq))
                if 0 <= idx < len(amplitudes):
                    # 添加高斯峰
                    x = np.linspace(-3, 3, width*2+1)
                    gaussian = amp * np.exp(-x**2)
                    start = max(0, idx - width)
                    end = min(len(amplitudes), idx + width + 1)
                    gaussian_start = max(0, width - (idx - start))
                    gaussian_end = min(len(gaussian), width + (end - idx))
                    amplitudes[start:end] += gaussian[gaussian_start:gaussian_end]
                    
            spectrum_data = {
                "frequencies": frequencies.tolist(),
                "amplitudes": amplitudes.tolist(),
                "timestamp": time.time(),
                "center_frequency": 2000,
                "bandwidth": 2000
            }
            
            self.emit_data(spectrum_data)
            
            time.sleep(1.0 / self.config.get("rate", 20.0))

4.2 数据可视化流水线

python 复制代码
"""
visualization_pipeline.py

数据可视化流水线
"""
from typing import Dict, List, Any, Optional, Tuple
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_agg import FigureCanvasAgg
import io
from PIL import Image
import tkinter as tk

class VisualizationStage(ProcessingStageBase):
    """可视化阶段"""
    
    def __init__(self, stage_id: str, config: Dict[str, Any]):
        super().__init__(stage_id, config)
        self.viz_type = config.get("viz_type", "plot")
        self.figure_config = config.get("figure", {})
        
    def process(self, packet: DataPacket) -> DataPacket:
        # 生成可视化图像
        image_data = self._create_visualization(packet.data, packet.metadata)
        
        return DataPacket(
            id=packet.id + "_visualized",
            type=packet.type,
            source=packet.source,
            timestamp=packet.timestamp,
            data=image_data,
            metadata={**packet.metadata, "viz_type": self.viz_type},
            processing_stage=ProcessingStage.VISUALIZED
        )
        
    def _create_visualization(self, data: Any, metadata: Dict[str, Any]) -> bytes:
        """创建可视化"""
        if self.viz_type == "plot":
            return self._create_plot(data, metadata)
        elif self.viz_type == "heatmap":
            return self._create_heatmap(data, metadata)
        elif self.viz_type == "3d":
            return self._create_3d_plot(data, metadata)
        else:
            return self._create_default_plot(data, metadata)
            
    def _create_plot(self, data: Any, metadata: Dict[str, Any]) -> bytes:
        """创建折线图"""
        fig, ax = plt.subplots(figsize=(8, 4))
        
        if isinstance(data, dict) and "frequencies" in data and "amplitudes" in data:
            # 频谱图
            frequencies = data["frequencies"]
            amplitudes = data["amplitudes"]
            
            ax.plot(frequencies, amplitudes, 'b-', linewidth=1)
            ax.set_xlabel("频率 (MHz)")
            ax.set_ylabel("幅度 (dB)")
            ax.set_title("频谱图")
            ax.grid(True, alpha=0.3)
            
        elif isinstance(data, np.ndarray):
            # 时间序列
            ax.plot(data, 'g-', linewidth=1)
            ax.set_xlabel("时间")
            ax.set_ylabel("值")
            ax.set_title("时间序列")
            ax.grid(True, alpha=0.3)
            
        else:
            ax.text(0.5, 0.5, "不支持的数据类型", 
                   ha='center', va='center', transform=ax.transAxes)
                   
        fig.tight_layout()
        
        # 转换为图像数据
        return self._figure_to_bytes(fig)
        
    def _create_heatmap(self, data: Any, metadata: Dict[str, Any]) -> bytes:
        """创建热力图"""
        fig, ax = plt.subplots(figsize=(8, 6))
        
        if isinstance(data, np.ndarray) and data.ndim == 2:
            im = ax.imshow(data, cmap='hot', aspect='auto')
            fig.colorbar(im, ax=ax)
            ax.set_title("热力图")
            
        elif isinstance(data, dict) and "matrix" in data:
            matrix = np.array(data["matrix"])
            im = ax.imshow(matrix, cmap='viridis', aspect='auto')
            fig.colorbar(im, ax=ax)
            ax.set_title(data.get("title", "热力图"))
            
        else:
            ax.text(0.5, 0.5, "不支持的热力图数据", 
                   ha='center', va='center', transform=ax.transAxes)
                   
        fig.tight_layout()
        return self._figure_to_bytes(fig)
        

    def _create_3d_plot(self, data: Any, metadata: Dict[str, Any]) -> bytes:
        """创建3D图"""
        from mpl_toolkits.mplot3d import Axes3D
        
        fig = plt.figure(figsize=(8, 6))
        ax = fig.add_subplot(111, projection='3d')
        
        if isinstance(data, dict) and "x" in data and "y" in data and "z" in data:
            # 3D散点图
            x = np.array(data["x"])
            y = np.array(data["y"])
            z = np.array(data["z"])
            
            if "c" in data:
                c = np.array(data["c"])
                scatter = ax.scatter(x, y, z, c=c, cmap='viridis', s=20)
                fig.colorbar(scatter, ax=ax)
            else:
                ax.scatter(x, y, z, s=20)
                
            ax.set_xlabel("X")
            ax.set_ylabel("Y")
            ax.set_zlabel("Z")
            ax.set_title("3D散点图")
            
        elif isinstance(data, np.ndarray) and data.ndim == 2 and data.shape[1] == 3:
            # 3D点云
            x = data[:, 0]
            y = data[:, 1]
            z = data[:, 2]
            ax.scatter(x, y, z, s=5)
            ax.set_xlabel("X")
            ax.set_ylabel("Y")
            ax.set_zlabel("Z")
            ax.set_title("3D点云")
            
        elif isinstance(data, dict) and "surface" in data:
            # 3D曲面
            x = np.array(data.get("x", np.arange(100)))
            y = np.array(data.get("y", np.arange(100)))
            Z = np.array(data["surface"])
            
            if Z.ndim == 2:
                X, Y = np.meshgrid(x, y)
                surf = ax.plot_surface(X, Y, Z, cmap='coolwarm', alpha=0.8)
                fig.colorbar(surf, ax=ax)
                ax.set_title("3D曲面")
            else:
                ax.text(0.5, 0.5, 0.5, "无效的曲面数据", 
                       ha='center', va='center', transform=ax.transAxes)
        else:
            ax.text(0.5, 0.5, 0.5, "不支持3D显示的数据", 
                   ha='center', va='center', transform=ax.transAxes)
                   
        fig.tight_layout()
        return self._figure_to_bytes(fig)
        
    def _create_default_plot(self, data: Any, metadata: Dict[str, Any]) -> bytes:
        """创建默认图"""
        fig, ax = plt.subplots(figsize=(8, 4))
        
        if isinstance(data, (list, np.ndarray)):
            ax.plot(data, 'r-', linewidth=1)
            ax.set_title("数据曲线")
        elif isinstance(data, dict):
            # 尝试绘制字典中的第一个数组
            for key, value in data.items():
                if isinstance(value, (list, np.ndarray)):
                    ax.plot(value, label=key)
            ax.legend()
            ax.set_title("多数据曲线")
        else:
            ax.text(0.5, 0.5, f"数据: {str(data)[:50]}...", 
                   ha='center', va='center', transform=ax.transAxes)
                   
        ax.set_xlabel("索引")
        ax.set_ylabel("值")
        ax.grid(True, alpha=0.3)
        fig.tight_layout()
        
        return self._figure_to_bytes(fig)
        
    def _figure_to_bytes(self, fig) -> bytes:
        """将matplotlib图形转换为字节流"""
        # 使用内存缓冲区
        buf = io.BytesIO()
        fig.savefig(buf, format='png', dpi=100, bbox_inches='tight')
        plt.close(fig)  # 关闭图形以释放内存
        buf.seek(0)
        return buf.read()

class ImageDisplaySink:
    """图像显示接收器(用于tkinter)"""
    
    def __init__(self, parent: tk.Widget, width: int = 400, height: int = 300):
        self.parent = parent
        self.width = width
        self.height = height
        
        # 创建标签用于显示图像
        self.image_label = tk.Label(parent, bg='black')
        self.image_label.pack(fill=tk.BOTH, expand=True)
        
        # 缓存图像引用
        self.current_image = None
        
    def display_image(self, image_data: bytes):
        """显示图像"""
        try:
            # 将字节流转换为PIL图像
            from PIL import Image, ImageTk
            import io
            
            pil_image = Image.open(io.BytesIO(image_data))
            
            # 调整大小以适应显示区域
            pil_image.thumbnail((self.width, self.height), Image.Resampling.LANCZOS)
            
            # 转换为PhotoImage
            photo = ImageTk.PhotoImage(pil_image)
            
            # 更新标签
            self.image_label.configure(image=photo)
            self.image_label.image = photo  # 保持引用
            
            # 保存当前图像引用
            self.current_image = photo
            
        except Exception as e:
            print(f"显示图像错误: {e}")
            
    def clear(self):
        """清除显示"""
        self.image_label.configure(image='')
        self.current_image = None

class DataPipelineManager:
    """数据流水线管理器"""
    
    def __init__(self):
        self.pipelines: Dict[str, DataPipeline] = {}
        self.viz_displays: Dict[str, ImageDisplaySink] = {}
        
    def create_telemetry_pipeline(self, pipeline_id: str, 
                                 display_widget: tk.Widget = None):
        """创建遥测数据流水线"""
        config = PipelineConfig(
            name="telemetry_pipeline",
            stages=["filter", "enhance", "analyze", "visualize"],
            buffer_size=1000,
            processing_rate=50.0,
            parallel_workers=2
        )
        
        pipeline = DataPipeline(config)
        
        # 添加数据源
        telemetry_source = TelemetrySource("telemetry_1", {"rate": 10.0})
        pipeline.add_source(telemetry_source)
        
        # 添加处理阶段
        filter_stage = FilterStage("filter", {
            "filter_type": "lowpass",
            "filter_params": {"window_size": 5}
        })
        pipeline.add_stage(filter_stage)
        
        enhance_stage = EnhancementStage("enhance", {})
        pipeline.add_stage(enhance_stage)
        
        analyze_stage = AnalysisStage("analyze", {})
        pipeline.add_stage(analyze_stage)
        
        visualize_stage = VisualizationStage("visualize", {
            "viz_type": "plot"
        })
        pipeline.add_stage(visualize_stage)
        
        # 添加显示接收器
        if display_widget:
            display_sink = ImageDisplaySink(display_widget)
            self.viz_displays[pipeline_id] = display_sink
            
            def display_callback(packet: DataPacket):
                if isinstance(packet.data, bytes):
                    display_sink.display_image(packet.data)
                    
            pipeline.register_sink("display", display_callback)
            
        self.pipelines[pipeline_id] = pipeline
        return pipeline
        
    def create_spectrum_pipeline(self, pipeline_id: str,
                                display_widget: tk.Widget = None):
        """创建频谱数据流水线"""
        config = PipelineConfig(
            name="spectrum_pipeline",
            stages=["filter", "analyze", "visualize"],
            buffer_size=2000,
            processing_rate=100.0,
            parallel_workers=1
        )
        
        pipeline = DataPipeline(config)
        
        # 添加数据源
        spectrum_source = SpectrumSource("spectrum_1", {"rate": 20.0})
        pipeline.add_source(spectrum_source)
        
        # 添加处理阶段
        filter_stage = FilterStage("filter", {
            "filter_type": "lowpass",
            "filter_params": {"window_size": 3}
        })
        pipeline.add_stage(filter_stage)
        
        analyze_stage = AnalysisStage("analyze", {})
        pipeline.add_stage(analyze_stage)
        
        visualize_stage = VisualizationStage("visualize", {
            "viz_type": "plot"
        })
        pipeline.add_stage(visualize_stage)
        
        # 添加显示接收器
        if display_widget:
            display_sink = ImageDisplaySink(display_widget)
            self.viz_displays[pipeline_id] = display_sink
            
            def display_callback(packet: DataPacket):
                if isinstance(packet.data, bytes):
                    display_sink.display_image(packet.data)
                    
            pipeline.register_sink("display", display_callback)
            
        self.pipelines[pipeline_id] = pipeline
        return pipeline
        
    def start_pipeline(self, pipeline_id: str):
        """启动流水线"""
        if pipeline_id in self.pipelines:
            self.pipelines[pipeline_id].start()
            
    def stop_pipeline(self, pipeline_id: str):
        """停止流水线"""
        if pipeline_id in self.pipelines:
            self.pipelines[pipeline_id].stop()
            
    def get_pipeline_stats(self, pipeline_id: str) -> Optional[Dict]:
        """获取流水线统计信息"""
        if pipeline_id in self.pipelines:
            return self.pipelines[pipeline_id].get_pipeline_stats()
        return None
        
    def clear_display(self, pipeline_id: str):
        """清除显示"""
        if pipeline_id in self.viz_displays:
            self.viz_displays[pipeline_id].clear()

5. 插件化架构设计与实现

5.1 插件管理系统

python 复制代码
"""
plugin_system.py

插件化架构系统
"""
import os
import sys
import importlib
import inspect
from typing import Dict, List, Any, Optional, Type, Set
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
import json
import threading
import time
from pathlib import Path

class PluginType(Enum):
    """插件类型"""
    VIEW = "view"            # 视图插件
    DATA_SOURCE = "data_source"  # 数据源插件
    PROCESSOR = "processor"  # 处理器插件
    VISUALIZATION = "visualization"  # 可视化插件
    TOOL = "tool"           # 工具插件
    EXTENSION = "extension"  # 扩展插件

class PluginState(Enum):
    """插件状态"""
    UNLOADED = "unloaded"    # 未加载
    LOADED = "loaded"        # 已加载
    ENABLED = "enabled"      # 已启用
    DISABLED = "disabled"    # 已禁用
    ERROR = "error"          # 错误

@dataclass
class PluginInfo:
    """插件信息"""
    id: str
    name: str
    type: PluginType
    version: str
    description: str
    author: str
    dependencies: List[str] = field(default_factory=list)
    config_schema: Dict[str, Any] = field(default_factory=dict)
    state: PluginState = PluginState.UNLOADED
    path: str = ""
    metadata: Dict[str, Any] = field(default_factory=dict)
    
class BasePlugin(ABC):
    """插件基类"""
    
    def __init__(self, info: PluginInfo):
        self.info = info
        self.config: Dict[str, Any] = {}
        
    @abstractmethod
    def initialize(self, system: Any, config: Dict[str, Any]) -> bool:
        """初始化插件"""
        pass
        
    @abstractmethod
    def start(self) -> bool:
        """启动插件"""
        pass
        
    @abstractmethod
    def stop(self) -> bool:
        """停止插件"""
        pass
        
    @abstractmethod
    def get_widget(self, parent: tk.Widget) -> Optional[tk.Widget]:
        """获取插件控件(用于视图插件)"""
        pass
        
    def update_config(self, config: Dict[str, Any]):
        """更新配置"""
        self.config.update(config)
        
    def get_status(self) -> Dict[str, Any]:
        """获取插件状态"""
        return {
            "id": self.info.id,
            "name": self.info.name,
            "state": self.info.state.value,
            "config": self.config
        }

class PluginManager:
    """插件管理器"""
    
    def __init__(self, system: Any):
        self.system = system
        self.plugins: Dict[str, BasePlugin] = {}
        self.plugin_info: Dict[str, PluginInfo] = {}
        self.plugin_dirs: List[str] = []
        self.plugin_loaders: Dict[str, Type] = {}
        
        # 插件事件
        self.event_handlers: Dict[str, List[Callable]] = {}
        
    def add_plugin_dir(self, dir_path: str):
        """添加插件目录"""
        if os.path.isdir(dir_path) and dir_path not in self.plugin_dirs:
            self.plugin_dirs.append(dir_path)
            
    def register_plugin_loader(self, plugin_type: str, loader_class: Type):
        """注册插件加载器"""
        self.plugin_loaders[plugin_type] = loader_class
        
    def discover_plugins(self) -> List[PluginInfo]:
        """发现插件"""
        discovered_plugins = []
        
        for plugin_dir in self.plugin_dirs:
            if not os.path.isdir(plugin_dir):
                continue
                
            for item in os.listdir(plugin_dir):
                plugin_path = os.path.join(plugin_dir, item)
                
                # 检查是否是目录
                if os.path.isdir(plugin_path):
                    # 检查是否有plugin.json文件
                    plugin_json = os.path.join(plugin_path, "plugin.json")
                    if os.path.isfile(plugin_json):
                        try:
                            with open(plugin_json, 'r', encoding='utf-8') as f:
                                plugin_data = json.load(f)
                                
                            # 创建插件信息
                            plugin_info = PluginInfo(
                                id=plugin_data.get("id", ""),
                                name=plugin_data.get("name", ""),
                                type=PluginType(plugin_data.get("type", "extension")),
                                version=plugin_data.get("version", "1.0.0"),
                                description=plugin_data.get("description", ""),
                                author=plugin_data.get("author", ""),
                                dependencies=plugin_data.get("dependencies", []),
                                config_schema=plugin_data.get("config_schema", {}),
                                path=plugin_path,
                                metadata=plugin_data.get("metadata", {})
                            )
                            
                            if plugin_info.id:
                                discovered_plugins.append(plugin_info)
                                
                        except Exception as e:
                            print(f"加载插件信息失败 {plugin_path}: {e}")
                            
        return discovered_plugins
        
    def load_plugin(self, plugin_info: PluginInfo) -> bool:
        """加载插件"""
        try:
            # 检查依赖
            for dep in plugin_info.dependencies:
                if dep not in self.plugins or self.plugins[dep].info.state != PluginState.ENABLED:
                    print(f"插件 {plugin_info.id} 依赖 {dep} 未满足")
                    return False
                    
            # 动态加载插件模块
            plugin_dir = plugin_info.path
            if not plugin_dir or not os.path.isdir(plugin_dir):
                print(f"插件目录不存在: {plugin_dir}")
                return False
                
            # 添加到Python路径
            if plugin_dir not in sys.path:
                sys.path.insert(0, plugin_dir)
                
            # 导入插件模块
            module_name = plugin_info.metadata.get("module", "plugin")
            try:
                module = importlib.import_module(module_name)
            except ImportError as e:
                print(f"导入插件模块失败: {e}")
                return False
                
            # 查找插件类
            plugin_class = None
            for name, obj in inspect.getmembers(module):
                if (inspect.isclass(obj) and 
                    issubclass(obj, BasePlugin) and 
                    obj != BasePlugin):
                    plugin_class = obj
                    break
                    
            if not plugin_class:
                print(f"未找到插件类: {module_name}")
                return False
                
            # 创建插件实例
            plugin = plugin_class(plugin_info)
            
            # 初始化插件
            config = plugin_info.metadata.get("config", {})
            if plugin.initialize(self.system, config):
                self.plugins[plugin_info.id] = plugin
                self.plugin_info[plugin_info.id] = plugin_info
                plugin_info.state = PluginState.LOADED
                
                # 触发插件加载事件
                self._emit_event("plugin_loaded", {
                    "plugin_id": plugin_info.id,
                    "plugin_info": plugin_info
                })
                
                return True
            else:
                print(f"插件初始化失败: {plugin_info.id}")
                return False
                
        except Exception as e:
            print(f"加载插件 {plugin_info.id} 失败: {e}")
            plugin_info.state = PluginState.ERROR
            return False
            
    def enable_plugin(self, plugin_id: str) -> bool:
        """启用插件"""
        if plugin_id not in self.plugins:
            print(f"插件未加载: {plugin_id}")
            return False
            
        plugin = self.plugins[plugin_id]
        
        try:
            if plugin.start():
                plugin.info.state = PluginState.ENABLED
                
                # 触发插件启用事件
                self._emit_event("plugin_enabled", {
                    "plugin_id": plugin_id,
                    "plugin": plugin
                })
                
                return True
            else:
                print(f"插件启动失败: {plugin_id}")
                plugin.info.state = PluginState.ERROR
                return False
                
        except Exception as e:
            print(f"启用插件 {plugin_id} 失败: {e}")
            plugin.info.state = PluginState.ERROR
            return False
            
    def disable_plugin(self, plugin_id: str) -> bool:
        """禁用插件"""
        if plugin_id not in self.plugins:
            print(f"插件未加载: {plugin_id}")
            return False
            
        plugin = self.plugins[plugin_id]
        
        try:
            if plugin.stop():
                plugin.info.state = PluginState.DISABLED
                
                # 触发插件禁用事件
                self._emit_event("plugin_disabled", {
                    "plugin_id": plugin_id,
                    "plugin": plugin
                })
                
                return True
            else:
                print(f"插件停止失败: {plugin_id}")
                return False
                
        except Exception as e:
            print(f"禁用插件 {plugin_id} 失败: {e}")
            return False
            
    def unload_plugin(self, plugin_id: str) -> bool:
        """卸载插件"""
        if plugin_id not in self.plugins:
            print(f"插件未加载: {plugin_id}")
            return False
            
        # 先禁用插件
        if self.plugins[plugin_id].info.state == PluginState.ENABLED:
            self.disable_plugin(plugin_id)
            
        # 移除插件
        del self.plugins[plugin_id]
        del self.plugin_info[plugin_id]
        
        # 触发插件卸载事件
        self._emit_event("plugin_unloaded", {
            "plugin_id": plugin_id
        })
        
        return True
        
    def get_plugin(self, plugin_id: str) -> Optional[BasePlugin]:
        """获取插件"""
        return self.plugins.get(plugin_id)
        
    def get_plugin_info(self, plugin_id: str) -> Optional[PluginInfo]:
        """获取插件信息"""
        return self.plugin_info.get(plugin_id)
        
    def get_all_plugins(self) -> List[BasePlugin]:
        """获取所有插件"""
        return list(self.plugins.values())
        
    def get_enabled_plugins(self) -> List[BasePlugin]:
        """获取启用的插件"""
        return [p for p in self.plugins.values() 
                if p.info.state == PluginState.ENABLED]
                
    def register_event_handler(self, event_type: str, handler: Callable):
        """注册事件处理函数"""
        if event_type not in self.event_handlers:
            self.event_handlers[event_type] = []
        self.event_handlers[event_type].append(handler)
        
    def _emit_event(self, event_type: str, data: Any):
        """触发事件"""
        if event_type in self.event_handlers:
            for handler in self.event_handlers[event_type]:
                try:
                    handler(data)
                except Exception as e:
                    print(f"插件事件处理错误: {e}")

# 插件示例
class ExampleViewPlugin(BasePlugin):
    """示例视图插件"""
    
    def __init__(self, info: PluginInfo):
        super().__init__(info)
        self.frame = None
        self.canvas = None
        
    def initialize(self, system: Any, config: Dict[str, Any]) -> bool:
        self.config = config
        return True
        
    def start(self) -> bool:
        return True
        
    def stop(self) -> bool:
        if self.frame:
            self.frame.destroy()
        return True
        
    def get_widget(self, parent: tk.Widget) -> Optional[tk.Widget]:
        """获取插件控件"""
        self.frame = ttk.Frame(parent)
        
        # 创建标题
        title = ttk.Label(self.frame, 
                         text=self.info.name,
                         font=("微软雅黑", 12, "bold"))
        title.pack(pady=10)
        
        # 创建画布
        self.canvas = tk.Canvas(self.frame, bg="#1C2833", height=200)
        self.canvas.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 绘制示例内容
        self._draw_example()
        
        return self.frame
        
    def _draw_example(self):
        """绘制示例内容"""
        if not self.canvas:
            return
            
        width = 300
        height = 150
        
        # 绘制背景
        self.canvas.create_rectangle(0, 0, width, height, 
                                   fill="#2C3E50", outline="")
        
        # 绘制文本
        self.canvas.create_text(width//2, height//2,
                               text="示例插件",
                               fill="#ECF0F1",
                               font=("微软雅黑", 16))
        
        # 绘制进度条
        progress = 0.7
        bar_width = 200
        bar_height = 20
        bar_x = (width - bar_width) // 2
        bar_y = height - 50
        
        # 背景
        self.canvas.create_rectangle(bar_x, bar_y, 
                                   bar_x + bar_width, bar_y + bar_height,
                                   fill="#34495E", outline="")
        
        # 进度
        self.canvas.create_rectangle(bar_x, bar_y,
                                   bar_x + bar_width * progress, bar_y + bar_height,
                                   fill="#2ECC71", outline="")
        
        # 进度文本
        self.canvas.create_text(bar_x + bar_width//2, bar_y + bar_height//2,
                               text=f"{progress*100:.0f}%",
                               fill="#ECF0F1",
                               font=("微软雅黑", 10))

class ExampleDataSourcePlugin(BasePlugin):
    """示例数据源插件"""
    
    def __init__(self, info: PluginInfo):
        super().__init__(info)
        self.data_callback = None
        self.running = False
        self.thread = None
        
    def initialize(self, system: Any, config: Dict[str, Any]) -> bool:
        self.system = system
        self.config = config
        return True
        
    def start(self) -> bool:
        self.running = True
        self.thread = threading.Thread(target=self._generate_data, daemon=True)
        self.thread.start()
        return True
        
    def stop(self) -> bool:
        self.running = False
        if self.thread:
            self.thread.join(timeout=1.0)
        return True
        
    def _generate_data(self):
        """生成数据"""
        import random
        
        while self.running:
            # 生成示例数据
            data = {
                "timestamp": time.time(),
                "value": random.uniform(0, 100),
                "status": "正常" if random.random() > 0.1 else "异常"
            }
            
            # 发送数据
            if hasattr(self.system, 'data_bus'):
                self.system.data_bus.send_data("example_data", data)
                
            time.sleep(1.0)
            
    def get_widget(self, parent: tk.Widget) -> Optional[tk.Widget]:
        """获取插件控件"""
        frame = ttk.Frame(parent)
        
        label = ttk.Label(frame, text="数据源插件: 运行中")
        label.pack(pady=10)
        
        return frame

class PluginBrowser:
    """插件浏览器界面"""
    
    def __init__(self, parent: tk.Widget, plugin_manager: PluginManager):
        self.parent = parent
        self.plugin_manager = plugin_manager
        
        self.create_ui()
        
    def create_ui(self):
        """创建UI界面"""
        # 主框架
        main_frame = ttk.Frame(self.parent)
        main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 标题
        title = ttk.Label(main_frame, 
                         text="插件管理器",
                         font=("微软雅黑", 16, "bold"))
        title.pack(pady=(0, 10))
        
        # 插件列表
        list_frame = ttk.LabelFrame(main_frame, text="可用插件", padding=10)
        list_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 10))
        
        # 创建Treeview
        columns = ("ID", "名称", "版本", "状态", "操作")
        self.tree = ttk.Treeview(list_frame, columns=columns, show="headings", height=10)
        
        for col in columns:
            self.tree.heading(col, text=col)
            if col == "操作":
                self.tree.column(col, width=150)
            else:
                self.tree.column(col, width=100)
                
        scrollbar = ttk.Scrollbar(list_frame, orient=tk.VERTICAL, command=self.tree.yview)
        self.tree.configure(yscrollcommand=scrollbar.set)
        
        self.tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        # 控制按钮
        button_frame = ttk.Frame(main_frame)
        button_frame.pack(fill=tk.X, pady=5)
        
        ttk.Button(button_frame, text="刷新", 
                  command=self.refresh_plugins).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="加载选中", 
                  command=self.load_selected).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="启用选中", 
                  command=self.enable_selected).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="禁用选中", 
                  command=self.disable_selected).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="卸载选中", 
                  command=self.unload_selected).pack(side=tk.LEFT, padx=5)
                  
        # 插件详情
        detail_frame = ttk.LabelFrame(main_frame, text="插件详情", padding=10)
        detail_frame.pack(fill=tk.BOTH, expand=True)
        
        self.detail_text = tk.Text(detail_frame, height=8, width=60,
                                  font=("Consolas", 9))
        detail_scrollbar = ttk.Scrollbar(detail_frame, orient=tk.VERTICAL,
                                        command=self.detail_text.yview)
        self.detail_text.configure(yscrollcommand=detail_scrollbar.set)
        
        self.detail_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        detail_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        # 绑定选择事件
        self.tree.bind("<<TreeviewSelect>>", self.on_plugin_selected)
        
        # 初始刷新
        self.refresh_plugins()
        
    def refresh_plugins(self):
        """刷新插件列表"""
        # 清空现有项
        for item in self.tree.get_children():
            self.tree.delete(item)
            
        # 发现插件
        discovered_plugins = self.plugin_manager.discover_plugins()
        
        # 添加已加载的插件
        loaded_plugins = self.plugin_manager.get_all_plugins()
        loaded_ids = {p.info.id for p in loaded_plugins}
        
        # 合并插件列表
        all_plugins = {}
        for plugin_info in discovered_plugins:
            all_plugins[plugin_info.id] = {
                "info": plugin_info,
                "loaded": plugin_info.id in loaded_ids
            }
            
        # 添加已加载但未发现的插件
        for plugin in loaded_plugins:
            if plugin.info.id not in all_plugins:
                all_plugins[plugin.info.id] = {
                    "info": plugin.info,
                    "loaded": True
                }
                
        # 添加到Treeview
        for plugin_id, plugin_data in all_plugins.items():
            plugin_info = plugin_data["info"]
            loaded = plugin_data["loaded"]
            
            if loaded:
                plugin = self.plugin_manager.get_plugin(plugin_id)
                state = plugin.info.state.value if plugin else "未知"
            else:
                state = "未加载"
                
            # 操作按钮文本
            if loaded:
                if plugin and plugin.info.state == PluginState.ENABLED:
                    action = "禁用"
                elif plugin and plugin.info.state == PluginState.DISABLED:
                    action = "启用"
                else:
                    action = "卸载"
            else:
                action = "加载"
                
            self.tree.insert("", tk.END, values=(
                plugin_info.id,
                plugin_info.name,
                plugin_info.version,
                state,
                action
            ))
            
    def on_plugin_selected(self, event):
        """插件选择事件"""
        selection = self.tree.selection()
        if not selection:
            return
            
        item = selection[0]
        values = self.tree.item(item, "values")
        plugin_id = values[0]
        
        # 获取插件信息
        plugin_info = self.plugin_manager.get_plugin_info(plugin_id)
        if not plugin_info:
            # 可能是未加载的插件,从发现列表中查找
            discovered_plugins = self.plugin_manager.discover_plugins()
            for p in discovered_plugins:
                if p.id == plugin_id:
                    plugin_info = p
                    break
                    
        if plugin_info:
            # 显示详情
            detail = f"ID: {plugin_info.id}\n"
            detail += f"名称: {plugin_info.name}\n"
            detail += f"类型: {plugin_info.type.value}\n"
            detail += f"版本: {plugin_info.version}\n"
            detail += f"作者: {plugin_info.author}\n"
            detail += f"描述: {plugin_info.description}\n"
            detail += f"依赖: {', '.join(plugin_info.dependencies)}\n"
            detail += f"路径: {plugin_info.path}\n"
            
            self.detail_text.delete(1.0, tk.END)
            self.detail_text.insert(1.0, detail)
            
    def load_selected(self):
        """加载选中的插件"""
        selection = self.tree.selection()
        if not selection:
            return
            
        item = selection[0]
        values = self.tree.item(item, "values")
        plugin_id = values[0]
        
        # 查找插件信息
        discovered_plugins = self.plugin_manager.discover_plugins()
        plugin_info = None
        for p in discovered_plugins:
            if p.id == plugin_id:
                plugin_info = p
                break
                
        if plugin_info:
            if self.plugin_manager.load_plugin(plugin_info):
                self.refresh_plugins()
                
    def enable_selected(self):
        """启用选中的插件"""
        selection = self.tree.selection()
        if not selection:
            return
            
        item = selection[0]
        values = self.tree.item(item, "values")
        plugin_id = values[0]
        
        if self.plugin_manager.enable_plugin(plugin_id):
            self.refresh_plugins()
            
    def disable_selected(self):
        """禁用选中的插件"""
        selection = self.tree.selection()
        if not selection:
            return
            
        item = selection[0]
        values = self.tree.item(item, "values")
        plugin_id = values[0]
        
        if self.plugin_manager.disable_plugin(plugin_id):
            self.refresh_plugins()
            
    def unload_selected(self):
        """卸载选中的插件"""
        selection = self.tree.selection()
        if not selection:
            return
            
        item = selection[0]
        values = self.tree.item(item, "values")
        plugin_id = values[0]
        
        if self.plugin_manager.unload_plugin(plugin_id):
            self.refresh_plugins()

6. 高级主题引擎与皮肤系统

6.1 完整的主题引擎实现

python 复制代码
"""
theme_engine.py

高级主题引擎与皮肤系统
"""
import tkinter as tk
from tkinter import ttk
from typing import Dict, List, Any, Optional, Tuple
from dataclasses import dataclass, field
from enum import Enum
import json
import colorsys
import os
from pathlib import Path

class ThemeType(Enum):
    """主题类型"""
    LIGHT = "light"          # 浅色主题
    DARK = "dark"            # 深色主题
    HIGH_CONTRAST = "high_contrast"  # 高对比度
    CUSTOM = "custom"        # 自定义主题

@dataclass
class ColorScheme:
    """颜色方案"""
    primary: str = "#3498DB"
    secondary: str = "#2ECC71"
    accent: str = "#E74C3C"
    background: str = "#ECF0F1"
    surface: str = "#FFFFFF"
    error: str = "#E74C3C"
    warning: str = "#F39C12"
    success: str = "#27AE60"
    info: str = "#3498DB"
    
    text_primary: str = "#2C3E50"
    text_secondary: str = "#7F8C8D"
    text_disabled: str = "#BDC3C7"
    
    border: str = "#BDC3C7"
    divider: str = "#ECF0F1"
    
    hover: str = "#F8F9FA"
    selected: str = "#E3F2FD"
    pressed: str = "#BBDEFB"
    
    def to_dict(self) -> Dict[str, str]:
        """转换为字典"""
        return {k: v for k, v in self.__dict__.items() 
                if not k.startswith('_')}
                
    @classmethod
    def from_dict(cls, data: Dict[str, str]) -> 'ColorScheme':
        """从字典创建"""
        return cls(**{k: v for k, v in data.items() 
                     if k in cls.__annotations__})

@dataclass
class Typography:
    """排版设置"""
    font_family: str = "微软雅黑, Segoe UI, Arial"
    font_size_small: int = 10
    font_size_normal: int = 12
    font_size_large: int = 14
    font_size_title: int = 18
    font_weight_normal: str = "normal"
    font_weight_bold: str = "bold"
    line_height: float = 1.5
    
@dataclass
class Spacing:
    """间距设置"""
    xs: int = 4
    sm: int = 8
    md: int = 12
    lg: int = 16
    xl: int = 24
    xxl: int = 32
    
@dataclass
class Shape:
    """形状设置"""
    border_radius_sm: int = 4
    border_radius_md: int = 8
    border_radius_lg: int = 12
    border_width: int = 1
    
@dataclass
class Shadow:
    """阴影设置"""
    sm: str = "0 1px 3px rgba(0,0,0,0.12)"
    md: str = "0 4px 6px rgba(0,0,0,0.1)"
    lg: str = "0 10px 15px rgba(0,0,0,0.1)"
    xl: str = "0 20px 25px rgba(0,0,0,0.1)"
    
@dataclass
class Theme:
    """主题"""
    id: str
    name: str
    type: ThemeType
    description: str = ""
    colors: ColorScheme = field(default_factory=ColorScheme)
    typography: Typography = field(default_factory=Typography)
    spacing: Spacing = field(default_factory=Spacing)
    shape: Shape = field(default_factory=Shape)
    shadow: Shadow = field(default_factory=Shadow)
    version: str = "1.0.0"
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        return {
            "id": self.id,
            "name": self.name,
            "type": self.type.value,
            "description": self.description,
            "version": self.version,
            "colors": self.colors.to_dict(),
            "typography": self.typography.__dict__,
            "spacing": self.spacing.__dict__,
            "shape": self.shape.__dict__,
            "shadow": self.shadow.__dict__
        }
        
    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> 'Theme':
        """从字典创建"""
        theme = cls(
            id=data["id"],
            name=data["name"],
            type=ThemeType(data["type"]),
            description=data.get("description", ""),
            version=data.get("version", "1.0.0")
        )
        
        if "colors" in data:
            theme.colors = ColorScheme.from_dict(data["colors"])
            
        if "typography" in data:
            theme.typography = Typography(**data["typography"])
            
        if "spacing" in data:
            theme.spacing = Spacing(**data["spacing"])
            
        if "shape" in data:
            theme.shape = Shape(**data["shape"])
            
        if "shadow" in data:
            theme.shadow = Shadow(**data["shadow"])
            
        return theme

class ThemeEngine:
    """主题引擎"""
    
    def __init__(self):
        self.themes: Dict[str, Theme] = {}
        self.current_theme: Optional[Theme] = None
        self.style = ttk.Style()
        
        # 注册的主题变化回调
        self.theme_change_callbacks: List[Callable] = []
        
        # 加载内置主题
        self.load_builtin_themes()
        
    def load_builtin_themes(self):
        """加载内置主题"""
        # 浅色主题
        light_theme = Theme(
            id="light",
            name="浅色主题",
            type=ThemeType.LIGHT,
            description="适合日间使用的明亮主题",
            colors=ColorScheme(
                primary="#3498DB",
                secondary="#2ECC71",
                accent="#E74C3C",
                background="#F8F9FA",
                surface="#FFFFFF",
                text_primary="#212529",
                text_secondary="#6C757D",
                border="#DEE2E6"
            )
        )
        self.register_theme(light_theme)
        
        # 深色主题
        dark_theme = Theme(
            id="dark", 
            name="深色主题",
            type=ThemeType.DARK,
            description="适合夜间使用的深色主题",
            colors=ColorScheme(
                primary="#3498DB",
                secondary="#2ECC71",
                accent="#E74C3C",
                background="#1C2833",
                surface="#2C3E50",
                text_primary="#ECF0F1",
                text_secondary="#BDC3C7",
                border="#566573"
            )
        )
        self.register_theme(dark_theme)
        
        # 高对比度主题
        hc_theme = Theme(
            id="high_contrast",
            name="高对比度主题",
            type=ThemeType.HIGH_CONTRAST,
            description="高可访问性高对比度主题",
            colors=ColorScheme(
                primary="#0000FF",
                secondary="#008000",
                accent="#FF0000",
                background="#000000",
                surface="#2A2A2A",
                text_primary="#FFFFFF",
                text_secondary="#CCCCCC",
                border="#FFFFFF"
            )
        )
        self.register_theme(hc_theme)
        
    def register_theme(self, theme: Theme):
        """注册主题"""
        self.themes[theme.id] = theme
        
    def load_theme_from_file(self, filepath: str) -> Optional[Theme]:
        """从文件加载主题"""
        try:
            with open(filepath, 'r', encoding='utf-8') as f:
                data = json.load(f)
                
            theme = Theme.from_dict(data)
            self.register_theme(theme)
            return theme
            
        except Exception as e:
            print(f"加载主题文件失败 {filepath}: {e}")
            return None
            
    def save_theme_to_file(self, theme: Theme, filepath: str):
        """保存主题到文件"""
        try:
            with open(filepath, 'w', encoding='utf-8') as f:
                json.dump(theme.to_dict(), f, indent=2, ensure_ascii=False)
            return True
        except Exception as e:
            print(f"保存主题文件失败 {filepath}: {e}")
            return False
            
    def apply_theme(self, theme_id: str) -> bool:
        """应用主题"""
        if theme_id not in self.themes:
            print(f"主题不存在: {theme_id}")
            return False
            
        theme = self.themes[theme_id]
        self.current_theme = theme
        
        # 应用tkinter样式
        self._apply_tkinter_theme(theme)
        
        # 触发主题变化回调
        for callback in self.theme_change_callbacks:
            try:
                callback(theme)
            except Exception as e:
                print(f"主题变化回调错误: {e}")
                
        return True
        
    def _apply_tkinter_theme(self, theme: Theme):
        """应用tkinter样式"""
        colors = theme.colors
        
        # 配置基础样式
        self.style.theme_use('clam')
        
        # 配置全局样式
        self.style.configure('.',
            background=colors.background,
            foreground=colors.text_primary,
            fieldbackground=colors.surface,
            troughcolor=colors.divider,
            selectbackground=colors.selected,
            selectforeground=colors.text_primary,
            borderwidth=theme.shape.border_width,
            focusthickness=3,
            focuscolor=''
        )
        
        # 配置Frame
        self.style.configure('TFrame',
            background=colors.background
        )
        
        # 配置Label
        self.style.configure('TLabel',
            background=colors.background,
            foreground=colors.text_primary,
            font=(theme.typography.font_family, theme.typography.font_size_normal)
        )
        
        # 配置LabelFrame
        self.style.configure('TLabelframe',
            background=colors.background,
            foreground=colors.text_primary,
            bordercolor=colors.border,
            relief='solid'
        )
        self.style.configure('TLabelframe.Label',
            background=colors.background,
            foreground=colors.text_primary
        )
        
        # 配置Button
        self._configure_button_styles(theme)
        
        # 配置Entry
        self._configure_entry_styles(theme)
        
        # 配置Combobox
        self._configure_combobox_styles(theme)
        
        # 配置Treeview
        self._configure_treeview_styles(theme)
        
        # 配置Progressbar
        self._configure_progressbar_styles(theme)
        
        # 配置Notebook
        self._configure_notebook_styles(theme)
        
        # 配置Scrollbar
        self._configure_scrollbar_styles(theme)
        
    def _configure_button_styles(self, theme: Theme):
        """配置按钮样式"""
        colors = theme.colors
        
        # 基础按钮
        self.style.configure('TButton',
            padding=[theme.spacing.md, theme.spacing.sm],
            background=colors.primary,
            foreground='white',
            borderwidth=0,
            focusthickness=3,
            focuscolor=colors.primary
        )
        self.style.map('TButton',
            background=[
                ('pressed', colors.pressed),
                ('active', colors.hover)
            ],
            foreground=[
                ('pressed', colors.text_primary),
                ('active', colors.text_primary)
            ]
        )
        
        # 次级按钮
        self.style.configure('Secondary.TButton',
            background=colors.secondary,
            foreground='white'
        )
        
        # 轮廓按钮
        self.style.configure('Outline.TButton',
            background='transparent',
            foreground=colors.primary,
            relief='solid',
            borderwidth=theme.shape.border_width
        )
        self.style.map('Outline.TButton',
            background=[
                ('pressed', colors.pressed),
                ('active', colors.hover)
            ]
        )
        
        # 文字按钮
        self.style.configure('Text.TButton',
            background='transparent',
            foreground=colors.primary,
            borderwidth=0,
            padding=[theme.spacing.xs, theme.spacing.xs]
        )
        
    def _configure_entry_styles(self, theme: Theme):
        """配置输入框样式"""
        colors = theme.colors
        
        self.style.configure('TEntry',
            fieldbackground=colors.surface,
            foreground=colors.text_primary,
            borderwidth=theme.shape.border_width,
            relief='solid',
            padding=[theme.spacing.sm, theme.spacing.xs],
            insertcolor=colors.text_primary
        )
        self.style.map('TEntry',
            fieldbackground=[
                ('readonly', colors.background),
                ('disabled', colors.divider)
            ],
            foreground=[
                ('readonly', colors.text_secondary),
                ('disabled', colors.text_disabled)
            ]
        )
        
    def _configure_combobox_styles(self, theme: Theme):
        """配置组合框样式"""
        colors = theme.colors
        
        self.style.configure('TCombobox',
            fieldbackground=colors.surface,
            foreground=colors.text_primary,
            borderwidth=theme.shape.border_width,
            relief='solid',
            padding=[theme.spacing.sm, theme.spacing.xs],
            arrowsize=12
        )
        self.style.map('TCombobox',
            fieldbackground=[
                ('readonly', colors.surface),
                ('disabled', colors.divider)
            ],
            foreground=[
                ('readonly', colors.text_primary),
                ('disabled', colors.text_disabled)
            ]
        )
        
    def _configure_treeview_styles(self, theme: Theme):
        """配置Treeview样式"""
        colors = theme.colors
        
        self.style.configure('Treeview',
            background=colors.surface,
            foreground=colors.text_primary,
            fieldbackground=colors.surface,
            rowheight=25,
            borderwidth=0
        )
        self.style.map('Treeview',
            background=[('selected', colors.selected)],
            foreground=[('selected', colors.text_primary)]
        )
        
        self.style.configure('Treeview.Heading',
            background=colors.background,
            foreground=colors.text_primary,
            borderwidth=0,
            relief='flat',
            padding=[theme.spacing.sm, theme.spacing.xs]
        )
        
    def _configure_progressbar_styles(self, theme: Theme):
        """配置进度条样式"""
        colors = theme.colors
        
        self.style.configure('Horizontal.TProgressbar',
            background=colors.primary,
            troughcolor=colors.divider,
            borderwidth=0,
            lightcolor=colors.primary,
            darkcolor=colors.primary
        )
        
    def _configure_notebook_styles(self, theme: Theme):
        """配置Notebook样式"""
        colors = theme.colors
        
        self.style.configure('TNotebook',
            background=colors.background,
            borderwidth=0,
            tabmargins=[0, 0, 0, 0]
        )
        
        self.style.configure('TNotebook.Tab',
            background=colors.divider,
            foreground=colors.text_secondary,
            borderwidth=0,
            padding=[theme.spacing.lg, theme.spacing.sm],
            font=(theme.typography.font_family, theme.typography.font_size_normal)
        )
        self.style.map('TNotebook.Tab',
            background=[
                ('selected', colors.background),
                ('active', colors.hover)
            ],
            foreground=[
                ('selected', colors.text_primary),
                ('active', colors.text_primary)
            ]
        )
        
    def _configure_scrollbar_styles(self, theme: Theme):
        """配置滚动条样式"""
        colors = theme.colors
        
        self.style.configure('Vertical.TScrollbar',
            background=colors.divider,
            troughcolor=colors.background,
            borderwidth=0,
            arrowsize=12
        )
        self.style.map('Vertical.TScrollbar',
            background=[('active', colors.border)]
        )
        
        self.style.configure('Horizontal.TScrollbar',
            background=colors.divider,
            troughcolor=colors.background,
            borderwidth=0,
            arrowsize=12
        )
        
    def register_theme_change_callback(self, callback: Callable):
        """注册主题变化回调"""
        self.theme_change_callbacks.append(callback)
        
    def get_current_theme(self) -> Optional[Theme]:
        """获取当前主题"""
        return self.current_theme
        
    def get_all_themes(self) -> List[Theme]:
        """获取所有主题"""
        return list(self.themes.values())
        
    def create_custom_theme(self, base_theme_id: str, 
                           name: str, 
                           color_overrides: Dict[str, str]) -> Theme:
        """创建自定义主题"""
        if base_theme_id not in self.themes:
            raise ValueError(f"基础主题不存在: {base_theme_id}")
            
        base_theme = self.themes[base_theme_id]
        
        # 创建新主题
        new_theme = Theme(
            id=f"custom_{int(time.time())}",
            name=name,
            type=ThemeType.CUSTOM,
            description=f"基于 {base_theme.name} 的自定义主题"
        )
        
        # 复制基础主题
        new_theme.colors = ColorScheme(**base_theme.colors.__dict__)
        new_theme.typography = Typography(**base_theme.typography.__dict__)
        new_theme.spacing = Spacing(**base_theme.spacing.__dict__)
        new_theme.shape = Shape(**base_theme.shape.__dict__)
        new_theme.shadow = Shadow(**base_theme.shadow.__dict__)
        
        # 应用颜色覆盖
        for key, value in color_overrides.items():
            if hasattr(new_theme.colors, key):
                setattr(new_theme.colors, key, value)
                
        # 注册新主题
        self.register_theme(new_theme)
        
        return new_theme

class ThemeEditor:
    """主题编辑器"""
    
    def __init__(self, parent: tk.Widget, theme_engine: ThemeEngine):
        self.parent = parent
        self.theme_engine = theme_engine
        self.current_theme: Optional[Theme] = None
        
        self.create_ui()
        
    def create_ui(self):
        """创建UI界面"""
        # 主框架
        main_frame = ttk.Frame(self.parent)
        main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 标题
        title = ttk.Label(main_frame,
                         text="主题编辑器",
                         font=("微软雅黑", 16, "bold"))
        title.pack(pady=(0, 10))
        
        # 控制面板
        control_frame = ttk.Frame(main_frame)
        control_frame.pack(fill=tk.X, pady=(0, 10))
        
        # 主题选择
        ttk.Label(control_frame, text="选择主题:").pack(side=tk.LEFT, padx=5)
        
        self.theme_var = tk.StringVar()
        self.theme_combo = ttk.Combobox(control_frame,
                                       textvariable=self.theme_var,
                                       state="readonly")
        self.theme_combo.pack(side=tk.LEFT, padx=5)
        self.theme_combo.bind("<<ComboboxSelected>>", self.on_theme_selected)
        
        # 创建自定义主题按钮
        ttk.Button(control_frame, text="创建自定义主题",
                  command=self.create_custom_theme).pack(side=tk.LEFT, padx=5)
                  
        # 保存主题按钮
        ttk.Button(control_frame, text="保存主题",
                  command=self.save_theme).pack(side=tk.LEFT, padx=5)
                  
        # 应用主题按钮
        ttk.Button(control_frame, text="应用主题",
                  command=self.apply_current_theme).pack(side=tk.LEFT, padx=5)
                  
        # 颜色编辑器
        self.color_editor = ColorEditor(main_frame, self)
        self.color_editor.pack(fill=tk.BOTH, expand=True, pady=(0, 10))
        
        # 预览区域
        preview_frame = ttk.LabelFrame(main_frame, text="主题预览", padding=10)
        preview_frame.pack(fill=tk.BOTH, expand=True)
        
        self.create_preview(preview_frame)
        
        # 初始化主题列表
        self.update_theme_list()
        
    def update_theme_list(self):
        """更新主题列表"""
        themes = self.theme_engine.get_all_themes()
        theme_names = [theme.name for theme in themes]
        self.theme_combo['values'] = theme_names
        
        if theme_names:
            self.theme_combo.set(theme_names[0])
            self.on_theme_selected()
            
    def on_theme_selected(self, event=None):
        """主题选择事件"""
        theme_name = self.theme_var.get()
        if not theme_name:
            return
            
        # 查找主题
        themes = self.theme_engine.get_all_themes()
        for theme in themes:
            if theme.name == theme_name:
                self.current_theme = theme
                self.color_editor.load_theme(theme)
                break
                
    def create_custom_theme(self):
        """创建自定义主题"""
        # 获取当前主题作为基础
        if not self.current_theme:
            return
            
        # 创建新主题名称
        new_name = f"{self.current_theme.name} (自定义)"
        
        # 创建自定义主题
        try:
            new_theme = self.theme_engine.create_custom_theme(
                self.current_theme.id,
                new_name,
                {}
            )
            
            # 更新UI
            self.update_theme_list()
            self.theme_combo.set(new_name)
            self.on_theme_selected()
            
        except Exception as e:
            print(f"创建自定义主题失败: {e}")
            
    def save_theme(self):
        """保存主题"""
        if not self.current_theme:
            return
            
        # 在实际应用中,这里会弹出文件对话框
        print(f"保存主题: {self.current_theme.name}")
        
    def apply_current_theme(self):
        """应用当前主题"""
        if self.current_theme:
            self.theme_engine.apply_theme(self.current_theme.id)
            
    def create_preview(self, parent: tk.Widget):
        """创建预览区域"""
        # 使用框架展示各种控件
        preview_frame = ttk.Frame(parent)
        preview_frame.pack(fill=tk.BOTH, expand=True)
        
        # 行1: 标签和按钮
        row1 = ttk.Frame(preview_frame)
        row1.pack(fill=tk.X, pady=5)
        
        ttk.Label(row1, text="标签:").pack(side=tk.LEFT, padx=5)
        ttk.Button(row1, text="主按钮").pack(side=tk.LEFT, padx=5)
        ttk.Button(row1, text="次级按钮", style="Secondary.TButton").pack(side=tk.LEFT, padx=5)
        
        # 行2: 输入控件
        row2 = ttk.Frame(preview_frame)
        row2.pack(fill=tk.X, pady=5)
        
        ttk.Label(row2, text="输入:").pack(side=tk.LEFT, padx=5)
        ttk.Entry(row2, width=20).pack(side=tk.LEFT, padx=5)
        ttk.Combobox(row2, values=["选项1", "选项2", "选项3"], width=15).pack(side=tk.LEFT, padx=5)
        
        # 行3: 进度条
        row3 = ttk.Frame(preview_frame)
        row3.pack(fill=tk.X, pady=5)
        
        ttk.Label(row3, text="进度:").pack(side=tk.LEFT, padx=5)
        progress = ttk.Progressbar(row3, length=200, mode='determinate')
        progress.pack(side=tk.LEFT, padx=5)
        progress['value'] = 50
        
        # 行4: 复选框和单选按钮
        row4 = ttk.Frame(preview_frame)
        row4.pack(fill=tk.X, pady=5)
        
        ttk.Checkbutton(row4, text="复选框").pack(side=tk.LEFT, padx=5)
        ttk.Radiobutton(row4, text="单选按钮1", value=1).pack(side=tk.LEFT, padx=5)
        ttk.Radiobutton(row4, text="单选按钮2", value=2).pack(side=tk.LEFT, padx=5)
        
        # 行5: 缩放条
        row5 = ttk.Frame(preview_frame)
        row5.pack(fill=tk.X, pady=5)
        
        ttk.Label(row5, text="缩放:").pack(side=tk.LEFT, padx=5)
        ttk.Scale(row5, from_=0, to=100, length=200).pack(side=tk.LEFT, padx=5)

class ColorEditor(ttk.Frame):
    """颜色编辑器"""
    
    def __init__(self, parent: tk.Widget, theme_editor: ThemeEditor):
        super().__init__(parent)
        self.theme_editor = theme_editor
        self.color_vars: Dict[str, tk.StringVar] = {}
        self.color_buttons: Dict[str, tk.Button] = {}
        
        self.create_ui()
        
    def create_ui(self):
        """创建UI界面"""
        # 颜色网格
        self.color_grid = ttk.Frame(self)
        self.color_grid.pack(fill=tk.BOTH, expand=True)
        
    def load_theme(self, theme: Theme):
        """加载主题"""
        # 清除现有颜色项
        for widget in self.color_grid.winfo_children():
            widget.destroy()
            
        self.color_vars.clear()
        self.color_buttons.clear()
        
        # 获取颜色字典
        color_dict = theme.colors.to_dict()
        
        # 按类别分组颜色
        color_categories = {
            "主色": ["primary", "secondary", "accent"],
            "背景色": ["background", "surface"],
            "文本色": ["text_primary", "text_secondary", "text_disabled"],
            "状态色": ["error", "warning", "success", "info"],
            "边框色": ["border", "divider"],
            "交互色": ["hover", "selected", "pressed"]
        }
        
        row = 0
        for category, color_keys in color_categories.items():
            # 分类标签
            ttk.Label(self.color_grid, 
                     text=category,
                     font=("微软雅黑", 10, "bold")).grid(
                row=row, column=0, columnspan=3, sticky=tk.W, pady=(10, 5)
            )
            row += 1
            
            # 颜色项
            for i, key in enumerate(color_keys):
                if key in color_dict:
                    col = i % 3
                    
                    # 颜色标签
                    label = ttk.Label(self.color_grid, text=key.replace('_', ' ').title())
                    label.grid(row=row, column=col*2, sticky=tk.W, padx=5, pady=2)
                    
                    # 颜色值输入
                    color_var = tk.StringVar(value=color_dict[key])
                    self.color_vars[key] = color_var
                    
                    entry = ttk.Entry(self.color_grid, textvariable=color_var, width=10)
                    entry.grid(row=row, column=col*2+1, sticky=tk.W, padx=5, pady=2)
                    
                    # 颜色选择按钮
                    btn = tk.Button(self.color_grid, 
                                  bg=color_dict[key],
                                  width=3,
                                  command=lambda k=key: self.choose_color(k))
                    btn.grid(row=row, column=col*2+2, sticky=tk.W, padx=5, pady=2)
                    self.color_buttons[key] = btn
                    
                    # 绑定输入变化事件
                    color_var.trace('w', lambda *args, k=key: self.on_color_changed(k))
                    
                    if col == 2:  # 每行3个
                        row += 1
                        
            if row % 3 != 0:  # 确保下一行从新行开始
                row += 1
                
    def choose_color(self, color_key: str):
        """选择颜色"""
        from tkinter import colorchooser
        
        # 弹出颜色选择器
        color_code = colorchooser.askcolor(
            initialcolor=self.color_vars[color_key].get()
        )
        
        if color_code[1]:  # 用户选择了颜色
            self.color_vars[color_key].set(color_code[1])
            
    def on_color_changed(self, color_key: str):
        """颜色变化事件"""
        color_value = self.color_vars[color_key].get()
        
        # 更新按钮颜色
        if color_key in self.color_buttons:
            self.color_buttons[color_key].config(bg=color_value)
            
        # 更新主题
        if self.theme_editor.current_theme:
            setattr(self.theme_editor.current_theme.colors, color_key, color_value)

7. 分布式系统架构概念

7.1 分布式通信框架

python 复制代码
"""
distributed_framework.py

分布式系统架构
"""
import socket
import threading
import queue
import time
import json
import pickle
from typing import Dict, List, Any, Optional, Tuple, Callable
from dataclasses import dataclass, field
from enum import Enum
import struct
import zlib
import hashlib
import ssl

class NodeType(Enum):
    """节点类型"""
    MASTER = "master"        # 主节点
    WORKER = "worker"        # 工作节点
    DISPLAY = "display"      # 显示节点
    STORAGE = "storage"      # 存储节点
    GATEWAY = "gateway"      # 网关节点

class MessageType(Enum):
    """消息类型"""
    HEARTBEAT = "heartbeat"  # 心跳
    DATA = "data"           # 数据
    COMMAND = "command"     # 命令
    STATUS = "status"       # 状态
    CONFIG = "config"       # 配置
    ALERT = "alert"         # 告警
    SYNC = "sync"           # 同步

@dataclass
class NetworkMessage:
    """网络消息"""
    msg_id: str
    type: MessageType
    source: str
    target: str
    timestamp: float = field(default_factory=time.time)
    data: Any = None
    metadata: Dict[str, Any] = field(default_factory=dict)
    
    def to_bytes(self) -> bytes:
        """转换为字节流"""
        # 使用pickle序列化
        data = {
            'msg_id': self.msg_id,
            'type': self.type.value,
            'source': self.source,
            'target': self.target,
            'timestamp': self.timestamp,
            'data': self.data,
            'metadata': self.metadata
        }
        
        # 压缩数据
        pickled = pickle.dumps(data)
        compressed = zlib.compress(pickled)
        
        # 添加消息头
        header = struct.pack('!I', len(compressed))
        
        return header + compressed
        
    @classmethod
    def from_bytes(cls, data: bytes) -> 'NetworkMessage':
        """从字节流创建"""
        # 解压数据
        decompressed = zlib.decompress(data)
        obj = pickle.loads(decompressed)
        
        return cls(
            msg_id=obj['msg_id'],
            type=MessageType(obj['type']),
            source=obj['source'],
            target=obj['target'],
            timestamp=obj['timestamp'],
            data=obj['data'],
            metadata=obj['metadata']
        )

class NetworkNode:
    """网络节点"""
    
    def __init__(self, node_id: str, node_type: NodeType, host: str = '0.0.0.0', port: int = 0):
        self.node_id = node_id
        self.node_type = node_type
        self.host = host
        self.port = port
        
        # 网络连接
        self.socket: Optional[socket.socket] = None
        self.connections: Dict[str, socket.socket] = {}
        
        # 消息处理
        self.incoming_queue = queue.Queue()
        self.outgoing_queue = queue.Queue()
        self.message_handlers: Dict[MessageType, List[Callable]] = {}
        
        # 节点状态
        self.running = False
        self.connected_nodes: Dict[str, Dict] = {}
        
        # 线程
        self.receive_thread: Optional[threading.Thread] = None
        self.send_thread: Optional[threading.Thread] = None
        self.process_thread: Optional[threading.Thread] = None
        
    def start(self):
        """启动节点"""
        self.running = True
        
        # 创建socket
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        
        # 绑定端口
        self.socket.bind((self.host, self.port))
        self.port = self.socket.getsockname()[1]  # 获取实际端口
        
        # 监听连接
        self.socket.listen(5)
        self.socket.setblocking(False)
        
        # 启动线程
        self.receive_thread = threading.Thread(target=self._accept_connections, daemon=True)
        self.send_thread = threading.Thread(target=self._send_loop, daemon=True)
        self.process_thread = threading.Thread(target=self._process_loop, daemon=True)
        
        self.receive_thread.start()
        self.send_thread.start()
        self.process_thread.start()
        
    def stop(self):
        """停止节点"""
        self.running = False
        
        # 关闭连接
        for conn in self.connections.values():
            try:
                conn.close()
            except:
                pass
                
        if self.socket:
            self.socket.close()
            
    def connect_to(self, host: str, port: int) -> bool:
        """连接到其他节点"""
        try:
            conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            conn.connect((host, port))
            
            # 发送连接信息
            conn_info = {
                'node_id': self.node_id,
                'node_type': self.node_type.value,
                'host': self.host,
                'port': self.port
            }
            
            self._send_raw(conn, conn_info)
            
            # 接收对方信息
            response = self._receive_raw(conn)
            if response and 'node_id' in response:
                node_id = response['node_id']
                self.connections[node_id] = conn
                self.connected_nodes[node_id] = response
                
                # 启动接收线程
                threading.Thread(
                    target=self._receive_from_connection,
                    args=(node_id, conn),
                    daemon=True
                ).start()
                
                return True
                
        except Exception as e:
            print(f"连接失败 {host}:{port}: {e}")
            
        return False
        
    def send_message(self, message: NetworkMessage):
        """发送消息"""
        self.outgoing_queue.put(message)
        
    def broadcast_message(self, message: NetworkMessage, exclude: List[str] = None):
        """广播消息"""
        exclude = exclude or []
        
        for node_id in self.connections:
            if node_id not in exclude:
                msg_copy = NetworkMessage(
                    msg_id=message.msg_id + f"_{node_id}",
                    type=message.type,
                    source=message.source,
                    target=node_id,
                    timestamp=message.timestamp,
                    data=message.data,
                    metadata=message.metadata
                )
                self.send_message(msg_copy)
                
    def register_message_handler(self, msg_type: MessageType, handler: Callable):
        """注册消息处理函数"""
        if msg_type not in self.message_handlers:
            self.message_handlers[msg_type] = []
        self.message_handlers[msg_type].append(handler)
        
    def _accept_connections(self):
        """接受连接"""
        while self.running:
            try:
                # 非阻塞接受连接
                readable, _, _ = select.select([self.socket], [], [], 0.1)
                if self.socket in readable:
                    conn, addr = self.socket.accept()
                    
                    # 接收连接信息
                    conn_info = self._receive_raw(conn)
                    if conn_info and 'node_id' in conn_info:
                        node_id = conn_info['node_id']
                        
                        # 发送本节点信息
                        self_info = {
                            'node_id': self.node_id,
                            'node_type': self.node_type.value,
                            'host': self.host,
                            'port': self.port
                        }
                        self._send_raw(conn, self_info)
                        
                        # 存储连接
                        self.connections[node_id] = conn
                        self.connected_nodes[node_id] = conn_info
                        
                        # 启动接收线程
                        threading.Thread(
                            target=self._receive_from_connection,
                            args=(node_id, conn),
                            daemon=True
                        ).start()
                        
        except Exception as e:
            if self.running:  # 只在运行时打印错误
                print(f"接受连接错误: {e}")
        time.sleep(0.1)
        
    def _receive_from_connection(self, node_id: str, conn: socket.socket):
        """从连接接收数据"""
        buffer = b""
        expected_length = 0
        
        while self.running and node_id in self.connections:
            try:
                # 接收数据
                data = conn.recv(4096)
                if not data:  # 连接关闭
                    break
                    
                buffer += data
                
                # 处理完整消息
                while len(buffer) >= 4:
                    if expected_length == 0:
                        # 读取消息头
                        if len(buffer) >= 4:
                            header = buffer[:4]
                            expected_length = struct.unpack('!I', header)[0]
                            buffer = buffer[4:]
                        else:
                            break
                            
                    if len(buffer) >= expected_length:
                        # 提取完整消息
                        message_data = buffer[:expected_length]
                        buffer = buffer[expected_length:]
                        
                        try:
                            message = NetworkMessage.from_bytes(message_data)
                            self.incoming_queue.put((node_id, message))
                        except Exception as e:
                            print(f"解析消息失败: {e}")
                            
                        expected_length = 0
                    else:
                        break
                        
            except (ConnectionResetError, ConnectionAbortedError, TimeoutError):
                break
            except Exception as e:
                print(f"接收数据错误: {e}")
                break
                
        # 连接断开
        self._handle_disconnection(node_id)
        
    def _send_loop(self):
        """发送循环"""
        while self.running:
            try:
                # 获取待发送消息
                message = self.outgoing_queue.get(timeout=0.1)
                
                # 发送到目标节点
                if message.target in self.connections:
                    conn = self.connections[message.target]
                    self._send_message_to_connection(conn, message)
                    
            except queue.Empty:
                continue
            except Exception as e:
                print(f"发送消息错误: {e}")
                
    def _process_loop(self):
        """处理循环"""
        while self.running:
            try:
                # 获取接收到的消息
                source_node, message = self.incoming_queue.get(timeout=0.1)
                
                # 调用消息处理函数
                if message.type in self.message_handlers:
                    for handler in self.message_handlers[message.type]:
                        try:
                            handler(source_node, message)
                        except Exception as e:
                            print(f"消息处理错误: {e}")
                            
            except queue.Empty:
                continue
            except Exception as e:
                print(f"处理消息错误: {e}")
                
    def _send_raw(self, conn: socket.socket, data: Any):
        """发送原始数据"""
        try:
            # 序列化数据
            pickled = pickle.dumps(data)
            compressed = zlib.compress(pickled)
            
            # 发送长度前缀
            header = struct.pack('!I', len(compressed))
            conn.sendall(header + compressed)
            
        except Exception as e:
            print(f"发送原始数据错误: {e}")
            
    def _receive_raw(self, conn: socket.socket) -> Optional[Any]:
        """接收原始数据"""
        try:
            # 接收长度前缀
            header = conn.recv(4)
            if len(header) < 4:
                return None
                
            data_length = struct.unpack('!I', header)[0]
            
            # 接收数据
            received = 0
            chunks = []
            while received < data_length:
                chunk = conn.recv(min(data_length - received, 4096))
                if not chunk:
                    return None
                chunks.append(chunk)
                received += len(chunk)
                
            data = b''.join(chunks)
            
            # 解压和反序列化
            decompressed = zlib.decompress(data)
            return pickle.loads(decompressed)
            
        except Exception as e:
            print(f"接收原始数据错误: {e}")
            return None
            
    def _send_message_to_connection(self, conn: socket.socket, message: NetworkMessage):
        """发送消息到连接"""
        try:
            data = message.to_bytes()
            conn.sendall(data)
        except Exception as e:
            print(f"发送消息到连接错误: {e}")
            
    def _handle_disconnection(self, node_id: str):
        """处理连接断开"""
        if node_id in self.connections:
            try:
                self.connections[node_id].close()
            except:
                pass
                
            del self.connections[node_id]
            
        if node_id in self.connected_nodes:
            del self.connected_nodes[node_id]
            
        print(f"节点 {node_id} 已断开连接")
        
    def get_connected_nodes(self) -> Dict[str, Dict]:
        """获取已连接的节点"""
        return self.connected_nodes.copy()

class DistributedSystemManager:
    """分布式系统管理器"""
    
    def __init__(self, master_host: str = 'localhost', master_port: int = 8888):
        self.master_host = master_host
        self.master_port = master_port
        self.master_node: Optional[NetworkNode] = None
        self.worker_nodes: Dict[str, NetworkNode] = {}
        self.node_registry: Dict[str, Dict] = {}
        
    def start_master(self) -> bool:
        """启动主节点"""
        try:
            self.master_node = NetworkNode(
                node_id="master",
                node_type=NodeType.MASTER,
                host=self.master_host,
                port=self.master_port
            )
            
            # 注册消息处理器
            self.master_node.register_message_handler(
                MessageType.HEARTBEAT, self.handle_heartbeat
            )
            self.master_node.register_message_handler(
                MessageType.DATA, self.handle_data
            )
            self.master_node.register_message_handler(
                MessageType.STATUS, self.handle_status
            )
            
            # 启动主节点
            self.master_node.start()
            
            # 启动心跳监控
            threading.Thread(target=self._heartbeat_monitor, daemon=True).start()
            
            return True
            
        except Exception as e:
            print(f"启动主节点失败: {e}")
            return False
            
    def start_worker(self, worker_id: str, host: str = 'localhost', port: int = 0) -> bool:
        """启动工作节点"""
        try:
            worker_node = NetworkNode(
                node_id=worker_id,
                node_type=NodeType.WORKER,
                host=host,
                port=port
            )
            
            # 注册消息处理器
            worker_node.register_message_handler(
                MessageType.COMMAND, self.handle_command
            )
            worker_node.register_message_handler(
                MessageType.CONFIG, self.handle_config
            )
            
            # 启动工作节点
            worker_node.start()
            
            # 连接到主节点
            if worker_node.connect_to(self.master_host, self.master_port):
                self.worker_nodes[worker_id] = worker_node
                
                # 启动心跳发送
                threading.Thread(
                    target=self._send_heartbeats,
                    args=(worker_node,),
                    daemon=True
                ).start()
                
                return True
            else:
                print(f"工作节点 {worker_id} 连接主节点失败")
                return False
                
        except Exception as e:
            print(f"启动工作节点失败: {e}")
            return False
            
    def handle_heartbeat(self, source_node: str, message: NetworkMessage):
        """处理心跳消息"""
        node_id = source_node
        heartbeat_data = message.data or {}
        
        # 更新节点注册表
        if node_id not in self.node_registry:
            self.node_registry[node_id] = {
                'node_id': node_id,
                'last_heartbeat': time.time(),
                'status': 'online',
                'data': heartbeat_data
            }
        else:
            self.node_registry[node_id]['last_heartbeat'] = time.time()
            self.node_registry[node_id]['data'].update(heartbeat_data)
            
    def handle_data(self, source_node: str, message: NetworkMessage):
        """处理数据消息"""
        # 在实际系统中,这里会处理数据并可能转发给其他节点
        print(f"收到来自 {source_node} 的数据: {message.data}")
        
    def handle_status(self, source_node: str, message: NetworkMessage):
        """处理状态消息"""
        node_id = source_node
        status_data = message.data or {}
        
        if node_id in self.node_registry:
            self.node_registry[node_id]['status'] = status_data.get('status', 'unknown')
            
    def handle_command(self, source_node: str, message: NetworkMessage):
        """处理命令消息"""
        # 工作节点处理来自主节点的命令
        command = message.data
        print(f"节点 {source_node} 收到命令: {command}")
        
    def handle_config(self, source_node: str, message: NetworkMessage):
        """处理配置消息"""
        # 工作节点处理来自主节点的配置
        config = message.data
        print(f"节点 {source_node} 收到配置: {config}")
        
    def _heartbeat_monitor(self):
        """心跳监控"""
        while self.master_node and self.master_node.running:
            current_time = time.time()
            
            # 检查所有节点的最后心跳时间
            for node_id, node_info in list(self.node_registry.items()):
                last_heartbeat = node_info.get('last_heartbeat', 0)
                if current_time - last_heartbeat > 10:  # 10秒超时
                    # 标记为离线
                    self.node_registry[node_id]['status'] = 'offline'
                    
                    # 发送节点离线通知
                    offline_message = NetworkMessage(
                        msg_id=f"offline_{node_id}_{int(time.time())}",
                        type=MessageType.ALERT,
                        source="master",
                        target="all",
                        data={
                            'node_id': node_id,
                            'status': 'offline',
                            'timestamp': current_time
                        }
                    )
                    self.master_node.broadcast_message(offline_message)
                    
            time.sleep(5)  # 每5秒检查一次
            
    def _send_heartbeats(self, worker_node: NetworkNode):
        """发送心跳"""
        while worker_node and worker_node.running:
            try:
                heartbeat_message = NetworkMessage(
                    msg_id=f"heartbeat_{worker_node.node_id}_{int(time.time())}",
                    type=MessageType.HEARTBEAT,
                    source=worker_node.node_id,
                    target="master",
                    data={
                        'cpu_usage': 0,  # 这里可以添加实际系统指标
                        'memory_usage': 0,
                        'queue_size': 0,
                        'timestamp': time.time()
                    }
                )
                
                worker_node.send_message(heartbeat_message)
                
            except Exception as e:
                print(f"发送心跳失败: {e}")
                
            time.sleep(3)  # 每3秒发送一次心跳
            
    def send_command_to_worker(self, worker_id: str, command: Dict[str, Any]):
        """发送命令到工作节点"""
        if self.master_node and worker_id in self.worker_nodes:
            command_message = NetworkMessage(
                msg_id=f"command_{int(time.time())}",
                type=MessageType.COMMAND,
                source="master",
                target=worker_id,
                data=command
            )
            self.master_node.send_message(command_message)
            
    def broadcast_command(self, command: Dict[str, Any]):
        """广播命令到所有工作节点"""
        if self.master_node:
            for worker_id in self.worker_nodes:
                self.send_command_to_worker(worker_id, command)
                
    def get_system_status(self) -> Dict[str, Any]:
        """获取系统状态"""
        online_nodes = 0
        offline_nodes = 0
        
        for node_info in self.node_registry.values():
            if node_info.get('status') == 'online':
                online_nodes += 1
            else:
                offline_nodes += 1
                
        return {
            'total_nodes': len(self.node_registry),
            'online_nodes': online_nodes,
            'offline_nodes': offline_nodes,
            'nodes': self.node_registry
        }

8. 系统集成与测试

8.1 完整集成系统实现

python 复制代码
"""
ewcc_integrated_system.py

综合电子战指挥控制台完整系统
"""
import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import threading
import time
import json
import os
from typing import Dict, List, Any, Optional, Tuple
from datetime import datetime
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import numpy as np
import queue

from view_manager import ViewManager, ViewType, ViewConfig, BaseView
from data_pipeline import DataPipeline, DataPipelineManager
from plugin_system import PluginManager, BasePlugin, PluginInfo
from theme_engine import ThemeEngine, Theme, ThemeType
from distributed_framework import DistributedSystemManager

class EWCCIntegratedSystem:
    """综合电子战指挥控制台完整系统"""
    
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("综合电子战指挥控制台")
        self.root.geometry("1600x900")
        
        # 设置图标
        try:
            self.root.iconbitmap("ewcc_icon.ico")
        except:
            pass
            
        # 系统组件
        self.view_manager = None
        self.plugin_manager = None
        self.theme_engine = None
        self.data_pipeline_manager = None
        self.distributed_manager = None
        
        # 系统状态
        self.system_running = False
        self.current_mode = "standalone"  # standalone, distributed
        
        # 数据缓存
        self.data_cache = {}
        self.alert_queue = queue.Queue()
        
        # 构建UI
        self.setup_system()
        self.create_main_ui()
        
        # 窗口居中
        self.center_window()
        
    def setup_system(self):
        """设置系统"""
        # 创建主题引擎
        self.theme_engine = ThemeEngine()
        
        # 创建视图管理器
        self.view_manager = ViewManager(self.root)
        
        # 创建插件管理器
        self.plugin_manager = PluginManager(self)
        self.plugin_manager.add_plugin_dir("./plugins")
        
        # 创建数据流水线管理器
        self.data_pipeline_manager = DataPipelineManager()
        
        # 创建分布式管理器
        self.distributed_manager = DistributedSystemManager()
        
    def create_main_ui(self):
        """创建主UI界面"""
        # 应用主题
        self.theme_engine.apply_theme("dark")
        
        # 主菜单
        self.create_menu_bar()
        
        # 主容器
        main_container = ttk.Frame(self.root)
        main_container.pack(fill=tk.BOTH, expand=True, padx=2, pady=2)
        
        # 标题栏
        self.create_title_bar(main_container)
        
        # 主内容区域
        content_frame = ttk.Frame(main_container)
        content_frame.pack(fill=tk.BOTH, expand=True, pady=5)
        
        # 左侧工具栏
        self.create_toolbar(content_frame)
        
        # 中央视图区域
        self.create_view_area(content_frame)
        
        # 右侧状态栏
        self.create_status_bar(content_frame)
        
        # 系统托盘
        self.create_system_tray()
        
    def create_menu_bar(self):
        """创建菜单栏"""
        menubar = tk.Menu(self.root)
        self.root.config(menu=menubar)
        
        # 文件菜单
        file_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="文件", menu=file_menu)
        file_menu.add_command(label="新建工程", command=self.new_project)
        file_menu.add_command(label="打开工程", command=self.open_project)
        file_menu.add_command(label="保存工程", command=self.save_project)
        file_menu.add_separator()
        file_menu.add_command(label="导入数据", command=self.import_data)
        file_menu.add_command(label="导出数据", command=self.export_data)
        file_menu.add_separator()
        file_menu.add_command(label="系统设置", command=self.system_settings)
        file_menu.add_command(label="退出", command=self.quit_system)
        
        # 视图菜单
        view_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="视图", menu=view_menu)
        
        # 视图子菜单
        view_submenu = tk.Menu(view_menu, tearoff=0)
        view_menu.add_cascade(label="显示视图", menu=view_submenu)
        
        view_types = [
            ("战场态势", "battlefield"),
            ("频谱监测", "spectrum"),
            ("资源管理", "resource"),
            ("日志信息", "log"),
            ("告警显示", "alert"),
            ("分析视图", "analysis")
        ]
        
        for name, view_type in view_types:
            view_submenu.add_command(
                label=name,
                command=lambda vt=view_type: self.show_view(vt)
            )
            
        # 布局子菜单
        layout_menu = tk.Menu(view_menu, tearoff=0)
        view_menu.add_cascade(label="布局", menu=layout_menu)
        layout_menu.add_command(label="默认布局", 
                               command=lambda: self.apply_layout("default"))
        layout_menu.add_command(label="分析布局", 
                               command=lambda: self.apply_layout("analysis"))
        layout_menu.add_command(label="监控布局", 
                               command=lambda: self.apply_layout("monitor"))
        layout_menu.add_separator()
        layout_menu.add_command(label="保存当前布局", 
                               command=self.save_current_layout)
        layout_menu.add_command(label="管理布局", 
                               command=self.manage_layouts)
        
        # 主题子菜单
        theme_menu = tk.Menu(view_menu, tearoff=0)
        view_menu.add_cascade(label="主题", menu=theme_menu)
        
        for theme in self.theme_engine.get_all_themes():
            theme_menu.add_command(
                label=theme.name,
                command=lambda t=theme.id: self.theme_engine.apply_theme(t)
            )
            
        theme_menu.add_separator()
        theme_menu.add_command(label="主题编辑器", 
                              command=self.open_theme_editor)
        
        # 工具菜单
        tool_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="工具", menu=tool_menu)
        tool_menu.add_command(label="插件管理器", 
                             command=self.open_plugin_manager)
        tool_menu.add_command(label="数据流水线", 
                             command=self.open_data_pipeline)
        tool_menu.add_command(label="系统监控", 
                             command=self.open_system_monitor)
        tool_menu.add_command(label="性能分析", 
                             command=self.open_performance_analyzer)
        
        # 系统菜单
        system_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="系统", menu=system_menu)
        system_menu.add_command(label="启动系统", 
                               command=self.start_system)
        system_menu.add_command(label="停止系统", 
                               command=self.stop_system)
        system_menu.add_separator()
        system_menu.add_command(label="连接集群", 
                               command=self.connect_to_cluster)
        system_menu.add_command(label="断开集群", 
                               command=self.disconnect_from_cluster)
        system_menu.add_separator()
        system_menu.add_command(label="系统日志", 
                               command=self.show_system_log)
        system_menu.add_command(label="关于", 
                               command=self.show_about)
        
        # 帮助菜单
        help_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="帮助", menu=help_menu)
        help_menu.add_command(label="用户手册", 
                             command=self.show_user_manual)
        help_menu.add_command(label="快捷键", 
                             command=self.show_shortcuts)
        help_menu.add_separator()
        help_menu.add_command(label="检查更新", 
                             command=self.check_for_updates)
        help_menu.add_command(label="技术支持", 
                             command=self.show_technical_support)
        
    def create_title_bar(self, parent):
        """创建标题栏"""
        title_frame = ttk.Frame(parent)
        title_frame.pack(fill=tk.X, pady=(0, 5))
        
        # 系统标题
        title_label = ttk.Label(
            title_frame,
            text="综合电子战指挥控制台",
            font=("微软雅黑", 20, "bold"),
            foreground="#3498DB"
        )
        title_label.pack(side=tk.LEFT, padx=10)
        
        # 系统状态
        self.system_status_var = tk.StringVar(value="就绪")
        status_label = ttk.Label(
            title_frame,
            textvariable=self.system_status_var,
            font=("微软雅黑", 10),
            foreground="#2ECC71"
        )
        status_label.pack(side=tk.RIGHT, padx=10)
        
    def create_toolbar(self, parent):
        """创建工具栏"""
        toolbar_frame = ttk.Frame(parent, width=60)
        toolbar_frame.pack(side=tk.LEFT, fill=tk.Y, padx=(0, 5))
        toolbar_frame.pack_propagate(False)
        
        # 工具栏按钮
        tools = [
            ("🏠", "主页", self.show_home),
            ("🗺️", "态势", lambda: self.show_view("battlefield")),
            ("📡", "频谱", lambda: self.show_view("spectrum")),
            ("📊", "分析", lambda: self.show_view("analysis")),
            ("🔧", "工具", self.open_tools),
            ("⚙️", "设置", self.system_settings),
            ("🔌", "插件", self.open_plugin_manager),
            ("📈", "监控", self.open_system_monitor)
        ]
        
        for icon, tooltip, command in tools:
            btn = ttk.Button(
                toolbar_frame,
                text=icon,
                command=command,
                width=4
            )
            btn.pack(pady=2)
            
            # 添加工具提示
            self.create_tooltip(btn, tooltip)
            
    def create_view_area(self, parent):
        """创建视图区域"""
        # 视图容器
        self.view_container = ttk.Frame(parent)
        self.view_container.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        
        # 创建默认视图
        self.create_default_views()
        
    def create_default_views(self):
        """创建默认视图"""
        # 战场态势视图
        battlefield_config = ViewConfig(
            id="battlefield",
            type=ViewType.BATTLEFIELD,
            title="战场态势",
            size=(600, 400)
        )
        self.view_manager.create_view(battlefield_config)
        
        # 频谱监测视图
        spectrum_config = ViewConfig(
            id="spectrum",
            type=ViewType.SPECTRUM,
            title="频谱监测",
            size=(400, 300)
        )
        self.view_manager.create_view(spectrum_config)
        
        # 资源管理视图
        resource_config = ViewConfig(
            id="resource",
            type=ViewType.RESOURCE,
            title="资源管理",
            size=(400, 300)
        )
        self.view_manager.create_view(resource_config)
        
        # 应用默认布局
        self.view_manager.apply_layout("default")
        
    def create_status_bar(self, parent):
        """创建状态栏"""
        status_frame = ttk.Frame(parent, width=300)
        status_frame.pack(side=tk.RIGHT, fill=tk.Y, padx=(5, 0))
        status_frame.pack_propagate(False)
        
        # 系统状态
        status_title = ttk.Label(
            status_frame,
            text="系统状态",
            font=("微软雅黑", 11, "bold")
        )
        status_title.pack(pady=(5, 10))
        
        # 状态指标
        self.status_vars = {}
        status_items = [
            ("系统", "就绪", "system"),
            ("CPU", "0%", "cpu"),
            ("内存", "0%", "memory"),
            ("网络", "正常", "network"),
            ("数据流", "0条/秒", "data_rate"),
            ("告警", "0", "alerts")
        ]
        
        for label, value, key in status_items:
            frame = ttk.Frame(status_frame)
            frame.pack(fill=tk.X, padx=5, pady=2)
            
            ttk.Label(frame, text=label + ":", width=8).pack(side=tk.LEFT)
            
            var = tk.StringVar(value=value)
            ttk.Label(frame, textvariable=var, 
                     font=("Consolas", 9)).pack(side=tk.RIGHT)
            
            self.status_vars[key] = var
            
        # 节点状态
        node_frame = ttk.LabelFrame(status_frame, text="节点状态", padding=5)
        node_frame.pack(fill=tk.X, padx=5, pady=(10, 5))
        
        self.node_tree = ttk.Treeview(node_frame, 
                                     columns=("状态",), 
                                     show="tree", 
                                     height=8)
        self.node_tree.pack(fill=tk.BOTH, expand=True)
        
        # 告警列表
        alert_frame = ttk.LabelFrame(status_frame, text="最近告警", padding=5)
        alert_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        self.alert_listbox = tk.Listbox(
            alert_frame,
            bg="#1C2833",
            fg="#ECF0F1",
            font=("Consolas", 8),
            height=6
        )
        scrollbar = ttk.Scrollbar(alert_frame, orient=tk.VERTICAL,
                                 command=self.alert_listbox.yview)
        self.alert_listbox.configure(yscrollcommand=scrollbar.set)
        
        self.alert_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
    def create_system_tray(self):
        """创建系统托盘"""
        # 在实际应用中,这里会创建系统托盘图标
        pass
        
    def create_tooltip(self, widget, text):
        """创建工具提示"""
        def enter(event):
            x, y, _, _ = widget.bbox("insert")
            x += widget.winfo_rootx() + 25
            y += widget.winfo_rooty() + 25
            
            self.tooltip = tk.Toplevel(widget)
            self.tooltip.wm_overrideredirect(True)
            self.tooltip.wm_geometry(f"+{x}+{y}")
            
            label = ttk.Label(self.tooltip, text=text, 
                             background="#ffffe0", relief="solid", borderwidth=1)
            label.pack()
            
        def leave(event):
            if hasattr(self, 'tooltip'):
                self.tooltip.destroy()
                
        widget.bind("<Enter>", enter)
        widget.bind("<Leave>", leave)
        
    def center_window(self):
        """窗口居中"""
        self.root.update_idletasks()
        width = self.root.winfo_width()
        height = self.root.winfo_height()
        screen_width = self.root.winfo_screenwidth()
        screen_height = self.root.winfo_screenheight()
        x = (screen_width - width) // 2
        y = (screen_height - height) // 2
        self.root.geometry(f'{width}x{height}+{x}+{y}')
        
    def show_view(self, view_type: str):
        """显示视图"""
        view_id = view_type
        if view_id not in self.view_manager.views:
            # 创建视图
            config = ViewConfig(
                id=view_id,
                type=ViewType(view_type),
                title=view_type,
                size=(400, 300)
            )
            self.view_manager.create_view(config)
            
        # 显示视图
        view = self.view_manager.get_view(view_id)
        if view:
            view.show()
            
    def apply_layout(self, layout_name: str):
        """应用布局"""
        self.view_manager.apply_layout(layout_name)
        
    def save_current_layout(self):
        """保存当前布局"""
        layout_name = f"layout_{int(time.time())}"
        self.view_manager.save_layout(layout_name)
        messagebox.showinfo("成功", f"布局已保存为: {layout_name}")
        
    def manage_layouts(self):
        """管理布局"""
        # 在实际应用中,这里会打开布局管理器
        pass
        
    def open_theme_editor(self):
        """打开主题编辑器"""
        from theme_engine import ThemeEditor
        
        editor_window = tk.Toplevel(self.root)
        editor_window.title("主题编辑器")
        editor_window.geometry("800x600")
        
        ThemeEditor(editor_window, self.theme_engine)
        
    def open_plugin_manager(self):
        """打开插件管理器"""
        from plugin_system import PluginBrowser
        
        plugin_window = tk.Toplevel(self.root)
        plugin_window.title("插件管理器")
        plugin_window.geometry("1000x700")
        
        PluginBrowser(plugin_window, self.plugin_manager)
        
    def open_data_pipeline(self):
        """打开数据流水线"""
        from data_pipeline import DataPipelineManagerUI
        
        pipeline_window = tk.Toplevel(self.root)
        pipeline_window.title("数据流水线管理器")
        pipeline_window.geometry("1200x800")
        
        DataPipelineManagerUI(pipeline_window, self.data_pipeline_manager)
        
    def open_system_monitor(self):
        """打开系统监控"""
        monitor_window = tk.Toplevel(self.root)
        monitor_window.title("系统监控")
        monitor_window.geometry("800x600")
        
        self.create_system_monitor_ui(monitor_window)
        
    def open_performance_analyzer(self):
        """打开性能分析器"""
        analyzer_window = tk.Toplevel(self.root)
        analyzer_window.title("性能分析器")
        analyzer_window.geometry("1000x700")
        
        self.create_performance_analyzer_ui(analyzer_window)
        
    def open_tools(self):
        """打开工具面板"""
        tools_window = tk.Toplevel(self.root)
        tools_window.title("工具面板")
        tools_window.geometry("600x400")
        
        self.create_tools_panel(tools_window)
        
    def create_system_monitor_ui(self, parent):
        """创建系统监控UI"""
        notebook = ttk.Notebook(parent)
        notebook.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 系统资源标签页
        resource_tab = ttk.Frame(notebook)
        self.create_resource_monitor(resource_tab)
        notebook.add(resource_tab, text="系统资源")
        
        # 数据流标签页
        dataflow_tab = ttk.Frame(notebook)
        self.create_dataflow_monitor(dataflow_tab)
        notebook.add(dataflow_tab, text="数据流")
        
        # 节点状态标签页
        node_tab = ttk.Frame(notebook)
        self.create_node_monitor(node_tab)
        notebook.add(node_tab, text="节点状态")
        
    def create_resource_monitor(self, parent):
        """创建资源监控"""
        # 创建图表
        fig = plt.Figure(figsize=(8, 6), dpi=100)
        canvas = FigureCanvasTkAgg(fig, parent)
        canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
        
        # 创建子图
        ax_cpu = fig.add_subplot(221)
        ax_memory = fig.add_subplot(222)
        ax_network = fig.add_subplot(223)
        ax_disk = fig.add_subplot(224)
        
        # 设置图表
        ax_cpu.set_title("CPU使用率")
        ax_cpu.set_ylabel("百分比%")
        ax_cpu.grid(True, alpha=0.3)
        
        ax_memory.set_title("内存使用率")
        ax_memory.set_ylabel("百分比%")
        ax_memory.grid(True, alpha=0.3)
        
        ax_network.set_title("网络流量")
        ax_network.set_ylabel("MB/s")
        ax_network.grid(True, alpha=0.3)
        
        ax_disk.set_title("磁盘IO")
        ax_disk.set_ylabel("MB/s")
        ax_disk.grid(True, alpha=0.3)
        
        fig.tight_layout()
        
    def create_dataflow_monitor(self, parent):
        """创建数据流监控"""
        # 创建Treeview显示数据流水线状态
        columns = ("流水线", "状态", "处理速率", "队列大小", "延迟")
        tree = ttk.Treeview(parent, columns=columns, show="headings", height=10)
        
        for col in columns:
            tree.heading(col, text=col)
            tree.column(col, width=100)
            
        scrollbar = ttk.Scrollbar(parent, orient=tk.VERTICAL, command=tree.yview)
        tree.configure(yscrollcommand=scrollbar.set)
        
        tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
    def create_node_monitor(self, parent):
        """创建节点监控"""
        # 创建节点状态显示
        frame = ttk.Frame(parent)
        frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        ttk.Label(frame, text="节点监控", font=("微软雅黑", 12, "bold")).pack(pady=(0, 10))
        
        # 节点状态表格
        columns = ("节点ID", "类型", "状态", "CPU", "内存", "最后活跃")
        tree = ttk.Treeview(frame, columns=columns, show="headings", height=8)
        
        for col in columns:
            tree.heading(col, text=col)
            tree.column(col, width=80)
            
        scrollbar = ttk.Scrollbar(frame, orient=tk.VERTICAL, command=tree.yview)
        tree.configure(yscrollcommand=scrollbar.set)
        
        tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
    def create_performance_analyzer_ui(self, parent):
        """创建性能分析器UI"""
        notebook = ttk.Notebook(parent)
        notebook.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 性能指标标签页
        metrics_tab = ttk.Frame(notebook)
        self.create_performance_metrics(metrics_tab)
        notebook.add(metrics_tab, text="性能指标")
        
        # 瓶颈分析标签页
        bottleneck_tab = ttk.Frame(notebook)
        self.create_bottleneck_analysis(bottleneck_tab)
        notebook.add(bottleneck_tab, text="瓶颈分析")
        
        # 优化建议标签页
        optimization_tab = ttk.Frame(notebook)
        self.create_optimization_suggestions(optimization_tab)
        notebook.add(optimization_tab, text="优化建议")
        
    def create_performance_metrics(self, parent):
        """创建性能指标显示"""
        frame = ttk.Frame(parent)
        frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 创建性能指标图表
        fig = plt.Figure(figsize=(10, 8), dpi=100)
        canvas = FigureCanvasTkAgg(fig, frame)
        canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
        
        # 创建多个子图
        axes = fig.subplots(2, 2)
        
        # 设置图表
        axes[0, 0].set_title("响应时间分布")
        axes[0, 0].set_ylabel("毫秒")
        axes[0, 0].grid(True, alpha=0.3)
        
        axes[0, 1].set_title("吞吐量趋势")
        axes[0, 1].set_ylabel("请求/秒")
        axes[0, 1].grid(True, alpha=0.3)
        
        axes[1, 0].set_title("资源使用率")
        axes[1, 0].set_ylabel("百分比%")
        axes[1, 0].grid(True, alpha=0.3)
        
        axes[1, 1].set_title("错误率")
        axes[1, 1].set_ylabel("百分比%")
        axes[1, 1].grid(True, alpha=0.3)
        
        fig.tight_layout()
        
    def create_bottleneck_analysis(self, parent):
        """创建瓶颈分析"""
        frame = ttk.Frame(parent)
        frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        ttk.Label(frame, text="瓶颈分析", font=("微软雅黑", 12, "bold")).pack(pady=(0, 10))
        
        # 瓶颈分析文本
        text = tk.Text(frame, height=20, width=60, font=("Consolas", 10))
        scrollbar = ttk.Scrollbar(frame, orient=tk.VERTICAL, command=text.yview)
        text.configure(yscrollcommand=scrollbar.set)
        
        text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        # 示例分析结果
        analysis = """瓶颈分析报告:
        
1. CPU瓶颈:
   - 进程: data_processor
   - CPU使用率: 85%
   - 建议: 优化算法或增加CPU核心
   
2. 内存瓶颈:
   - 进程: cache_manager
   - 内存使用: 3.2GB
   - 建议: 增加内存或优化缓存策略
   
3. 磁盘IO瓶颈:
   - 文件: data_log.db
   - IO等待: 45%
   - 建议: 使用SSD或优化写入策略
   
4. 网络瓶颈:
   - 接口: eth0
   - 带宽使用: 80%
   - 建议: 增加带宽或压缩数据
        """
        
        text.insert(1.0, analysis)
        
    def create_optimization_suggestions(self, parent):
        """创建优化建议"""
        frame = ttk.Frame(parent)
        frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        ttk.Label(frame, text="优化建议", font=("微软雅黑", 12, "bold")).pack(pady=(0, 10))
        
        # 优化建议列表
        suggestions = [
            ("CPU优化", "将计算密集型任务分布到多个核心", "高"),
            ("内存优化", "使用内存池减少内存分配开销", "中"),
            ("磁盘优化", "使用异步IO提高磁盘读写效率", "高"),
            ("网络优化", "启用数据压缩减少网络流量", "低"),
            ("缓存优化", "增加缓存命中率减少数据库访问", "中"),
            ("算法优化", "使用更高效的算法减少计算量", "高")
        ]
        
        for i, (title, description, priority) in enumerate(suggestions):
            suggestion_frame = ttk.Frame(frame)
            suggestion_frame.pack(fill=tk.X, pady=2)
            
            ttk.Label(suggestion_frame, text=title, width=15).pack(side=tk.LEFT)
            ttk.Label(suggestion_frame, text=description, width=40).pack(side=tk.LEFT, padx=5)
            
            # 优先级标签
            colors = {"高": "#E74C3C", "中": "#F39C12", "低": "#2ECC71"}
            label = ttk.Label(suggestion_frame, text=priority, 
                            foreground=colors.get(priority, "black"))
            label.pack(side=tk.RIGHT, padx=5)
            
    def create_tools_panel(self, parent):
        """创建工具面板"""
        notebook = ttk.Notebook(parent)
        notebook.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 数据工具标签页
        data_tools_tab = ttk.Frame(notebook)
        self.create_data_tools(data_tools_tab)
        notebook.add(data_tools_tab, text="数据工具")
        
        # 分析工具标签页
        analysis_tools_tab = ttk.Frame(notebook)
        self.create_analysis_tools(analysis_tools_tab)
        notebook.add(analysis_tools_tab, text="分析工具")
        
        # 系统工具标签页
        system_tools_tab = ttk.Frame(notebook)
        self.create_system_tools(system_tools_tab)
        notebook.add(system_tools_tab, text="系统工具")
        
    def create_data_tools(self, parent):
        """创建数据工具"""
        tools = [
            ("数据导入", self.import_data),
            ("数据导出", self.export_data),
            ("数据清洗", self.clean_data),
            ("数据转换", self.transform_data),
            ("数据合并", self.merge_data),
            ("数据抽样", self.sample_data)
        ]
        
        for i, (name, command) in enumerate(tools):
            btn = ttk.Button(parent, text=name, command=command, width=20)
            btn.grid(row=i//2, column=i%2, padx=10, pady=10, sticky=tk.NSEW)
            
        # 配置网格权重
        for i in range(2):
            parent.grid_columnconfigure(i, weight=1)
        for i in range((len(tools) + 1) // 2):
            parent.grid_rowconfigure(i, weight=1)
            
    def create_analysis_tools(self, parent):
        """创建分析工具"""
        tools = [
            ("统计分析", self.statistical_analysis),
            ("频谱分析", self.spectrum_analysis),
            ("趋势分析", self.trend_analysis),
            ("相关性分析", self.correlation_analysis),
            ("聚类分析", self.cluster_analysis),
            ("异常检测", self.anomaly_detection)
        ]
        
        for i, (name, command) in enumerate(tools):
            btn = ttk.Button(parent, text=name, command=command, width=20)
            btn.grid(row=i//2, column=i%2, padx=10, pady=10, sticky=tk.NSEW)
            
    def create_system_tools(self, parent):
        """创建系统工具"""
        tools = [
            ("系统诊断", self.system_diagnosis),
            ("性能测试", self.performance_test),
            ("压力测试", self.stress_test),
            ("日志分析", self.log_analysis),
            ("配置备份", self.config_backup),
            ("系统恢复", self.system_recovery)
        ]
        
        for i, (name, command) in enumerate(tools):
            btn = ttk.Button(parent, text=name, command=command, width=20)
            btn.grid(row=i//2, column=i%2, padx=10, pady=10, sticky=tk.NSEW)
            
    def new_project(self):
        """新建工程"""
        response = messagebox.askyesno("确认", "创建新工程将丢失当前未保存的更改,是否继续?")
        if response:
            # 重置系统状态
            self.reset_system()
            
    def open_project(self):
        """打开工程"""
        filename = filedialog.askopenfilename(
            title="选择工程文件",
            filetypes=[("EWCC工程文件", "*.ewcc"), ("所有文件", "*.*")]
        )
        
        if filename:
            try:
                with open(filename, 'r', encoding='utf-8') as f:
                    project_data = json.load(f)
                    
                # 加载工程配置
                self.load_project(project_data)
                
                messagebox.showinfo("成功", f"工程已加载: {filename}")
                
            except Exception as e:
                messagebox.showerror("错误", f"加载工程失败: {str(e)}")
                
    def save_project(self):
        """保存工程"""
        filename = filedialog.asksaveasfilename(
            title="保存工程文件",
            defaultextension=".ewcc",
            filetypes=[("EWCC工程文件", "*.ewcc"), ("所有文件", "*.*")]
        )
        
        if filename:
            try:
                project_data = self.save_project_data()
                
                with open(filename, 'w', encoding='utf-8') as f:
                    json.dump(project_data, f, indent=2, ensure_ascii=False)
                    
                messagebox.showinfo("成功", f"工程已保存: {filename}")
                
            except Exception as e:
                messagebox.showerror("错误", f"保存工程失败: {str(e)}")
                
    def load_project(self, project_data: Dict[str, Any]):
        """加载工程数据"""
        # 在实际应用中,这里会加载工程的所有配置和数据
        pass
        
    def save_project_data(self) -> Dict[str, Any]:
        """保存工程数据"""
        return {
            "name": "综合电子战指挥控制台工程",
            "version": "1.0.0",
            "timestamp": time.time(),
            "config": {
                "theme": self.theme_engine.current_theme.id if self.theme_engine.current_theme else "default",
                "layout": self.view_manager.current_layout,
                "views": [view.config.id for view in self.view_manager.get_all_views()]
            }
        }
        
    def import_data(self):
        """导入数据"""
        filename = filedialog.askopenfilename(
            title="选择数据文件",
            filetypes=[
                ("CSV文件", "*.csv"),
                ("JSON文件", "*.json"),
                ("Excel文件", "*.xlsx"),
                ("所有文件", "*.*")
            ]
        )
        
        if filename:
            try:
                # 在实际应用中,这里会解析和导入数据
                print(f"导入数据: {filename}")
                
            except Exception as e:
                messagebox.showerror("错误", f"导入数据失败: {str(e)}")
                
    def export_data(self):
        """导出数据"""
        filename = filedialog.asksaveasfilename(
            title="导出数据",
            defaultextension=".csv",
            filetypes=[
                ("CSV文件", "*.csv"),
                ("JSON文件", "*.json"),
                ("Excel文件", "*.xlsx"),
                ("所有文件", "*.*")
            ]
        )
        
        if filename:
            try:
                # 在实际应用中,这里会导出数据
                print(f"导出数据: {filename}")
                
            except Exception as e:
                messagebox.showerror("错误", f"导出数据失败: {str(e)}")
                
    def system_settings(self):
        """系统设置"""
        settings_window = tk.Toplevel(self.root)
        settings_window.title("系统设置")
        settings_window.geometry("600x400")
        
        notebook = ttk.Notebook(settings_window)
        notebook.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        
        # 常规设置
        general_tab = ttk.Frame(notebook)
        self.create_general_settings(general_tab)
        notebook.add(general_tab, text="常规")
        
        # 显示设置
        display_tab = ttk.Frame(notebook)
        self.create_display_settings(display_tab)
        notebook.add(display_tab, text="显示")
        
        # 数据设置
        data_tab = ttk.Frame(notebook)
        self.create_data_settings(data_tab)
        notebook.add(data_tab, text="数据")
        
        # 网络设置
        network_tab = ttk.Frame(notebook)
        self.create_network_settings(network_tab)
        notebook.add(network_tab, text="网络")
        
    def create_general_settings(self, parent):
        """创建常规设置"""
        frame = ttk.Frame(parent)
        frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        settings = [
            ("启动时加载上次工程", tk.BooleanVar(value=True)),
            ("自动保存间隔(分钟)", tk.IntVar(value=10)),
            ("最大历史记录数", tk.IntVar(value=100)),
            ("语言", tk.StringVar(value="中文")),
            ("时区", tk.StringVar(value="Asia/Shanghai"))
        ]
        
        for i, (label, var) in enumerate(settings):
            ttk.Label(frame, text=label).grid(row=i, column=0, sticky=tk.W, pady=5)
            
            if isinstance(var, tk.BooleanVar):
                ttk.Checkbutton(frame, variable=var).grid(row=i, column=1, sticky=tk.W, pady=5)
            elif isinstance(var, tk.IntVar):
                ttk.Entry(frame, textvariable=var, width=10).grid(row=i, column=1, sticky=tk.W, pady=5)
            elif isinstance(var, tk.StringVar):
                ttk.Entry(frame, textvariable=var, width=20).grid(row=i, column=1, sticky=tk.W, pady=5)
                
    def create_display_settings(self, parent):
        """创建显示设置"""
        frame = ttk.Frame(parent)
        frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        settings = [
            ("默认主题", tk.StringVar(value="dark")),
            ("字体大小", tk.IntVar(value=12)),
            ("动画效果", tk.BooleanVar(value=True)),
            ("硬件加速", tk.BooleanVar(value=True)),
            ("高DPI缩放", tk.BooleanVar(value=True))
        ]
        
        for i, (label, var) in enumerate(settings):
            ttk.Label(frame, text=label).grid(row=i, column=0, sticky=tk.W, pady=5)
            
            if isinstance(var, tk.BooleanVar):
                ttk.Checkbutton(frame, variable=var).grid(row=i, column=1, sticky=tk.W, pady=5)
            elif isinstance(var, tk.IntVar):
                ttk.Entry(frame, textvariable=var, width=10).grid(row=i, column=1, sticky=tk.W, pady=5)
            elif isinstance(var, tk.StringVar):
                ttk.Entry(frame, textvariable=var, width=20).grid(row=i, column=1, sticky=tk.W, pady=5)
                
    def create_data_settings(self, parent):
        """创建数据设置"""
        frame = ttk.Frame(parent)
        frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        settings = [
            ("数据缓存大小(MB)", tk.IntVar(value=100)),
            ("自动备份间隔(小时)", tk.IntVar(value=24)),
            ("数据压缩", tk.BooleanVar(value=True)),
            ("数据加密", tk.BooleanVar(value=False)),
            ("最大连接数", tk.IntVar(value=10))
        ]
        
        for i, (label, var) in enumerate(settings):
            ttk.Label(frame, text=label).grid(row=i, column=0, sticky=tk.W, pady=5)
            
            if isinstance(var, tk.BooleanVar):
                ttk.Checkbutton(frame, variable=var).grid(row=i, column=1, sticky=tk.W, pady=5)
            elif isinstance(var, tk.IntVar):
                ttk.Entry(frame, textvariable=var, width=10).grid(row=i, column=1, sticky=tk.W, pady=5)
                
    def create_network_settings(self, parent):
        """创建网络设置"""
        frame = ttk.Frame(parent)
        frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        settings = [
            ("服务器地址", tk.StringVar(value="localhost")),
            ("服务器端口", tk.IntVar(value=8888)),
            ("连接超时(秒)", tk.IntVar(value=30)),
            ("启用SSL", tk.BooleanVar(value=False)),
            ("代理服务器", tk.StringVar(value=""))
        ]
        
        for i, (label, var) in enumerate(settings):
            ttk.Label(frame, text=label).grid(row=i, column=0, sticky=tk.W, pady=5)
            
            if isinstance(var, tk.BooleanVar):
                ttk.Checkbutton(frame, variable=var).grid(row=i, column=1, sticky=tk.W, pady=5)
            elif isinstance(var, tk.IntVar):
                ttk.Entry(frame, textvariable=var, width=10).grid(row=i, column=1, sticky=tk.W, pady=5)
            elif isinstance(var, tk.StringVar):
                ttk.Entry(frame, textvariable=var, width=20).grid(row=i, column=1, sticky=tk.W, pady=5)
                
    def start_system(self):
        """启动系统"""
        if self.system_running:
            return
            
        self.system_running = True
        self.system_status_var.set("运行中")
        
        # 启动数据流水线
        self.start_data_pipelines()
        
        # 启动插件
        self.start_plugins()
        
        # 启动系统监控
        self.start_system_monitor()
        
        messagebox.showinfo("系统启动", "综合电子战指挥控制台已启动")
        
    def stop_system(self):
        """停止系统"""
        if not self.system_running:
            return
            
        response = messagebox.askyesno("确认", "确定要停止系统吗?")
        if response:
            self.system_running = False
            self.system_status_var.set("已停止")
            
            # 停止数据流水线
            self.stop_data_pipelines()
            
            # 停止插件
            self.stop_plugins()
            
            # 停止系统监控
            self.stop_system_monitor()
            
            messagebox.showinfo("系统停止", "系统已安全停止")
            
    def connect_to_cluster(self):
        """连接到集群"""
        if self.current_mode == "distributed":
            messagebox.showinfo("提示", "已连接到集群")
            return
            
        # 在实际应用中,这里会连接到分布式集群
        self.current_mode = "distributed"
        self.distributed_manager.start_master()
        
        messagebox.showinfo("集群连接", "已连接到分布式集群")
        
    def disconnect_from_cluster(self):
        """断开集群连接"""
        if self.current_mode == "standalone":
            messagebox.showinfo("提示", "未连接到集群")
            return
            
        self.current_mode = "standalone"
        # 在实际应用中,这里会断开集群连接
        
        messagebox.showinfo("集群断开", "已断开集群连接")
        
    def show_system_log(self):
        """显示系统日志"""
        log_window = tk.Toplevel(self.root)
        log_window.title("系统日志")
        log_window.geometry("800x500")
        
        text = tk.Text(log_window, font=("Consolas", 10))
        scrollbar = ttk.Scrollbar(log_window, orient=tk.VERTICAL, command=text.yview)
        text.configure(yscrollcommand=scrollbar.set)
        
        text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        # 示例日志
        logs = """[INFO] 2024-01-10 10:00:00 系统启动
[INFO] 2024-01-10 10:00:01 加载主题: dark
[INFO] 2024-01-10 10:00:02 创建视图: 战场态势
[INFO] 2024-01-10 10:00:03 创建视图: 频谱监测
[INFO] 2024-01-10 10:00:04 数据流水线启动
[INFO] 2024-01-10 10:00:05 插件管理器加载
[INFO] 2024-01-10 10:00:06 系统准备就绪
"""
        
        text.insert(1.0, logs)
        
    def show_about(self):
        """显示关于信息"""
        about_text = """综合电子战指挥控制台
版本: 3.0.0
        
功能特点:
- 多视图协同显示
- 实时数据处理
- 插件化架构
- 分布式支持
- 主题皮肤系统
        
技术栈:
- Python 3.8+
- tkinter/ttk GUI
- matplotlib 可视化
- 多线程/多进程
        
作者: Python GUI研究团队
日期: 2024年
许可证: MIT
        """
        
        messagebox.showinfo("关于", about_text)
        
    def show_user_manual(self):
        """显示用户手册"""
        # 在实际应用中,这里会打开用户手册
        messagebox.showinfo("用户手册", "用户手册功能开发中...")
        
    def show_shortcuts(self):
        """显示快捷键"""
        shortcuts = """系统快捷键:
Ctrl+N: 新建工程
Ctrl+O: 打开工程
Ctrl+S: 保存工程
Ctrl+Q: 退出系统
        
视图快捷键:
F1: 战场态势
F2: 频谱监测
F3: 资源管理
F4: 日志信息
F5: 告警显示
F6: 分析视图
        
操作快捷键:
Ctrl+R: 刷新数据
Ctrl+F: 搜索
Ctrl+P: 打印
Ctrl+H: 帮助
Esc: 取消/返回
        """
        
        messagebox.showinfo("快捷键", shortcuts)
        
    def check_for_updates(self):
        """检查更新"""
        # 在实际应用中,这里会检查软件更新
        messagebox.showinfo("检查更新", "当前已是最新版本")
        
    def show_technical_support(self):
        """显示技术支持"""
        support_text = """技术支持:
        
官方网站: https://ewcc.example.com
技术支持邮箱: support@ewcc.example.com
文档中心: https://docs.ewcc.example.com
社区论坛: https://forum.ewcc.example.com
        
问题反馈:
请通过邮件或论坛反馈问题,我们会尽快处理。
        """
        
        messagebox.showinfo("技术支持", support_text)
        
    def start_data_pipelines(self):
        """启动数据流水线"""
        # 启动遥测数据流水线
        self.data_pipeline_manager.create_telemetry_pipeline(
            "telemetry_pipeline",
            self.get_view("spectrum").canvas if hasattr(self, 'get_view') else None
        )
        self.data_pipeline_manager.start_pipeline("telemetry_pipeline")
        
        # 启动频谱数据流水线
        self.data_pipeline_manager.create_spectrum_pipeline(
            "spectrum_pipeline",
            self.get_view("spectrum").canvas if hasattr(self, 'get_view') else None
        )
        self.data_pipeline_manager.start_pipeline("spectrum_pipeline")
        
    def stop_data_pipelines(self):
        """停止数据流水线"""
        self.data_pipeline_manager.stop_pipeline("telemetry_pipeline")
        self.data_pipeline_manager.stop_pipeline("spectrum_pipeline")
        
    def start_plugins(self):
        """启动插件"""
        # 发现并加载插件
        self.plugin_manager.discover_plugins()
        
        # 加载所有插件
        for plugin_info in self.plugin_manager.discover_plugins():
            if self.plugin_manager.load_plugin(plugin_info):
                self.plugin_manager.enable_plugin(plugin_info.id)
                
    def stop_plugins(self):
        """停止插件"""
        for plugin in self.plugin_manager.get_all_plugins():
            self.plugin_manager.disable_plugin(plugin.info.id)
            
    def start_system_monitor(self):
        """启动系统监控"""
        # 启动系统状态更新线程
        self.monitor_thread = threading.Thread(
            target=self._update_system_status,
            daemon=True
        )
        self.monitor_thread.start()
        
    def stop_system_monitor(self):
        """停止系统监控"""
        pass
        
    def _update_system_status(self):
        """更新系统状态"""
        import psutil
        
        while self.system_running:
            try:
                # 获取系统状态
                cpu_percent = psutil.cpu_percent(interval=1)
                memory_percent = psutil.virtual_memory().percent
                
                # 更新状态变量
                self.root.after(0, self.status_vars['cpu'].set, f"{cpu_percent:.1f}%")
                self.root.after(0, self.status_vars['memory'].set, f"{memory_percent:.1f}%")
                
                # 更新数据流状态
                if hasattr(self.data_pipeline_manager, 'get_pipeline_stats'):
                    stats = self.data_pipeline_manager.get_pipeline_stats("telemetry_pipeline")
                    if stats:
                        data_rate = stats.get('throughput', 0)
                        self.root.after(0, self.status_vars['data_rate'].set, 
                                       f"{data_rate:.1f}条/秒")
                        
            except Exception as e:
                print(f"更新系统状态错误: {e}")
                
            time.sleep(2)  # 每2秒更新一次
            
    def reset_system(self):
        """重置系统"""
        # 停止系统
        self.stop_system()
        
        # 清除数据
        self.data_cache.clear()
        
        # 重置视图
        for view in self.view_manager.get_all_views():
            view.destroy()
        self.view_manager.views.clear()
        
        # 重新创建默认视图
        self.create_default_views()
        
        # 更新状态
        self.system_status_var.set("就绪")
        
    def quit_system(self):
        """退出系统"""
        response = messagebox.askyesno("确认", "确定要退出系统吗?")
        if response:
            # 停止系统
            self.stop_system()
            
            # 保存配置
            self.save_project()
            
            # 退出应用
            self.root.quit()
            
    # 以下是一些示例工具方法
    def clean_data(self):
        """数据清洗"""
        messagebox.showinfo("数据清洗", "数据清洗功能开发中...")
        
    def transform_data(self):
        """数据转换"""
        messagebox.showinfo("数据转换", "数据转换功能开发中...")
        
    def merge_data(self):
        """数据合并"""
        messagebox.showinfo("数据合并", "数据合并功能开发中...")
        
    def sample_data(self):
        """数据抽样"""
        messagebox.showinfo("数据抽样", "数据抽样功能开发中...")
        
    def statistical_analysis(self):
        """统计分析"""
        messagebox.showinfo("统计分析", "统计分析功能开发中...")
        
    def spectrum_analysis(self):
        """频谱分析"""
        messagebox.showinfo("频谱分析", "频谱分析功能开发中...")
        
    def trend_analysis(self):
        """趋势分析"""
        messagebox.showinfo("趋势分析", "趋势分析功能开发中...")
        
    def correlation_analysis(self):
        """相关性分析"""
        messagebox.showinfo("相关性分析", "相关性分析功能开发中...")
        
    def cluster_analysis(self):
        """聚类分析"""
        messagebox.showinfo("聚类分析", "聚类分析功能开发中...")
        
    def anomaly_detection(self):
        """异常检测"""
        messagebox.showinfo("异常检测", "异常检测功能开发中...")
        
    def system_diagnosis(self):
        """系统诊断"""
        messagebox.showinfo("系统诊断", "系统诊断功能开发中...")
        
    def performance_test(self):
        """性能测试"""
        messagebox.showinfo("性能测试", "性能测试功能开发中...")
        
    def stress_test(self):
        """压力测试"""
        messagebox.showinfo("压力测试", "压力测试功能开发中...")
        
    def log_analysis(self):
        """日志分析"""
        messagebox.showinfo("日志分析", "日志分析功能开发中...")
        
    def config_backup(self):
        """配置备份"""
        messagebox.showinfo("配置备份", "配置备份功能开发中...")
        
    def system_recovery(self):
        """系统恢复"""
        messagebox.showinfo("系统恢复", "系统恢复功能开发中...")
        
    def get_view(self, view_id: str):
        """获取视图"""
        return self.view_manager.get_view(view_id)
        
    def run(self):
        """运行系统"""
        self.root.mainloop()

# 主程序入口
if __name__ == "__main__":
    app = EWCCIntegratedSystem()
    app.run()

9. 性能优化与部署

9.1 性能优化策略

python 复制代码
"""
performance_optimization.py

性能优化与部署策略
"""
import time
import tracemalloc
import cProfile
import pstats
from typing import Dict, List, Any, Optional, Callable
from functools import wraps
import threading
import queue
import numpy as np
from dataclasses import dataclass, field
from enum import Enum
import gc

class OptimizationLevel(Enum):
    """优化级别"""
    NONE = "none"           # 无优化
    BASIC = "basic"         # 基础优化
    ADVANCED = "advanced"   # 高级优化
    AGGRESSIVE = "aggressive"  # 激进优化

@dataclass
class PerformanceMetrics:
    """性能指标"""
    execution_time: float = 0.0
    memory_usage: float = 0.0
    cpu_usage: float = 0.0
    call_count: int = 0
    cache_hits: int = 0
    cache_misses: int = 0
    queue_size: int = 0
    
class PerformanceOptimizer:
    """性能优化器"""
    
    def __init__(self, optimization_level: OptimizationLevel = OptimizationLevel.BASIC):
        self.optimization_level = optimization_level
        self.metrics: Dict[str, PerformanceMetrics] = {}
        self.caches: Dict[str, Any] = {}
        self.profiler = cProfile.Profile()
        self.enabled = False
        
    def start(self):
        """启动优化器"""
        self.enabled = True
        tracemalloc.start()
        
    def stop(self):
        """停止优化器"""
        self.enabled = False
        tracemalloc.stop()
        
    def profile_function(self, func: Callable):
        """性能分析装饰器"""
        @wraps(func)
        def wrapper(*args, **kwargs):
            if not self.enabled:
                return func(*args, **kwargs)
                
            # 开始性能分析
            start_time = time.perf_counter()
            start_memory = tracemalloc.get_traced_memory()[0]
            
            # 执行函数
            result = func(*args, **kwargs)
            
            # 计算性能指标
            end_time = time.perf_counter()
            end_memory = tracemalloc.get_traced_memory()[0]
            
            # 记录指标
            func_name = func.__name__
            if func_name not in self.metrics:
                self.metrics[func_name] = PerformanceMetrics()
                
            metrics = self.metrics[func_name]
            metrics.execution_time += end_time - start_time
            metrics.memory_usage = max(metrics.memory_usage, end_memory - start_memory)
            metrics.call_count += 1
            
            return result
            
        return wrapper
        
    def cache_result(self, func: Callable):
        """结果缓存装饰器"""
        @wraps(func)
        def wrapper(*args, **kwargs):
            if self.optimization_level == OptimizationLevel.NONE:
                return func(*args, **kwargs)
                
            # 创建缓存键
            cache_key = f"{func.__name__}:{str(args)}:{str(kwargs)}"
            
            # 检查缓存
            if cache_key in self.caches:
                self.metrics.setdefault(func.__name__, PerformanceMetrics()).cache_hits += 1
                return self.caches[cache_key]
                
            # 计算并缓存结果
            result = func(*args, **kwargs)
            self.caches[cache_key] = result
            self.metrics.setdefault(func.__name__, PerformanceMetrics()).cache_misses += 1
            
            # 清理旧缓存(如果缓存太大)
            if len(self.caches) > 1000:
                self._cleanup_cache()
                
            return result
            
        return wrapper
        
    def _cleanup_cache(self):
        """清理缓存"""
        # 保留最近使用的缓存项
        if len(self.caches) > 1000:
            # 简单的LRU策略:删除一半旧缓存
            keys_to_remove = list(self.caches.keys())[:500]
            for key in keys_to_remove:
                del self.caches[key]
                
    def lazy_loading(self, func: Callable):
        """懒加载装饰器"""
        cached_result = None
        initialized = False
        
        @wraps(func)
        def wrapper(*args, **kwargs):
            nonlocal cached_result, initialized
            
            if not initialized:
                cached_result = func(*args, **kwargs)
                initialized = True
                
            return cached_result
            
        return wrapper
        
    def batch_processing(self, batch_size: int = 100):
        """批处理装饰器"""
        def decorator(func: Callable):
            buffer = []
            
            @wraps(func)
            def wrapper(item):
                buffer.append(item)
                
                if len(buffer) >= batch_size:
                    result = func(buffer)
                    buffer.clear()
                    return result
                    
                return None
                
            return wrapper
        return decorator
        
    def get_performance_report(self) -> Dict[str, Any]:
        """获取性能报告"""
        report = {
            "total_functions": len(self.metrics),
            "total_calls": sum(m.call_count for m in self.metrics.values()),
            "total_time": sum(m.execution_time for m in self.metrics.values()),
            "cache_efficiency": 0,
            "function_metrics": {}
        }
        
        # 计算缓存效率
        total_hits = sum(m.cache_hits for m in self.metrics.values())
        total_misses = sum(m.cache_misses for m in self.metrics.values())
        if total_hits + total_misses > 0:
            report["cache_efficiency"] = total_hits / (total_hits + total_misses)
            
        # 添加函数级别的指标
        for func_name, metrics in self.metrics.items():
            report["function_metrics"][func_name] = {
                "call_count": metrics.call_count,
                "total_time": metrics.execution_time,
                "avg_time": metrics.execution_time / metrics.call_count if metrics.call_count > 0 else 0,
                "memory_usage": metrics.memory_usage,
                "cache_hits": metrics.cache_hits,
                "cache_misses": metrics.cache_misses
            }
            
        return report
        
    def optimize_memory(self):
        """优化内存使用"""
        if self.optimization_level == OptimizationLevel.NONE:
            return
            
        # 强制垃圾回收
        gc.collect()
        
        if self.optimization_level in [OptimizationLevel.ADVANCED, OptimizationLevel.AGGRESSIVE]:
            # 禁用循环引用垃圾回收(仅在高级优化时使用)
            gc.disable()
            
    def restore_memory_settings(self):
        """恢复内存设置"""
        if self.optimization_level in [OptimizationLevel.ADVANCED, OptimizationLevel.AGGRESSIVE]:
            gc.enable()
            
    def run_profiling(self, func: Callable, *args, **kwargs):
        """运行性能分析"""
        self.profiler.enable()
        result = func(*args, **kwargs)
        self.profiler.disable()
        
        # 生成分析报告
        stats = pstats.Stats(self.profiler)
        stats.sort_stats('cumulative')
        
        return result, stats

class ThreadPoolOptimizer:
    """线程池优化器"""
    
    def __init__(self, max_workers: int = None, optimization_level: OptimizationLevel = OptimizationLevel.BASIC):
        import concurrent.futures
        
        self.max_workers = max_workers or (threading.cpu_count() * 2)
        self.optimization_level = optimization_level
        self.executor = concurrent.futures.ThreadPoolExecutor(max_workers=self.max_workers)
        self.task_queue = queue.Queue()
        self.running = False
        
    def start(self):
        """启动线程池"""
        self.running = True
        # 启动任务处理线程
        for _ in range(self.max_workers):
            threading.Thread(target=self._worker, daemon=True).start()
            
    def stop(self):
        """停止线程池"""
        self.running = False
        self.executor.shutdown(wait=True)
        
    def submit_task(self, func, *args, **kwargs):
        """提交任务"""
        future = self.executor.submit(func, *args, **kwargs)
        return future
        
    def map_tasks(self, func, iterable, chunk_size=1):
        """映射任务"""
        return self.executor.map(func, iterable, chunksize=chunk_size)
        
    def _worker(self):
        """工作线程"""
        while self.running:
            try:
                task = self.task_queue.get(timeout=0.1)
                if task is None:
                    break
                    
                func, args, kwargs = task
                try:
                    func(*args, **kwargs)
                except Exception as e:
                    print(f"任务执行错误: {e}")
                finally:
                    self.task_queue.task_done()
                    
            except queue.Empty:
                continue
                
    def get_queue_size(self):
        """获取队列大小"""
        return self.task_queue.qsize()
        
    def get_active_workers(self):
        """获取活动工作线程数"""
        return self.executor._work_queue.qsize()  # 注意:这是内部属性,实际中需要更安全的方法

class MemoryOptimizer:
    """内存优化器"""
    
    def __init__(self, optimization_level: OptimizationLevel = OptimizationLevel.BASIC):
        self.optimization_level = optimization_level
        self.memory_pool = {}
        self.object_cache = {}
        
    def optimize_data_structure(self, data):
        """优化数据结构"""
        if self.optimization_level == OptimizationLevel.NONE:
            return data
            
        if isinstance(data, np.ndarray):
            return self._optimize_ndarray(data)
        elif isinstance(data, list):
            return self._optimize_list(data)
        elif isinstance(data, dict):
            return self._optimize_dict(data)
        else:
            return data
            
    def _optimize_ndarray(self, array: np.ndarray) -> np.ndarray:
        """优化NumPy数组"""
        if self.optimization_level in [OptimizationLevel.ADVANCED, OptimizationLevel.AGGRESSIVE]:
            # 使用更节省内存的数据类型
            if array.dtype == np.float64:
                return array.astype(np.float32)
            elif array.dtype == np.int64:
                return array.astype(np.int32)
                
        return array
        
    def _optimize_list(self, lst: list) -> list:
        """优化列表"""
        if self.optimization_level == OptimizationLevel.AGGRESSIVE:
            # 转换为元组(如果可能)
            if len(lst) < 1000:  # 小列表
                return tuple(lst)
                
        return lst
        
    def _optimize_dict(self, dct: dict) -> dict:
        """优化字典"""
        if self.optimization_level == OptimizationLevel.AGGRESSIVE:
            # 使用更紧凑的字典实现
            from collections import OrderedDict
            return OrderedDict(dct)
            
        return dct
        
    def create_memory_pool(self, pool_id: str, size: int, dtype=np.float32):
        """创建内存池"""
        if pool_id not in self.memory_pool:
            self.memory_pool[pool_id] = np.zeros(size, dtype=dtype)
            
    def get_from_pool(self, pool_id: str, size: int) -> np.ndarray:
        """从内存池获取内存"""
        if pool_id in self.memory_pool:
            pool = self.memory_pool[pool_id]
            if len(pool) >= size:
                return pool[:size]
                
        # 如果内存池不足,创建新的
        self.create_memory_pool(pool_id, size)
        return self.memory_pool[pool_id][:size]
        
    def cache_object(self, key: str, obj: Any, max_size: int = 1000):
        """缓存对象"""
        if len(self.object_cache) >= max_size:
            # 使用LRU策略清理缓存
            oldest_key = next(iter(self.object_cache))
            del self.object_cache[oldest_key]
            
        self.object_cache[key] = obj
        
    def get_cached_object(self, key: str) -> Optional[Any]:
        """获取缓存对象"""
        return self.object_cache.get(key)
        
    def clear_cache(self):
        """清空缓存"""
        self.object_cache.clear()
        self.memory_pool.clear()

class DiskCacheOptimizer:
    """磁盘缓存优化器"""
    
    def __init__(self, cache_dir: str = "./cache", max_size_mb: int = 1000):
        self.cache_dir = cache_dir
        self.max_size_mb = max_size_mb
        os.makedirs(cache_dir, exist_ok=True)
        
    def cache_to_disk(self, key: str, data: Any, compress: bool = True):
        """缓存到磁盘"""
        import pickle
        import gzip
        
        # 创建缓存文件名
        cache_file = os.path.join(self.cache_dir, f"{hash(key)}.cache")
        
        # 序列化数据
        if compress:
            with gzip.open(cache_file, 'wb') as f:
                pickle.dump(data, f)
        else:
            with open(cache_file, 'wb') as f:
                pickle.dump(data, f)
                
        # 检查缓存大小
        self._manage_cache_size()
        
    def load_from_disk(self, key: str) -> Optional[Any]:
        """从磁盘加载"""
        import pickle
        import gzip
        
        cache_file = os.path.join(self.cache_dir, f"{hash(key)}.cache")
        
        if not os.path.exists(cache_file):
            return None
            
        try:
            # 尝试gzip解压
            with gzip.open(cache_file, 'rb') as f:
                return pickle.load(f)
        except:
            # 如果不是gzip压缩,尝试普通加载
            try:
                with open(cache_file, 'rb') as f:
                    return pickle.load(f)
            except:
                return None
                
    def _manage_cache_size(self):
        """管理缓存大小"""
        import shutil
        
        # 计算当前缓存大小
        total_size = 0
        cache_files = []
        
        for filename in os.listdir(self.cache_dir):
            if filename.endswith('.cache'):
                filepath = os.path.join(self.cache_dir, filename)
                size = os.path.getsize(filepath)
                total_size += size
                cache_files.append((filepath, os.path.getmtime(filepath)))
                
        # 转换为MB
        total_size_mb = total_size / (1024 * 1024)
        
        # 如果超过最大大小,删除最旧的文件
        if total_size_mb > self.max_size_mb:
            # 按修改时间排序
            cache_files.sort(key=lambda x: x[1])
            
            for filepath, _ in cache_files:
                if total_size_mb <= self.max_size_mb * 0.8:  # 保留80%的空间
                    break
                    
                # 删除文件
                os.remove(filepath)
                total_size_mb -= os.path.getsize(filepath) / (1024 * 1024)
                
    def clear_disk_cache(self):
        """清空磁盘缓存"""
        import shutil
        
        if os.path.exists(self.cache_dir):
            shutil.rmtree(self.cache_dir)
            os.makedirs(self.cache_dir, exist_ok=True)

class DeploymentOptimizer:
    """部署优化器"""
    
    def __init__(self, app_name: str, version: str = "1.0.0"):
        self.app_name = app_name
        self.version = version
        self.build_config = {}
        
    def create_installer(self, output_dir: str = "./dist"):
        """创建安装程序"""
        import subprocess
        import sys
        
        # 确保输出目录存在
        os.makedirs(output_dir, exist_ok=True)
        
        # 使用PyInstaller创建可执行文件
        pyinstaller_cmd = [
            sys.executable, "-m", "PyInstaller",
            "--name", f"{self.app_name}_{self.version}",
            "--onefile",
            "--windowed",
            "--add-data", "plugins:plugins",
            "--add-data", "themes:themes",
            "--add-data", "config:config",
            "--icon", "ewcc_icon.ico",
            "ewcc_integrated_system.py"
        ]
        
        try:
            subprocess.run(pyinstaller_cmd, check=True)
            print(f"安装程序创建成功: {output_dir}")
        except subprocess.CalledProcessError as e:
            print(f"创建安装程序失败: {e}")
            
    def create_docker_image(self, dockerfile_path: str = "./Dockerfile"):
        """创建Docker镜像"""
        import subprocess
        
        # 构建Docker镜像
        docker_cmd = [
            "docker", "build",
            "-t", f"{self.app_name.lower()}:{self.version}",
            "-f", dockerfile_path,
            "."
        ]
        
        try:
            subprocess.run(docker_cmd, check=True)
            print(f"Docker镜像创建成功: {self.app_name}:{self.version}")
        except subprocess.CalledProcessError as e:
            print(f"创建Docker镜像失败: {e}")
        except FileNotFoundError:
            print("Docker未安装或未在PATH中")
            
    def generate_requirements(self, output_file: str = "requirements.txt"):
        """生成requirements.txt文件"""
        import pkg_resources
        
        # 获取已安装的包
        installed_packages = pkg_resources.working_set
        
        with open(output_file, 'w', encoding='utf-8') as f:
            for package in installed_packages:
                f.write(f"{package.key}=={package.version}\n")
                
        print(f"requirements.txt已生成: {output_file}")
        
    def optimize_for_production(self):
        """生产环境优化"""
        # 禁用调试功能
        import sys
        if hasattr(sys, 'gettrace') and sys.gettrace() is not None:
            print("警告: 在调试模式下运行,性能可能受影响")
            
        # 设置生产环境变量
        os.environ['PYTHONOPTIMIZE'] = '1'
        os.environ['PYTHONDONTWRITEBYTECODE'] = '1'
        
        # 优化Python设置
        import sys
        sys.setrecursionlimit(10000)
        
    def create_config_file(self, config: Dict[str, Any], output_file: str = "config.yaml"):
        """创建配置文件"""
        import yaml
        
        with open(output_file, 'w', encoding='utf-8') as f:
            yaml.dump(config, f, default_flow_style=False)
            
        print(f"配置文件已生成: {output_file}")
        
    def performance_test(self, test_cases: List[Callable]):
        """性能测试"""
        results = {}
        
        for test_case in test_cases:
            test_name = test_case.__name__
            
            # 测量执行时间
            start_time = time.perf_counter()
            test_case()
            execution_time = time.perf_counter() - start_time
            
            # 测量内存使用
            import tracemalloc
            tracemalloc.start()
            test_case()
            current, peak = tracemalloc.get_traced_memory()
            tracemalloc.stop()
            
            results[test_name] = {
                'execution_time': execution_time,
                'memory_peak': peak / 1024 / 1024,  # MB
                'memory_current': current / 1024 / 1024  # MB
            }
            
        return results

# 使用示例
if __name__ == "__main__":
    # 创建性能优化器
    optimizer = PerformanceOptimizer(OptimizationLevel.ADVANCED)
    optimizer.start()
    
    # 示例函数
    @optimizer.profile_function
    @optimizer.cache_result
    def expensive_computation(n: int) -> int:
        time.sleep(0.1)  # 模拟耗时计算
        return n * n
        
    # 测试缓存
    print(expensive_computation(5))  # 计算并缓存
    print(expensive_computation(5))  # 从缓存获取
    
    # 获取性能报告
    report = optimizer.get_performance_report()
    print(f"缓存效率: {report['cache_efficiency']:.2%}")
    
    optimizer.stop()

10. 总结与展望

10.1 本博客的技术成果总结

通过本博客,我们构建了一个完整的综合电子战指挥控制台系统,展示了tkinter/ttk在构建复杂专业系统方面的强大能力:

10.2 关键技术突破

  1. 复杂布局管理

    • 实现了可拖拽、可停靠、可最大化的多视图系统

    • 支持多种布局模式和预设配置

    • 视图间协同和数据同步机制

  2. 高性能数据处理

    • 构建了完整的数据流水线框架

    • 支持多级数据处理和可视化

    • 实现了高效的数据缓存和复用机制

  3. 可扩展架构

    • 完整的插件化系统设计

    • 动态加载和热插拔支持

    • 统一的插件接口规范

  4. 现代化UI系统

    • 主题引擎支持动态换肤

    • 完整的控件样式系统

    • 响应式布局和自适应设计

  5. 分布式系统支持

    • 网络通信框架

    • 节点发现和管理

    • 负载均衡和故障转移

10.3 实际应用价值

  1. 军事指挥系统

    • 电子战态势监控

    • 频谱管理和分析

    • 资源调度和优化

  2. 工业控制系统

    • 实时数据监控

    • 分布式控制

    • 故障诊断和预警

  3. 科研仿真平台

    • 算法验证和测试

    • 数据分析和可视化

    • 多学科协同研究

  4. 教育培训系统

    • 模拟训练环境

    • 交互式教学

    • 技能评估和考核

10.4 未来发展方向

10.5 结语

本博客通过构建综合电子战指挥控制台系统,全面展示了tkinter/ttk在构建复杂专业系统方面的能力。我们不仅实现了复杂的业务逻辑和算法,还构建了美观、易用、高性能的用户界面。

核心价值

  • 证明了Python标准库能够胜任专业级复杂系统的开发

  • 展示了现代化GUI设计的最佳实践

  • 提供了完整的系统架构和设计模式参考

  • 开源了所有代码,便于学习和二次开发

技术启示

  1. 不要低估标准库:tkinter/ttk经过合理设计和优化,完全可以构建专业级应用

  2. 架构决定成败:良好的系统架构是复杂项目成功的关键

  3. 性能是设计出来的:从架构层面考虑性能,而不是事后优化

  4. 可扩展性是必须的:为未来的功能扩展预留接口

相关推荐
前端不太难2 小时前
State 驱动鸿蒙游戏架构详解
游戏·架构·harmonyos
杜子不疼.2 小时前
Python + AI 实战:用 LangChain 搭建企业级 RAG 知识库
人工智能·python·langchain
无敌昊哥战神2 小时前
【算法与数据结构】深入浅出回溯算法:理论基础与核心模板(C/C++与Python三语解析)
c语言·数据结构·c++·笔记·python·算法
甄心爱学习2 小时前
【项目实训(个人3)】
vue.js·人工智能·python·个人开发
进击的小头2 小时前
第8篇:嵌入式芯片内存架构详解:SRAM_Flash_Cache与外部存储的层级设计
单片机·嵌入式硬件·架构
平安的平安2 小时前
MCP 协议实战:用 Python 开发你的第一个 AI 工具服务
网络·人工智能·python
许彰午2 小时前
# 政务表单动态建表?运行时DDL引擎,前端拖完字段后端直接建
java·前端·后端·架构·政务
宸津-代码粉碎机2 小时前
Spring Boot 4.0 进阶实战+源码解析系列(持续更新)—— 从落地到源码,搞定面试与工作
java·人工智能·spring boot·后端·python·面试
Z.风止2 小时前
Large Model-learning(4)
人工智能·pytorch·笔记·python·深度学习·机器学习