flower_linux 3 mēneši atpakaļ
vecāks
revīzija
c0bb0fde0f

+ 14 - 4
mainwindow.cpp

@@ -327,13 +327,23 @@ function:  链接信号槽
 */
 void MainWindow::connectSignals() {
     // 连接设备树选择信号到自动跳转槽函数
+    // 现在有两个独立的设备树实例(串口页面和网络页面),都需要连接
     ViewInstanceManager* viewMgr = ViewInstanceManager::instance();
     if (viewMgr) {
-        DeviceTreeWidget* deviceTree = viewMgr->getDeviceTreeWidget();
-        if (deviceTree) {
-            connect(deviceTree, &DeviceTreeWidget::deviceSelected,
+        // 连接串口页面的设备树
+        DeviceTreeWidget* serialDeviceTree = viewMgr->getSerialDeviceTreeWidget();
+        if (serialDeviceTree) {
+            connect(serialDeviceTree, &DeviceTreeWidget::deviceSelected,
                     this, &MainWindow::onDeviceSelectedForAutoSwitch);
-            LOG_INFO() << "MainWindow: 设备树自动跳转信号已连接";
+            LOG_INFO() << "MainWindow: 串口页面设备树自动跳转信号已连接";
+        }
+        
+        // 连接网络页面的设备树
+        DeviceTreeWidget* networkDeviceTree = viewMgr->getNetworkDeviceTreeWidget();
+        if (networkDeviceTree) {
+            connect(networkDeviceTree, &DeviceTreeWidget::deviceSelected,
+                    this, &MainWindow::onDeviceSelectedForAutoSwitch);
+            LOG_INFO() << "MainWindow: 网络页面设备树自动跳转信号已连接";
         }
     }
 }

+ 5 - 3
src/api/SoftBusAPI.cpp

@@ -829,13 +829,15 @@ void SoftBusAPI::setDaemonClient(DaemonClient* daemonClient) {
     
     m_daemonClient = daemonClient;
     
-    // 连接新的信号
+    // 连接新的信号(使用队列连接确保线程安全)
     if (m_daemonClient) {
         // 连接硬件数据接收信号
         connect(m_daemonClient, &DaemonClient::serialDataReceived,
-                this, &SoftBusAPI::onSerialDataReceived);
+                this, &SoftBusAPI::onSerialDataReceived,
+                Qt::QueuedConnection);
         connect(m_daemonClient, &DaemonClient::canDataReceived,
-                this, &SoftBusAPI::onCanDataReceived);
+                this, &SoftBusAPI::onCanDataReceived,
+                Qt::QueuedConnection);
         
         // 注意:不再自动启用守护进程模式,由用户设置决定
     }

+ 3 - 2
src/connect_signal/signal_connector.cpp

@@ -301,11 +301,12 @@ void SignalConnector::connectAPIToSerialData(SerialDataWidget* pSerialData)
         return;
     }
 
-    // 获取 SoftBusAPI 实例并连接信号
+    // 获取 SoftBusAPI 实例并连接信号(使用队列连接确保线程安全)
     SoftBusAPI* pApi = SoftBusAPI::instance();
     if (pApi) {
         connect(pApi, &SoftBusAPI::serialDataReceived,
-                pSerialData, &SerialDataWidget::onSerialDataReceived);
+                pSerialData, &SerialDataWidget::onSerialDataReceived,
+                Qt::QueuedConnection);
         m_mapConnectionStatus[strConnectionKey] = true;
         LOG_INFO() << "SignalConnector: SoftBusAPI -> 串口数据 连接已建立";
     } else {

+ 102 - 95
src/connect_signal/view_instance_manager.cpp

@@ -131,9 +131,15 @@ ViewCore* ViewInstanceManager::getViewCore() const
     return qobject_cast<ViewCore*>(pWidget);
 }
 
-DeviceTreeWidget* ViewInstanceManager::getDeviceTreeWidget() const
+DeviceTreeWidget* ViewInstanceManager::getSerialDeviceTreeWidget() const
 {
-    QWidget* pWidget = getView(EViewType::ViewDeviceTree);
+    QWidget* pWidget = getView(EViewType::ViewSerialDeviceTree);
+    return qobject_cast<DeviceTreeWidget*>(pWidget);
+}
+
+DeviceTreeWidget* ViewInstanceManager::getNetworkDeviceTreeWidget() const
+{
+    QWidget* pWidget = getView(EViewType::ViewNetworkDeviceTree);
     return qobject_cast<DeviceTreeWidget*>(pWidget);
 }
 
@@ -155,9 +161,15 @@ NetworkDataWidget* ViewInstanceManager::getNetworkDataWidget() const
     return qobject_cast<NetworkDataWidget*>(pWidget);
 }
 
-ModbusConfigWidget* ViewInstanceManager::getModbusConfigWidget() const
+ModbusConfigWidget* ViewInstanceManager::getSerialModbusConfigWidget() const
+{
+    QWidget* pWidget = getView(EViewType::ViewSerialModbusConfig);
+    return qobject_cast<ModbusConfigWidget*>(pWidget);
+}
+
+ModbusConfigWidget* ViewInstanceManager::getNetworkModbusConfigWidget() const
 {
-    QWidget* pWidget = getView(EViewType::ViewModbusConfig);
+    QWidget* pWidget = getView(EViewType::ViewNetworkModbusConfig);
     return qobject_cast<ModbusConfigWidget*>(pWidget);
 }
 
@@ -198,66 +210,6 @@ void ViewInstanceManager::createSharedComponents(QWidget* pParent, DeviceBusCore
         return;
     }
 
-    // 获取 SoftBusAPI 实例并确保已初始化
-    SoftBusAPI* pApi = SoftBusAPI::instance();
-    if (!pApi) {
-        LOG_ERROR() << "ViewInstanceManager: SoftBusAPI 实例为空,无法创建共享组件";
-        return;
-    }
-    
-    // 确保 API 已初始化
-    if (!pApi->isInitialized()) {
-        LOG_INFO() << "ViewInstanceManager: SoftBusAPI 未初始化,正在初始化...";
-        if (!pApi->initialize()) {
-            LOG_ERROR() << "ViewInstanceManager: SoftBusAPI 初始化失败";
-            return;
-        }
-    }
-
-    // 创建设备树组件(共享组件)
-    DeviceTreeWidget* pDeviceTree = new DeviceTreeWidget(pParent);
-    LOG_DEBUG() << "ViewInstanceManager: DeviceTreeWidget 对象已创建";
-    
-    // 检查 API 状态
-    LOG_DEBUG() << "ViewInstanceManager: API 状态检查 - 指针:" << (void*)pApi 
-                << ", 已初始化:" << (pApi ? pApi->isInitialized() : false);
-    
-    // 检查设备发现状态(如果 API 有相关方法)
-    if (pApi && pApi->isInitialized()) {
-        // 尝试获取当前设备列表,检查是否为空
-        QStringList serialPorts = pApi->getAvailableSerialPorts();
-        QList<int> canDevices = pApi->getAvailableCanDevices();
-        LOG_DEBUG() << "ViewInstanceManager: 当前可用设备 - 串口数:" << serialPorts.size() 
-                    << ", CAN设备数:" << canDevices.size();
-        if (!serialPorts.isEmpty()) {
-            LOG_DEBUG() << "ViewInstanceManager: 可用串口列表:" << serialPorts.join(", ");
-        }
-    }
-    
-    // 设置 API 到设备树
-    pDeviceTree->setAPI(pApi);
-    LOG_DEBUG() << "ViewInstanceManager: DeviceTreeWidget::setAPI() 已调用";
-    
-    // 设置 API 后,再次检查设备列表(设备树内部会调用 updateDeviceList)
-    if (pApi && pApi->isInitialized()) {
-        QTimer::singleShot(100, [pApi]() {
-            QStringList serialPorts = pApi->getAvailableSerialPorts();
-            QList<int> canDevices = pApi->getAvailableCanDevices();
-            LOG_DEBUG() << "ViewInstanceManager: 延迟检查设备列表 - 串口数:" << serialPorts.size() 
-                        << ", CAN设备数:" << canDevices.size();
-        });
-    }
-    
-    registerView(EViewType::ViewDeviceTree, pDeviceTree);
-    LOG_DEBUG() << "ViewInstanceManager: DeviceTreeWidget 已注册到管理器";
-
-    // 创建 Modbus 配置组件(共享组件)
-    ModbusConfigWidget* pModbusConfig = new ModbusConfigWidget(pParent);
-    pModbusConfig->setBusCore(pBusCore);
-    pModbusConfig->setAPI(pApi);
-    registerView(EViewType::ViewModbusConfig, pModbusConfig);
-    LOG_DEBUG() << "ViewInstanceManager: ModbusConfigWidget 已创建并注册";
-
     // 创建原始数据表格组件(共享组件)
     RawDataTableWidget* pRawDataTable = new RawDataTableWidget(pParent);
     pRawDataTable->setBusCore(pBusCore);
@@ -270,14 +222,12 @@ void ViewInstanceManager::createSharedComponents(QWidget* pParent, DeviceBusCore
     registerView(EViewType::ViewBusDataTable, pBusDataTable);
     LOG_DEBUG() << "ViewInstanceManager: BusDataTableWidget 已创建并注册";
 
-    LOG_INFO() << "ViewInstanceManager: 共享组件创建完成,共创建 4 个组件";
+    LOG_INFO() << "ViewInstanceManager: 共享组件创建完成,共创建 2 个组件";
 }
 
 bool ViewInstanceManager::hasSharedComponents() const
 {
-    return hasView(EViewType::ViewDeviceTree) &&
-           hasView(EViewType::ViewModbusConfig) &&
-           hasView(EViewType::ViewRawDataTable) &&
+    return hasView(EViewType::ViewRawDataTable) &&
            hasView(EViewType::ViewBusDataTable);
 }
 
@@ -356,6 +306,24 @@ void ViewInstanceManager::createSerialComponents(QWidget* pParent, DeviceBusCore
         }
     }
 
+    // 创建串口页面的设备树组件(独立实例)
+    DeviceTreeWidget* pDeviceTree = new DeviceTreeWidget(pParent);
+    LOG_DEBUG() << "ViewInstanceManager: 串口页面 DeviceTreeWidget 对象已创建";
+    
+    // 设置 API 到设备树
+    pDeviceTree->setAPI(pApi);
+    LOG_DEBUG() << "ViewInstanceManager: 串口页面 DeviceTreeWidget::setAPI() 已调用";
+    
+    registerView(EViewType::ViewSerialDeviceTree, pDeviceTree);
+    LOG_DEBUG() << "ViewInstanceManager: 串口页面 DeviceTreeWidget 已注册到管理器";
+
+    // 创建串口页面的 Modbus 配置组件(独立实例)
+    ModbusConfigWidget* pModbusConfig = new ModbusConfigWidget(pParent);
+    pModbusConfig->setBusCore(pBusCore);
+    pModbusConfig->setAPI(pApi);
+    registerView(EViewType::ViewSerialModbusConfig, pModbusConfig);
+    LOG_DEBUG() << "ViewInstanceManager: 串口页面 ModbusConfigWidget 已创建并注册";
+
     // 创建串口设置组件(串口特有)
     SerialSettingsWidget* pSerialSettings = new SerialSettingsWidget(pParent);
     pSerialSettings->setAPI(pApi);
@@ -368,12 +336,14 @@ void ViewInstanceManager::createSerialComponents(QWidget* pParent, DeviceBusCore
     registerView(EViewType::ViewSerialData, pSerialData);
     LOG_DEBUG() << "ViewInstanceManager: SerialDataWidget 已创建并注册";
 
-    LOG_INFO() << "ViewInstanceManager: 串口特有组件创建完成,共创建 2 个组件";
+    LOG_INFO() << "ViewInstanceManager: 串口特有组件创建完成,共创建 4 个组件";
 }
 
 bool ViewInstanceManager::hasSerialComponents() const
 {
-    return hasView(EViewType::ViewSerialSettings) &&
+    return hasView(EViewType::ViewSerialDeviceTree) &&
+           hasView(EViewType::ViewSerialModbusConfig) &&
+           hasView(EViewType::ViewSerialSettings) &&
            hasView(EViewType::ViewSerialData);
 }
 
@@ -383,6 +353,8 @@ void ViewInstanceManager::destroySerialComponents()
 
     // 定义需要销毁的串口特有组件类型(不包括共享组件)
     QList<EViewType> serialViewTypes = {
+        EViewType::ViewSerialDeviceTree,
+        EViewType::ViewSerialModbusConfig,
         EViewType::ViewSerialSettings,
         EViewType::ViewSerialData
     };
@@ -480,6 +452,24 @@ void ViewInstanceManager::createNetworkComponents(QWidget* pParent, DeviceBusCor
         }
     }
 
+    // 创建网络页面的设备树组件(独立实例)
+    DeviceTreeWidget* pDeviceTree = new DeviceTreeWidget(pParent);
+    LOG_DEBUG() << "ViewInstanceManager: 网络页面 DeviceTreeWidget 对象已创建";
+    
+    // 设置 API 到设备树
+    pDeviceTree->setAPI(pApi);
+    LOG_DEBUG() << "ViewInstanceManager: 网络页面 DeviceTreeWidget::setAPI() 已调用";
+    
+    registerView(EViewType::ViewNetworkDeviceTree, pDeviceTree);
+    LOG_DEBUG() << "ViewInstanceManager: 网络页面 DeviceTreeWidget 已注册到管理器";
+
+    // 创建网络页面的 Modbus 配置组件(独立实例)
+    ModbusConfigWidget* pModbusConfig = new ModbusConfigWidget(pParent);
+    pModbusConfig->setBusCore(pBusCore);
+    pModbusConfig->setAPI(pApi);
+    registerView(EViewType::ViewNetworkModbusConfig, pModbusConfig);
+    LOG_DEBUG() << "ViewInstanceManager: 网络页面 ModbusConfigWidget 已创建并注册";
+
     // 创建网络设置组件(网络特有)
     NetworkSettingsWidget* pNetworkSettings = new NetworkSettingsWidget(pParent);
     if (!pNetworkSettings) {
@@ -500,12 +490,14 @@ void ViewInstanceManager::createNetworkComponents(QWidget* pParent, DeviceBusCor
     registerView(EViewType::ViewNetworkData, pNetworkData);
     LOG_DEBUG() << "ViewInstanceManager: NetworkDataWidget 已创建并注册";
 
-    LOG_INFO() << "ViewInstanceManager: 网络特有组件创建完成,共创建 2 个组件";
+    LOG_INFO() << "ViewInstanceManager: 网络特有组件创建完成,共创建 4 个组件";
 }
 
 bool ViewInstanceManager::hasNetworkComponents() const
 {
-    return hasView(EViewType::ViewNetworkSettings) &&
+    return hasView(EViewType::ViewNetworkDeviceTree) &&
+           hasView(EViewType::ViewNetworkModbusConfig) &&
+           hasView(EViewType::ViewNetworkSettings) &&
            hasView(EViewType::ViewNetworkData);
 }
 
@@ -515,6 +507,8 @@ void ViewInstanceManager::destroyNetworkComponents()
 
     // 定义需要销毁的网络特有组件类型(不包括共享组件)
     QList<EViewType> networkViewTypes = {
+        EViewType::ViewNetworkDeviceTree,
+        EViewType::ViewNetworkModbusConfig,
         EViewType::ViewNetworkSettings,
         EViewType::ViewNetworkData
     };
@@ -570,28 +564,32 @@ void ViewInstanceManager::initializeConnections()
     }
 
     // 获取主要视图实例
-    DeviceTreeWidget* pDeviceTree = getDeviceTreeWidget();
+    DeviceTreeWidget* pSerialDeviceTree = getSerialDeviceTreeWidget();
+    DeviceTreeWidget* pNetworkDeviceTree = getNetworkDeviceTreeWidget();
     SerialDockPage* pSerialDockPage = getSerialDockPage();
     NetworkDockPage* pNetworkDockPage = getNetworkDockPage();
     ViewCan* pViewCan = getViewCan();
 
-    // 连接设备树到各页面
-    if (pDeviceTree && pSerialDockPage) {
-        pConnector->connectTreeToSerialDockPage(pDeviceTree, pSerialDockPage);
+    // 连接串口页面的设备树到串口页面
+    if (pSerialDeviceTree && pSerialDockPage) {
+        pConnector->connectTreeToSerialDockPage(pSerialDeviceTree, pSerialDockPage);
     }
 
-    if (pDeviceTree && pNetworkDockPage) {
-        pConnector->connectTreeToNetworkDockPage(pDeviceTree, pNetworkDockPage);
+    // 连接网络页面的设备树到网络页面
+    if (pNetworkDeviceTree && pNetworkDockPage) {
+        pConnector->connectTreeToNetworkDockPage(pNetworkDeviceTree, pNetworkDockPage);
     }
 
-    if (pDeviceTree && pViewCan) {
-        pConnector->connectTreeToViewCan(pDeviceTree, pViewCan);
+    // 连接设备树到 CAN 视图(使用串口页面的设备树,因为 CAN 通常与串口相关)
+    if (pSerialDeviceTree && pViewCan) {
+        pConnector->connectTreeToViewCan(pSerialDeviceTree, pViewCan);
     }
 
     // 获取子组件并建立连接
     SerialSettingsWidget* pSerialSettings = getSerialSettingsWidget();
     NetworkSettingsWidget* pNetworkSettings = getNetworkSettingsWidget();
-    ModbusConfigWidget* pModbusConfig = getModbusConfigWidget();
+    ModbusConfigWidget* pSerialModbusConfig = getSerialModbusConfigWidget();
+    ModbusConfigWidget* pNetworkModbusConfig = getNetworkModbusConfigWidget();
     SerialDataWidget* pSerialData = getSerialDataWidget();
     NetworkDataWidget* pNetworkData = getNetworkDataWidget();
     RawDataTableWidget* pRawDataTable = getRawDataTableWidget();
@@ -602,21 +600,21 @@ void ViewInstanceManager::initializeConnections()
     // ========================================================================
 
     // 串口设置 -> Modbus配置(同步串口参数)
-    if (pSerialSettings && pModbusConfig) {
-        pConnector->connectSerialSettingsToModbusConfig(pSerialSettings, pModbusConfig);
+    if (pSerialSettings && pSerialModbusConfig) {
+        pConnector->connectSerialSettingsToModbusConfig(pSerialSettings, pSerialModbusConfig);
     }
 
     // Modbus配置 -> SerialDockPage(命令生成和配置应用)
-    if (pModbusConfig && pSerialDockPage) {
-        pConnector->connectModbusConfigToSerialDockPage(pModbusConfig, pSerialDockPage);
+    if (pSerialModbusConfig && pSerialDockPage) {
+        pConnector->connectModbusConfigToSerialDockPage(pSerialModbusConfig, pSerialDockPage);
         // 连接配置应用信号
-        connect(pModbusConfig, &ModbusConfigWidget::configApplied,
+        connect(pSerialModbusConfig, &ModbusConfigWidget::configApplied,
                 pSerialDockPage, &SerialDockPage::onModbusConfigApplied);
     }
 
     // Modbus配置 -> 串口数据(直接连接,用于快速发送命令)
-    if (pModbusConfig && pSerialData) {
-        pConnector->connectModbusConfigToSerialData(pModbusConfig, pSerialData);
+    if (pSerialModbusConfig && pSerialData) {
+        pConnector->connectModbusConfigToSerialData(pSerialModbusConfig, pSerialData);
     }
 
     // 串口设置 -> SerialDockPage(配置应用)
@@ -649,9 +647,9 @@ void ViewInstanceManager::initializeConnections()
     // ========================================================================
 
     // Modbus配置 -> NetworkDockPage(命令生成和配置应用)
-    if (pModbusConfig && pNetworkDockPage) {
+    if (pNetworkModbusConfig && pNetworkDockPage) {
         // 连接配置应用信号
-        connect(pModbusConfig, &ModbusConfigWidget::configApplied,
+        connect(pNetworkModbusConfig, &ModbusConfigWidget::configApplied,
                 pNetworkDockPage, &NetworkDockPage::onModbusConfigApplied);
         LOG_INFO() << "ViewInstanceManager: Modbus配置 -> NetworkDockPage 连接已建立";
     }
@@ -691,13 +689,22 @@ void ViewInstanceManager::initializeConnections()
     // 设备树与数据表格的连接
     // ========================================================================
 
-    // 设备树 -> 数据表格
-    if (pDeviceTree && pRawDataTable) {
-        pConnector->connectDeviceSelectionToRawDataTable(pDeviceTree, pRawDataTable);
+    // 串口页面的设备树 -> 数据表格
+    if (pSerialDeviceTree && pRawDataTable) {
+        pConnector->connectDeviceSelectionToRawDataTable(pSerialDeviceTree, pRawDataTable);
+    }
+
+    if (pSerialDeviceTree && pBusDataTable) {
+        pConnector->connectDeviceSelectionToBusDataTable(pSerialDeviceTree, pBusDataTable);
+    }
+
+    // 网络页面的设备树 -> 数据表格(两个设备树都连接到同一个数据表格)
+    if (pNetworkDeviceTree && pRawDataTable) {
+        pConnector->connectDeviceSelectionToRawDataTable(pNetworkDeviceTree, pRawDataTable);
     }
 
-    if (pDeviceTree && pBusDataTable) {
-        pConnector->connectDeviceSelectionToBusDataTable(pDeviceTree, pBusDataTable);
+    if (pNetworkDeviceTree && pBusDataTable) {
+        pConnector->connectDeviceSelectionToBusDataTable(pNetworkDeviceTree, pBusDataTable);
     }
 
     // 标记连接已初始化

+ 39 - 16
src/connect_signal/view_instance_manager.h

@@ -44,11 +44,13 @@ enum class EViewType
     ViewSerial,         ///< 串口视图(SerialDockPage)
     ViewNetwork,        ///< 网络视图(NetworkDockPage)
     ViewCan,            ///< CAN视图
-    ViewDeviceTree,     ///< 设备树视图
+    ViewSerialDeviceTree,     ///< 串口页面的设备树视图
+    ViewNetworkDeviceTree,    ///< 网络页面的设备树视图
     ViewSerialSettings, ///< 串口设置视图
     ViewNetworkSettings,///< 网络设置视图
     ViewNetworkData,    ///< 网络数据视图
-    ViewModbusConfig,   ///< Modbus配置视图
+    ViewSerialModbusConfig,   ///< 串口页面的Modbus配置视图
+    ViewNetworkModbusConfig, ///< 网络页面的Modbus配置视图
     ViewSerialData,     ///< 串口数据视图
     ViewRawDataTable,   ///< 原始数据表格视图
     ViewBusDataTable,   ///< 总线数据表格视图
@@ -140,10 +142,16 @@ public:
     ViewCore* getViewCore() const;
 
     /**
-     * @brief 获取设备树组件实例
+     * @brief 获取串口页面的设备树组件实例
      * @return DeviceTreeWidget 指针
      */
-    DeviceTreeWidget* getDeviceTreeWidget() const;
+    DeviceTreeWidget* getSerialDeviceTreeWidget() const;
+
+    /**
+     * @brief 获取网络页面的设备树组件实例
+     * @return DeviceTreeWidget 指针
+     */
+    DeviceTreeWidget* getNetworkDeviceTreeWidget() const;
 
     /**
      * @brief 获取串口设置组件实例
@@ -164,10 +172,16 @@ public:
     NetworkDataWidget* getNetworkDataWidget() const;
 
     /**
-     * @brief 获取Modbus配置组件实例
+     * @brief 获取串口页面的Modbus配置组件实例
      * @return ModbusConfigWidget 指针
      */
-    ModbusConfigWidget* getModbusConfigWidget() const;
+    ModbusConfigWidget* getSerialModbusConfigWidget() const;
+
+    /**
+     * @brief 获取网络页面的Modbus配置组件实例
+     * @return ModbusConfigWidget 指针
+     */
+    ModbusConfigWidget* getNetworkModbusConfigWidget() const;
 
     /**
      * @brief 获取串口数据组件实例
@@ -197,13 +211,14 @@ public:
      * @param pBusCore 设备总线核心指针
      * 
      * 创建以下共享组件并注册到管理器:
-     * - DeviceTreeWidget(设备树,串口、网络、CAN共享)
-     * - ModbusConfigWidget(Modbus配置,串口、网络共享)
      * - RawDataTableWidget(原始数据表格,串口、网络、CAN共享)
      * - BusDataTableWidget(总线数据表格,串口、网络、CAN共享)
      * 
      * 注意:此方法由 createSerialDockPage 和 createNetworkDockPage 内部调用
      * 如果共享组件已存在,则不会重复创建
+     * 
+     * 注意:DeviceTreeWidget 和 ModbusConfigWidget 不再作为共享组件,
+     * 而是为每个页面创建独立实例,避免Qt强制移动组件的问题
      */
     void createSharedComponents(QWidget* pParent, DeviceBusCore* pBusCore);
 
@@ -220,8 +235,9 @@ public:
      * 
      * 创建以下组件并注册到管理器:
      * - SerialDockPage(串口主页面)
-     * - 共享组件(如果尚未创建):DeviceTreeWidget、ModbusConfigWidget、RawDataTableWidget、BusDataTableWidget
+     * - 共享组件(如果尚未创建):RawDataTableWidget、BusDataTableWidget
      * - 串口特有组件:SerialSettingsWidget、SerialDataWidget
+     * - 串口页面的独立组件:ViewSerialDeviceTree、ViewSerialModbusConfig
      * 
      * 采用扁平化管理模式,所有组件统一由本管理器创建
      */
@@ -235,9 +251,11 @@ public:
      * 创建以下串口特有组件并注册到管理器:
      * - SerialSettingsWidget(串口设置)
      * - SerialDataWidget(串口数据)
+     * - DeviceTreeWidget(串口页面的设备树,独立实例)
+     * - ModbusConfigWidget(串口页面的Modbus配置,独立实例)
      * 
      * 注意:此方法由 createSerialDockPage 内部调用
-     * 共享组件(DeviceTreeWidget、ModbusConfigWidget等)由 createSharedComponents() 创建
+     * 共享组件(RawDataTableWidget、BusDataTableWidget)由 createSharedComponents() 创建
      */
     void createSerialComponents(QWidget* pParent, DeviceBusCore* pBusCore);
 
@@ -250,8 +268,9 @@ public:
     /**
      * @brief 销毁串口页面相关的特有组件
      * 
-     * 注销并删除串口特有组件(SerialSettingsWidget、SerialDataWidget)
-     * 注意:不会销毁共享组件
+     * 注销并删除串口特有组件(SerialSettingsWidget、SerialDataWidget、
+     * ViewSerialDeviceTree、ViewSerialModbusConfig)
+     * 注意:不会销毁共享组件(RawDataTableWidget、BusDataTableWidget)
      */
     void destroySerialComponents();
 
@@ -262,8 +281,9 @@ public:
      * 
      * 创建以下组件并注册到管理器:
      * - NetworkDockPage(网络主页面)
-     * - 共享组件(如果尚未创建):DeviceTreeWidget、ModbusConfigWidget、RawDataTableWidget、BusDataTableWidget
+     * - 共享组件(如果尚未创建):RawDataTableWidget、BusDataTableWidget
      * - 网络特有组件:NetworkSettingsWidget、NetworkDataWidget
+     * - 网络页面的独立组件:ViewNetworkDeviceTree、ViewNetworkModbusConfig
      * 
      * 采用扁平化管理模式,所有组件统一由本管理器创建
      */
@@ -277,9 +297,11 @@ public:
      * 创建以下网络特有组件并注册到管理器:
      * - NetworkSettingsWidget(网络设置)
      * - NetworkDataWidget(网络数据)
+     * - DeviceTreeWidget(网络页面的设备树,独立实例)
+     * - ModbusConfigWidget(网络页面的Modbus配置,独立实例)
      * 
      * 注意:此方法由 createNetworkDockPage 内部调用
-     * 共享组件(DeviceTreeWidget、ModbusConfigWidget等)由 createSharedComponents() 创建
+     * 共享组件(RawDataTableWidget、BusDataTableWidget)由 createSharedComponents() 创建
      */
     void createNetworkComponents(QWidget* pParent, DeviceBusCore* pBusCore);
 
@@ -292,8 +314,9 @@ public:
     /**
      * @brief 销毁网络页面相关的特有组件
      * 
-     * 注销并删除网络特有组件(NetworkSettingsWidget、NetworkDataWidget)
-     * 注意:不会销毁共享组件
+     * 注销并删除网络特有组件(NetworkSettingsWidget、NetworkDataWidget、
+     * ViewNetworkDeviceTree、ViewNetworkModbusConfig)
+     * 注意:不会销毁共享组件(RawDataTableWidget、BusDataTableWidget)
      */
     void destroyNetworkComponents();
 

+ 4 - 4
src/daemon/daemon_service.cpp

@@ -43,20 +43,20 @@ DaemonService::DaemonService(CoreService* coreService, QObject* parent)
     QTimer::singleShot(100, this, [this]() {
         SoftBusAPI* api = SoftBusAPI::instance();
         if (api && api->isInitialized()) {
-            // 连接串口信号
+            // 连接串口信号(使用队列连接确保线程安全)
             connect(api, &SoftBusAPI::serialDataReceived,
                     this, [this](const QString& portName, const QByteArray& data) {
                         QString base64Data = QString::fromUtf8(data.toBase64());
                         emit serialDataReceived(portName, base64Data);
-                    });
+                    }, Qt::QueuedConnection);
             
-            // 连接CAN信号
+            // 连接CAN信号(使用队列连接确保线程安全)
             connect(api, &SoftBusAPI::canDataReceived,
                     this, [this](const QString& deviceName, int canPort, unsigned int canId,
                                  const QByteArray& data, bool isExtendedId) {
                         QString base64Data = QString::fromUtf8(data.toBase64());
                         emit canDataReceived(deviceName, canPort, canId, base64Data, isExtendedId);
-                    });
+                    }, Qt::QueuedConnection);
         }
     });
 }

+ 0 - 12
src/my_dock_manager/mdockmanager.cpp

@@ -55,14 +55,6 @@ void MDockManager::addDockWidget(QWidget *widget, const QString &title, ads::Doc
 {
     if (!widget || !m_DockManager) return;
 
-    // 确保组件有合理的大小和可见性
-    if (widget->width() < 100 || widget->height() < 100) {
-        widget->setMinimumSize(200, 300);
-        widget->resize(250, 400);
-    }
-    widget->setVisible(true);
-    widget->show();
-
     // 创建停靠窗口
     ads::CDockWidget* dockWidget = new ads::CDockWidget(m_DockManager, title);
     dockWidget->setWidget(widget);
@@ -79,10 +71,6 @@ void MDockManager::addDockWidget(QWidget *widget, const QString &title, ads::Doc
     if (dockWidget->isClosed()) {
         dockWidget->toggleView(true);
     }
-    
-    // 确保停靠窗口显示
-    dockWidget->show();
-    dockWidget->raise();
 
     // 保存引用以便管理
     m_dockWidgets.insert(title, dockWidget);

+ 23 - 16
src/view_can/can_data_widget.cpp

@@ -83,6 +83,13 @@ void CanDataWidget::onCanDataReceived(const QString &deviceName, int canPort, un
     QString idTypeStr = isExtendedId ? "EID" : "SID";
     QString canPortStr = QString("CAN%1").arg(canPort + 1);
 
+    // 转义 HTML 特殊字符,防止破坏 HTML 结构导致崩溃
+    QString escapedDeviceName = deviceName.toHtmlEscaped();
+    QString escapedCanPortStr = canPortStr.toHtmlEscaped();
+    QString escapedCanIdStr = canIdStr.toHtmlEscaped();
+    QString escapedIdTypeStr = idTypeStr.toHtmlEscaped();
+    QString escapedDisplayData = displayData.toHtmlEscaped();
+    
     // 检查是否是当前设备的响应
     if (deviceName == m_currentDeviceId && m_waitingForResponse)
     {
@@ -93,21 +100,21 @@ void CanDataWidget::onCanDataReceived(const QString &deviceName, int canPort, un
         // 显示接收到的响应(带成功标记)
         ui->textEdit_can->append(QString("<span style='color:green;'>%1 %2 [%3] ID:%4 [接收✓] %5</span>")
                                 .arg(timestamp)
-                                .arg(deviceName)
-                                .arg(canPortStr)
-                                .arg(canIdStr)
-                                .arg(displayData));
+                                .arg(escapedDeviceName)
+                                .arg(escapedCanPortStr)
+                                .arg(escapedCanIdStr)
+                                .arg(escapedDisplayData));
     }
     else
     {
         // 普通接收显示
         ui->textEdit_can->append(QString("<span style='color:green;'>%1 %2 [%3] ID:%4 [%5] [接收] %6</span>")
                                 .arg(timestamp)
-                                .arg(deviceName)
-                                .arg(canPortStr)
-                                .arg(canIdStr)
-                                .arg(idTypeStr)
-                                .arg(displayData));
+                                .arg(escapedDeviceName)
+                                .arg(escapedCanPortStr)
+                                .arg(escapedCanIdStr)
+                                .arg(escapedIdTypeStr)
+                                .arg(escapedDisplayData));
     }
 }
 
@@ -163,7 +170,7 @@ void CanDataWidget::on_btn_can_detect_clicked()
                 failCount++;
                 ui->textEdit_can->append(QString("<span style='color:red;'>%1 [设备检测] 打开设备 %2 失败</span>")
                                         .arg(timestamp)
-                                        .arg(deviceName));
+                                        .arg(deviceName.toHtmlEscaped()));
                 continue;
             }
         }
@@ -178,7 +185,7 @@ void CanDataWidget::on_btn_can_detect_clicked()
             successCount++;
             ui->textEdit_can->append(QString("<span style='color:grey;'>%1 [设备检测→] %2 CAN%3 ID:%4</span>")
                                     .arg(timestamp)
-                                    .arg(deviceName)
+                                    .arg(deviceName.toHtmlEscaped())
                                     .arg(canPort + 1)
                                     .arg(detectCanId, 0, 16));
         }
@@ -187,7 +194,7 @@ void CanDataWidget::on_btn_can_detect_clicked()
             failCount++;
             ui->textEdit_can->append(QString("<span style='color:red;'>%1 [设备检测] 向设备 %2 发送失败</span>")
                                     .arg(timestamp)
-                                    .arg(deviceName));
+                                    .arg(deviceName.toHtmlEscaped()));
         }
     }
     
@@ -282,11 +289,11 @@ void CanDataWidget::on_btn_can_send_clicked()
         QString idTypeStr = isExtendedId ? "EID" : "SID";
         ui->textEdit_can->append(QString("<span style='color:blue;'>%1 [发送→] %2 [%3] ID:%4 [%5] %6</span>")
                                 .arg(timestamp)
-                                .arg(m_currentDeviceId)
-                                .arg(canPortStr)
+                                .arg(m_currentDeviceId.toHtmlEscaped())
+                                .arg(canPortStr.toHtmlEscaped())
                                 .arg(canId, 0, 16)
-                                .arg(idTypeStr)
-                                .arg(dataToSend));
+                                .arg(idTypeStr.toHtmlEscaped())
+                                .arg(dataToSend.toHtmlEscaped()));
     }
     else
     {

+ 3 - 2
src/view_can/viewcan.cpp

@@ -128,10 +128,11 @@ void ViewCan::createConnections()
     connect(m_deviceTreeWidget, &DeviceTreeWidget::deviceSelected,
             this, &ViewCan::onDeviceSelected);
     
-    // API信号 -> 组件
+    // API信号 -> 组件(使用队列连接确保线程安全)
     SoftBusAPI *api = SoftBusAPI::instance();
     connect(api, &SoftBusAPI::canDataReceived,
-            m_canDataWidget, &CanDataWidget::onCanDataReceived);
+            m_canDataWidget, &CanDataWidget::onCanDataReceived,
+            Qt::QueuedConnection);
     
     // 软总线消息存储信号 -> 更新图表/表格等
     connect(m_busCore, &DeviceBusCore::busMessageStored,

+ 32 - 23
src/view_device_config/device_tree_widget.ui

@@ -13,30 +13,39 @@
   <property name="windowTitle">
    <string>设备树</string>
   </property>
-  <layout class="QVBoxLayout" name="verticalLayout">
-   <item>
-    <widget class="QPushButton" name="btn_refresh">
-     <property name="text">
-      <string>刷新</string>
-     </property>
-    </widget>
-   </item>
-   <item>
-    <widget class="QTreeView" name="treeV_device">
-     <property name="selectionMode">
-      <enum>QAbstractItemView::SingleSelection</enum>
-     </property>
-     <property name="rootIsDecorated">
-      <bool>true</bool>
-     </property>
-     <property name="expandsOnDoubleClick">
-      <bool>false</bool>
-     </property>
-    </widget>
-   </item>
-  </layout>
+  <widget class="QPushButton" name="btn_refresh">
+   <property name="geometry">
+    <rect>
+     <x>9</x>
+     <y>9</y>
+     <width>80</width>
+     <height>30</height>
+    </rect>
+   </property>
+   <property name="text">
+    <string>刷新</string>
+   </property>
+  </widget>
+  <widget class="QTreeView" name="treeV_device">
+   <property name="geometry">
+    <rect>
+     <x>9</x>
+     <y>45</y>
+     <width>232</width>
+     <height>346</height>
+    </rect>
+   </property>
+   <property name="selectionMode">
+    <enum>QAbstractItemView::SelectionMode::SingleSelection</enum>
+   </property>
+   <property name="rootIsDecorated">
+    <bool>true</bool>
+   </property>
+   <property name="expandsOnDoubleClick">
+    <bool>false</bool>
+   </property>
+  </widget>
  </widget>
  <resources/>
  <connections/>
 </ui>
-

+ 8 - 19
src/view_network/networkdockpage.cpp

@@ -208,29 +208,18 @@ void NetworkDockPage::createUI()
         LOG_WARNING() << "SoftBusAPI not initialized yet, components may not work properly";
     }
 
-    // 确保设备树组件已创建(设备树由串口组件创建,但网络页面也需要使用)
-    // 必须在创建网络组件之前确保设备树存在
-    if (!m_viewMgr->hasView(EViewType::ViewDeviceTree))
+    // 确保共享组件已创建(数据表格等)
+    if (!m_viewMgr->hasSharedComponents())
     {
-        LOG_INFO() << "DeviceTreeWidget not found, creating serial components to initialize it";
-        // 如果设备树不存在,创建串口组件(这会创建设备树和其他共享组件)
-        if (!m_viewMgr->hasSerialComponents())
-        {
-            LOG_INFO() << "Creating serial components to initialize shared components";
-            m_viewMgr->createSerialComponents(this, m_busCore);
-        }
-        
-        // 再次检查设备树是否已创建
-        if (!m_viewMgr->hasView(EViewType::ViewDeviceTree))
-        {
-            LOG_ERROR() << "Failed to create DeviceTreeWidget after creating serial components";
-        }
+        LOG_INFO() << "共享组件不存在,正在创建...";
+        m_viewMgr->createSharedComponents(this, m_busCore);
     }
 
     // 通过 ViewInstanceManager 创建网络组件(扁平化管理模式)
+    // 网络组件包括:网络页面的设备树、Modbus配置、网络设置、网络数据
     if (!m_viewMgr->hasNetworkComponents())
     {
-        LOG_INFO() << "Creating network components";
+        LOG_INFO() << "网络组件不存在,正在创建...";
         m_viewMgr->createNetworkComponents(this, m_busCore);
     }
 
@@ -702,7 +691,7 @@ void NetworkDockPage::onBusMessageStored(const BusMessage &message)
 
 DeviceTreeWidget* NetworkDockPage::deviceTreeWidget() const
 {
-    return m_viewMgr ? m_viewMgr->getDeviceTreeWidget() : nullptr;
+    return m_viewMgr ? m_viewMgr->getNetworkDeviceTreeWidget() : nullptr;
 }
 
 NetworkSettingsWidget* NetworkDockPage::networkSettingsWidget() const
@@ -712,7 +701,7 @@ NetworkSettingsWidget* NetworkDockPage::networkSettingsWidget() const
 
 ModbusConfigWidget* NetworkDockPage::modbusConfigWidget() const
 {
-    return m_viewMgr ? m_viewMgr->getModbusConfigWidget() : nullptr;
+    return m_viewMgr ? m_viewMgr->getNetworkModbusConfigWidget() : nullptr;
 }
 
 NetworkDataWidget* NetworkDockPage::networkDataWidget() const

+ 12 - 8
src/view_serial/serial_data_widget.cpp

@@ -81,6 +81,10 @@ void SerialDataWidget::onSerialDataReceived(const QString &portName, const QByte
         displayData.replace('\t', "\\t");
     }
 
+    // 转义 HTML 特殊字符,防止破坏 HTML 结构导致崩溃
+    QString escapedPortName = portName.toHtmlEscaped();
+    QString escapedDisplayData = displayData.toHtmlEscaped();
+    
     // 检查是否是当前设备的响应
     if (portName == m_currentDeviceId && m_waitingForResponse)
     {
@@ -91,16 +95,16 @@ void SerialDataWidget::onSerialDataReceived(const QString &portName, const QByte
         // 显示接收到的响应(带成功标记)
         ui->textEdit_serial->append(QString("<span style='color:green;'>%1 串口%2 [接收✓] %3</span>")
                                     .arg(timestamp)
-                                    .arg(portName)
-                                    .arg(displayData));
+                                    .arg(escapedPortName)
+                                    .arg(escapedDisplayData));
     }
     else
     {
         // 普通接收显示
         ui->textEdit_serial->append(QString("<span style='color:green;'>%1 串口%2 [接收] %3</span>")
                                     .arg(timestamp)
-                                    .arg(portName)
-                                    .arg(displayData));
+                                    .arg(escapedPortName)
+                                    .arg(escapedDisplayData));
     }
 }
 
@@ -173,7 +177,7 @@ void SerialDataWidget::on_btn_serial_detect_clicked()
                 failCount++;
                 ui->textEdit_serial->append(QString("<span style='color:red;'>%1 [串口检测] 打开串口 %2 失败</span>")
                                             .arg(timestamp)
-                                            .arg(portName));
+                                            .arg(portName.toHtmlEscaped()));
                 continue;
             }
         }
@@ -191,14 +195,14 @@ void SerialDataWidget::on_btn_serial_detect_clicked()
             successCount++;
             ui->textEdit_serial->append(QString("<span style='color:grey;'>%1 [串口检测→] %2</span>")
                                         .arg(timestamp)
-                                        .arg(detectMessage));
+                                        .arg(detectMessage.toHtmlEscaped()));
         }
         else
         {
             failCount++;
             ui->textEdit_serial->append(QString("<span style='color:red;'>%1 [串口检测] 向串口 %2 发送失败</span>")
                                         .arg(timestamp)
-                                        .arg(portName));
+                                        .arg(portName.toHtmlEscaped()));
         }
     }
     
@@ -276,7 +280,7 @@ void SerialDataWidget::on_btn_serial_send_clicked()
         QString timestamp = QDateTime::currentDateTime().toString("[hh:mm:ss]");
         ui->textEdit_serial->append(QString("<span style='color:blue;'>%1 [发送→] %2</span>")
                                     .arg(timestamp)
-                                    .arg(dataToSend));
+                                    .arg(dataToSend.toHtmlEscaped()));
     }
     else
     {

+ 3 - 63
src/view_serial/serialdockpage.cpp

@@ -17,7 +17,6 @@
 #include <QSerialPortInfo>
 #include <QMap>
 #include <QHash>
-#include <QTimer>
 
 /**
  * @brief 构造函数
@@ -210,67 +209,8 @@ void SerialDockPage::createUI()
     // 添加空指针检查,避免段错误
     DeviceTreeWidget *pDeviceTree = deviceTreeWidget();
     if (pDeviceTree) {
-        // 在添加到 DockWidget 之前,确保组件有合理的大小和可见性
-        pDeviceTree->setMinimumSize(250, 400);
-        pDeviceTree->resize(250, 400);
-        pDeviceTree->setVisible(true);
-        pDeviceTree->show();
-        LOG_DEBUG() << "设备树组件准备就绪,大小:" << pDeviceTree->width() << "x" << pDeviceTree->height();
-        
-        QString dockTitle = tr("设备树");
-        addDockWidget(pDeviceTree, dockTitle, ads::LeftDockWidgetArea);
+        addDockWidget(pDeviceTree, tr("设备树"), ads::LeftDockWidgetArea);
         LOG_DEBUG() << "设备树组件已添加到布局";
-        
-        // 立即确保 DockWidget 可见
-        ads::CDockWidget* dockWidget = getDockWidget(dockTitle);
-        if (dockWidget) {
-            if (dockWidget->isClosed()) {
-                LOG_DEBUG() << "设备树停靠窗口已关闭,正在打开";
-                dockWidget->toggleView(true);
-            }
-            dockWidget->show();
-            dockWidget->raise();
-            
-            // 确保内部组件可见
-            QWidget* widget = dockWidget->widget();
-            if (widget) {
-                widget->setVisible(true);
-                widget->show();
-                widget->setMinimumSize(250, 400);
-                if (widget->width() < 200 || widget->height() < 200) {
-                    widget->resize(250, 400);
-                }
-                LOG_DEBUG() << "DockWidget 内部组件已设置为可见,大小:" << widget->width() << "x" << widget->height();
-            }
-            
-            LOG_DEBUG() << "设备树停靠窗口已设置为可见,DockWidget大小:" << dockWidget->width() << "x" << dockWidget->height();
-        } else {
-            LOG_WARNING() << "无法获取设备树停靠窗口";
-        }
-        
-        // 延迟刷新设备列表,确保布局完成后再更新
-        // 这样可以确保视图正确显示,避免模型更新时视图还未准备好
-        QTimer::singleShot(300, [pDeviceTree, dockTitle, this]() {
-            if (pDeviceTree) {
-                LOG_DEBUG() << "延迟刷新设备树列表";
-                // 强制刷新设备列表
-                pDeviceTree->updateDeviceList();
-                // 确保视图可见
-                pDeviceTree->ensureDockWidgetVisible();
-                // 再次确保 DockWidget 可见
-                ads::CDockWidget* dockWidget = getDockWidget(dockTitle);
-                if (dockWidget) {
-                    if (dockWidget->isClosed()) {
-                        dockWidget->toggleView(true);
-                    }
-                    dockWidget->show();
-                    dockWidget->raise();
-                }
-                // 强制刷新视图
-                pDeviceTree->update();
-                pDeviceTree->repaint();
-            }
-        });
     } else {
         LOG_ERROR() << "DeviceTreeWidget is null, cannot add to layout";
     }
@@ -864,7 +804,7 @@ void SerialDockPage::refreshDeviceLog()
 
 DeviceTreeWidget* SerialDockPage::deviceTreeWidget() const
 {
-    return m_viewMgr ? m_viewMgr->getDeviceTreeWidget() : nullptr;
+    return m_viewMgr ? m_viewMgr->getSerialDeviceTreeWidget() : nullptr;
 }
 
 SerialSettingsWidget* SerialDockPage::serialSettingsWidget() const
@@ -874,7 +814,7 @@ SerialSettingsWidget* SerialDockPage::serialSettingsWidget() const
 
 ModbusConfigWidget* SerialDockPage::modbusConfigWidget() const
 {
-    return m_viewMgr ? m_viewMgr->getModbusConfigWidget() : nullptr;
+    return m_viewMgr ? m_viewMgr->getSerialModbusConfigWidget() : nullptr;
 }
 
 SerialDataWidget* SerialDockPage::serialDataWidget() const

+ 1 - 1
src/view_serial/serialmodule.cpp

@@ -28,7 +28,7 @@ void SerialModule::setupUi(QMainWindow *owner) {
   m_page = ViewInstanceManager::instance()->createSerialDockPage(owner);
 
   m_toolbar = new Toolbar(tr("串口工具栏"), owner);
-  m_toolbar->hide();
+  // m_toolbar->hide();
   QAction *resetAction = m_toolbar->addAction(
       QIcon(":/qrc/icons/create_floating_table.svg"), tr("重置布局"));
   connect(resetAction, &QAction::triggered, this, [this]() {