This commit is contained in:
coco
2026-07-03 16:05:30 +08:00
commit df489d5640
1101 changed files with 779140 additions and 0 deletions
@@ -0,0 +1,434 @@
# 主界面
<cite>
**本文引用的文件**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp)
- [MainFrm.h](file://h/MainFrm.h)
- [Splash.cpp](file://cpp/Views/Splash.cpp)
- [Splash.h](file://h/Splash.h)
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp)
- [ChildFrm.cpp](file://cpp/Views/ChildFrm.cpp)
- [ChildFrm.h](file://h/ChildFrm.h)
- [Resource.h](file://Resource.h)
- [GeoMative.rc2](file://res/GeoMative.rc2)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本文件面向用户与开发者,系统性阐述主界面(CMainFrame)的布局结构、菜单系统、工具栏、状态栏与多文档界面(MDI)架构;解释应用启动初始化流程与主窗口的消息映射机制;结合MFC资源定义说明界面元素的可视化设计与事件绑定方式;提供主界面导航指南(窗口切换、视图管理与快捷操作);并给出开发者扩展方法(新增菜单项、集成自定义视图、处理WM_COMMAND消息)。同时覆盖启动画面(Splash)的显示逻辑与UI状态同步机制。
## 项目结构
主界面相关的核心文件集中在 Views 与 Main 目录:
- 主框架:cpp/Views/MainFrm.cpp、h/MainFrm.h
- 启动画面:cpp/Views/Splash.cpp、h/Splash.h
- 应用入口与初始化:cpp/Main/GeoMative.cpp
- 子框架(MDI子窗口):cpp/Views/ChildFrm.cpp、h/ChildFrm.h
- 资源与ID定义:Resource.h、res/GeoMative.rc2
```mermaid
graph TB
subgraph "应用层"
App["CGeoMativeApp<br/>应用入口与初始化"]
end
subgraph "主界面层"
MainFrm["CMainFrame<br/>主MDI框架"]
ToolBar["CToolBar<br/>工具栏"]
StatusBar["CStatusBar<br/>状态栏"]
Splash["CSplashWnd<br/>启动画面"]
end
subgraph "子窗口层"
ChildFrm["CChildFrame<br/>MDI子窗口"]
ChildView["CChildView<br/>子窗口视图"]
end
subgraph "资源层"
ResH["Resource.h<br/>资源ID常量"]
RC2["GeoMative.rc2<br/>非可编辑资源"]
end
App --> MainFrm
MainFrm --> ToolBar
MainFrm --> StatusBar
App --> Splash
MainFrm --> ChildFrm
ChildFrm --> ChildView
ResH --> MainFrm
ResH --> Splash
RC2 --> App
```
图表来源
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L190-L230)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L164-L224)
- [ChildFrm.cpp](file://cpp/Views/ChildFrm.cpp#L85-L118)
- [Resource.h](file://Resource.h#L17-L20)
- [GeoMative.rc2](file://res/GeoMative.rc2#L1-L14)
章节来源
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L190-L230)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L164-L224)
- [ChildFrm.cpp](file://cpp/Views/ChildFrm.cpp#L85-L118)
- [Resource.h](file://Resource.h#L17-L20)
- [GeoMative.rc2](file://res/GeoMative.rc2#L1-L14)
## 核心组件
- CMainFrame:继承自 CMDIFrameWnd,负责主MDI框架的创建、工具栏/状态栏初始化、菜单命令分发、MDI子窗口管理、消息映射与UI状态更新。
- CChildFrame:MDI子窗口,承载视图控件,处理焦点与命令转发。
- CSplashWnd:启动画面窗口类,负责显示与定时关闭。
- CGeoMativeApp:应用入口,负责初始化数据库、网络、线程、语言设置、主窗口创建与显示。
章节来源
- [MainFrm.h](file://h/MainFrm.h#L12-L118)
- [ChildFrm.h](file://h/ChildFrm.h#L12-L62)
- [Splash.h](file://h/Splash.h#L12-L56)
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L139-L230)
## 架构总览
主界面采用经典的MFC MDI架构:
- 应用启动时由 CGeoMativeApp 创建并显示 CMainFrame。
- CMainFrame 在 OnCreate 中创建工具栏与状态栏,并通过资源ID加载工具栏位图。
- 启动画面通过 CSplashWnd::ShowSplashScreen 在主窗口创建前显示,随后在初始化流程中逐步完成数据库连接、网络初始化、线程启动与UI状态更新。
- MDI子窗口通过 CChildFrame 承载视图,支持多文档切换与管理。
```mermaid
sequenceDiagram
participant App as "CGeoMativeApp"
participant Frame as "CMainFrame"
participant Splash as "CSplashWnd"
participant Child as "CChildFrame"
participant View as "CChildView"
App->>App : 初始化数据库/网络/线程/语言
App->>Splash : EnableSplashScreen()
App->>Frame : new CMainFrame / LoadFrame()
App->>Frame : ShowWindow(SW_SHOWMAXIMIZED)
Frame->>Splash : ShowSplashScreen(Frame)
Splash-->>Frame : 定时器触发/鼠标键盘事件隐藏
Frame->>Frame : OnCreate() 创建工具栏/状态栏
App->>App : 初始化完成,更新状态栏
Frame->>Child : CreateNewChild(...) 创建MDI子窗口
Child->>View : OnCreate() 创建视图
```
图表来源
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L139-L230)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L164-L224)
- [Splash.cpp](file://cpp/Views/Splash.cpp#L45-L142)
- [ChildFrm.cpp](file://cpp/Views/ChildFrm.cpp#L85-L118)
## 详细组件分析
### 主框架(CMainFrame)布局与消息映射
- 布局结构
- 工具栏:在 OnCreate 中创建并停靠,使用资源ID加载工具栏位图。
- 状态栏:在 OnCreate 中创建并设置指示器数组。
- MDI子窗口:通过 OnMngDataWin、OnMngExecWin、OnMngDevWin 等命令创建或激活对应子窗口。
- 消息映射
- BEGIN_MESSAGE_MAP 到 END_MESSAGE_MAP 映射了大量命令与消息,包括文件导入导出、测试窗口、同步、设备检测、语言切换、网络响应、升级通知等。
- WM_COMMAND 通过 ON_COMMAND 绑定到具体处理函数,如 OnFileExp、OnFileImp、OnTestrspWin、OnSynWin 等。
- 自定义消息通过 ON_MESSAGE 绑定,如 WM_SCHEDULE、WM_REFRESH、WM_NEWLINK、WM_BREAKLINE、WM_UPG_GEOMATIVE 等。
- 鼠标提示通过 ON_NOTIFY_EX(TTN_NEEDTEXT,0,OnToolTipText) 实现。
- 启动画面集成
- 在 OnCreate 中调用 CSplashWnd::ShowSplashScreen(this),并在短暂休眠后继续初始化流程。
```mermaid
classDiagram
class CMainFrame {
+LoadFrame(nIDResource, dwDefaultStyle, pParentWnd, pContext)
+OnCreate(lpCreateStruct)
+OnMngDataWin()
+OnMngExecWin()
+OnMngDevWin()
+OnFileExp()
+OnFileImp()
+OnTestrspWin()
+OnSynWin()
+OnLoggingTest()
+OnSetLinkUsb()
+OnSetLinkBluetooth()
+OnHelpUpg()
+OnLicenseUpg()
+OnPasswordManage()
+OnShowGeoWebsite()
+OnChangeChinese()
+OnChangeEnglish()
+OnDeviceChange(nEventType, dwData)
+OnTimer(nIDEvent)
+OnToolTipText(nID, pNMHDR, pResult)
+OnSchedule(wParam, lParam)
+OnRefresh(wParam, lParam)
+OnNewLink(wParam, lParam)
+OnBreakLine(wParam, lParam)
+OnUpgGeomative(wParam, lParam)
+DetectLine(wParam, lParam)
+CloseWindows(wParam, lParam)
+OnClearUpgInfo(wParam, lParam)
+OnShowUpgInfo(wParam, lParam)
+OnChangeLanguage(wParam, lParam)
+OnMsgNotifyDeviceOnOrOff(wParam, lParam)
+OnRefreshMainWndMenu(wParam, lParam)
+GetToolBar()
+SetStatusText(strText)
+GetGeoMativeVersion()
+LastErrorEx()
}
class CMDIFrameWnd
CMainFrame --|> CMDIFrameWnd
```
图表来源
- [MainFrm.h](file://h/MainFrm.h#L12-L118)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L58-L94)
章节来源
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L58-L94)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L164-L224)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L254-L328)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L330-L579)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L581-L622)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L624-L668)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L675-L753)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L755-L800)
### 启动画面(CSplashWnd
- 显示逻辑
- EnableSplashScreen 控制是否启用启动画面。
- ShowSplashScreen 创建并显示启动画面窗口,居中显示,设置定时器在指定毫秒后自动隐藏。
- PreTranslateAppMessage 拦截键盘与鼠标消息以提前关闭启动画面。
- UI状态同步
- 启动画面在主窗口创建前显示,主窗口初始化完成后通过 UpdateWindow 更新主界面状态。
```mermaid
sequenceDiagram
participant App as "CGeoMativeApp"
participant Frame as "CMainFrame"
participant Splash as "CSplashWnd"
App->>Splash : EnableSplashScreen(true)
App->>Frame : new CMainFrame / LoadFrame()
App->>Frame : ShowWindow()
Frame->>Splash : ShowSplashScreen(Frame)
Splash->>Splash : OnCreate() 居中/设置定时器
Splash->>Splash : OnTimer() 定时器触发
Splash->>Frame : HideSplashScreen() 销毁窗口
Frame->>Frame : UpdateWindow() 刷新主窗口
```
图表来源
- [Splash.cpp](file://cpp/Views/Splash.cpp#L45-L142)
- [Splash.h](file://h/Splash.h#L12-L56)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L193-L194)
章节来源
- [Splash.cpp](file://cpp/Views/Splash.cpp#L45-L142)
- [Splash.h](file://h/Splash.h#L12-L56)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L193-L194)
### 子框架(CChildFrame)与视图(CChildView
- CChildFrame
- PreCreateWindow 修改创建样式,移除客户端边框。
- OnCreate 创建默认视图控件并占满客户区。
- OnSetFocus 将焦点传递给子视图。
- OnCmdMsg 优先让视图处理命令,否则交由父类处理。
- CChildView
- 作为子窗口的默认视图,承载具体业务控件与交互。
```mermaid
classDiagram
class CChildFrame {
+PreCreateWindow(cs)
+OnCreate(lpCreateStruct)
+OnSetFocus(pOldWnd)
+OnFileClose()
+OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)
-m_wndView : CChildView
}
class CMDIChildWnd
class CChildView
CChildFrame --|> CMDIChildWnd
CChildFrame --> CChildView : "拥有"
```
图表来源
- [ChildFrm.h](file://h/ChildFrm.h#L12-L62)
- [ChildFrm.cpp](file://cpp/Views/ChildFrm.cpp#L18-L118)
章节来源
- [ChildFrm.cpp](file://cpp/Views/ChildFrm.cpp#L85-L118)
- [ChildFrm.h](file://h/ChildFrm.h#L12-L62)
### 菜单系统与工具栏
- 资源ID
- 主工具栏资源IDIDR_MAINFRAME
- 多种功能工具栏资源ID:如 IDR_TB_PRO_DB、IDR_TB_SPT_DB 等,分布在 Resource.h 中。
- 菜单与命令
- 主框架的消息映射中包含大量命令处理函数,如 OnMngDataWin、OnMngExecWin、OnMngDevWin、OnFileExp、OnFileImp、OnTestrspWin、OnSynWin、OnLoggingTest、OnSetLinkUsb、OnSetLinkBluetooth、OnHelpUpg、OnLicenseUpg、OnPasswordManage、OnShowGeoWebsite、OnChangeChinese、OnChangeEnglish 等。
- 事件绑定
- ON_COMMAND 将菜单项与处理函数绑定。
- ON_MESSAGE 将自定义消息与处理函数绑定。
- ON_NOTIFY_EX(TTN_NEEDTEXT,0,OnToolTipText) 提供工具提示文本。
章节来源
- [Resource.h](file://Resource.h#L17-L60)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L58-L94)
### 状态栏与指示器
- 指示器数组包含 ID_SEPARATOR、ID_INDICATOR_CAPS、ID_INDICATOR_NUM、ID_INDICATOR_SCRL 等标准指示器。
- CMainFrame 提供 SetStatusText 方法用于更新状态栏第一指示器文本。
章节来源
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L96-L102)
- [MainFrm.h](file://h/MainFrm.h#L39-L46)
### MDI子窗口管理与窗口切换
- 管理窗口
- OnMngDataWin:创建或激活数据管理子窗口。
- OnMngExecWin:创建或激活执行/任务管理子窗口。
- OnMngDevWin:创建或激活设备管理子窗口。
- 子窗口创建
- 通过 CreateNewChild(RUNTIME_CLASS(...), IDR_MAINFRAME) 创建子窗口。
- ShowWindow(SW_SHOWMAXIMIZED) 或 ActivateFrame() 激活窗口。
- 视图管理
- CChildFrame 在 OnCreate 中创建默认视图控件,OnSetFocus 将焦点交给视图。
- OnCmdMsg 优先让视图处理命令,保证视图优先响应。
章节来源
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L624-L668)
- [ChildFrm.cpp](file://cpp/Views/ChildFrm.cpp#L85-L118)
### 启动初始化流程与UI状态同步
- 应用入口
- CGeoMativeApp::InitInstance 完成OLE初始化、3D控件启用、主窗口创建与显示、数据库连接、网络初始化、线程创建、语言设置、菜单刷新等。
- UI状态更新
- 在数据库更新与初始化过程中,通过 SetStatusText 更新状态栏文本,向用户反馈进度。
- 启动画面
- 在主窗口创建前显示启动画面,初始化完成后销毁并刷新主窗口。
```mermaid
flowchart TD
Start(["应用启动"]) --> InitApp["CGeoMativeApp::InitInstance()"]
InitApp --> OLEInit["初始化OLE/控件容器"]
InitApp --> CreateFrame["创建并显示主窗口"]
InitApp --> DBConn["连接数据库"]
InitApp --> NetInit["网络初始化/线程启动"]
InitApp --> LangCfg["语言设置/菜单刷新"]
InitApp --> SplashShow["显示启动画面"]
CreateFrame --> StatusReady["状态栏就绪"]
DBConn --> StatusUpdates["更新状态栏"]
NetInit --> StatusUpdates
LangCfg --> StatusUpdates
SplashShow --> SplashHide["启动画面隐藏"]
StatusUpdates --> Ready(["应用就绪"])
```
图表来源
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L139-L230)
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L370-L422)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L193-L194)
章节来源
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L139-L230)
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L370-L422)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L193-L194)
## 依赖关系分析
- 组件耦合
- CMainFrame 依赖 CDevMngFrame、CDataMngFrame、CSptMngFrame 等管理框架类,用于创建/激活对应MDI子窗口。
- CMainFrame 依赖 CScheduler 进行调度与UI刷新。
- CMainFrame 依赖 CSplashWnd 进行启动画面显示。
- CChildFrame 依赖 CChildView 作为默认视图。
- 外部依赖
- 数据库连接:通过 ADO 连接 Access 数据库。
- 网络通信:网络初始化与工作线程启动。
- 系统线程:扫描设备线程、系统时间线程等。
```mermaid
graph LR
MainFrm["CMainFrame"] --> DevMng["CDevMngFrame"]
MainFrm --> DataMng["CDataMngFrame"]
MainFrm --> SptMng["CSptMngFrame"]
MainFrm --> Scheduler["CScheduler"]
MainFrm --> Splash["CSplashWnd"]
ChildFrm["CChildFrame"] --> ChildView["CChildView"]
App["CGeoMativeApp"] --> MainFrm
App --> DB["ADO数据库连接"]
App --> Net["网络模块"]
App --> Threads["系统线程"]
```
图表来源
- [MainFrm.h](file://h/MainFrm.h#L12-L48)
- [ChildFrm.h](file://h/ChildFrm.h#L12-L38)
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L233-L292)
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L578-L622)
章节来源
- [MainFrm.h](file://h/MainFrm.h#L12-L48)
- [ChildFrm.h](file://h/ChildFrm.h#L12-L38)
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L233-L292)
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L578-L622)
## 性能考虑
- 启动画面显示时长:启动画面定时器与用户交互(键盘/鼠标)会尽快结束,避免阻塞主流程。
- 线程与定时器:心跳包、设备扫描、市场数据上传等定时器需合理设置间隔,避免频繁唤醒影响性能。
- 数据库连接:连接字符串与锁策略已配置,注意异常捕获与资源释放,避免阻塞UI线程。
- 网络初始化:网络连接失败时及时提示并回退到离线模式,减少UI等待时间。
[本节为通用指导,不直接分析具体文件]
## 故障排查指南
- 启动失败
- OLE 初始化失败:检查系统COM组件与权限,查看提示信息。
- 数据库连接失败:确认数据库路径与密码正确,检查Jet OLEDB驱动安装。
- 网络初始化失败:检查IP/端口配置与网络连通性。
- 设备连接问题
- 设备掉线:OnBreakLine 处理设备断开,关闭串口并清理内存数据,必要时弹窗提示。
- 新设备连接:OnNewLink 处理新设备发现,自动注册与状态更新,必要时弹窗提示。
- UI无响应
- 检查定时器与线程是否正常运行,避免长时间阻塞消息循环。
- 状态栏文本更新:通过 SetStatusText 反馈当前状态,便于定位问题阶段。
章节来源
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L156-L170)
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L279-L310)
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L503-L521)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L254-L328)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L330-L579)
## 结论
CMainFrame 作为Geomative Studio的主界面核心,承担了MDI框架、工具栏/状态栏、菜单与命令处理、启动画面集成与UI状态同步等职责。通过清晰的消息映射与资源ID定义,实现了良好的可扩展性与可维护性。开发者可在现有基础上轻松添加新菜单项、集成自定义视图与处理WM_COMMAND消息,同时遵循现有的初始化流程与UI状态更新机制,确保应用稳定运行。
[本节为总结性内容,不直接分析具体文件]
## 附录
### 开发者扩展指南
- 添加新菜单项
- 在资源脚本中定义菜单项与图标ID(参考 Resource.h 中的IDR_*与IDD_*定义)。
- 在 MainFrm.h 的消息映射声明中添加对应处理函数原型。
- 在 MainFrm.cpp 的消息映射中添加 ON_COMMAND 绑定。
- 在 OnCreate 或相应时机更新菜单显示(如需要动态刷新)。
- 集成自定义视图
- 在 ChildFrm.cpp 的 OnCreate 中创建自定义视图控件,或通过 CreateNewChild 动态创建。
- 确保视图优先处理命令,必要时重写 OnCmdMsg 并将未处理命令交由父类。
- 处理WM_COMMAND消息
- 在 MainFrm.cpp 的消息映射中添加 ON_COMMAND 条目,实现具体业务逻辑。
- 对于复杂操作,建议封装到独立的管理器或对话框类中,保持消息处理函数简洁。
- 启动画面与UI状态同步
- 使用 CSplashWnd::ShowSplashScreen 在主窗口创建前显示启动画面。
- 在初始化流程中通过 SetStatusText 更新状态栏,向用户反馈进度。
- 在异常或失败场景及时提示并引导用户检查配置。
章节来源
- [Resource.h](file://Resource.h#L17-L60)
- [MainFrm.h](file://h/MainFrm.h#L59-L118)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L58-L94)
- [ChildFrm.cpp](file://cpp/Views/ChildFrm.cpp#L85-L118)
- [Splash.cpp](file://cpp/Views/Splash.cpp#L45-L142)
@@ -0,0 +1,230 @@
# 实时数据监控
<cite>
**本文档引用的文件**
- [DialListRealTimeMeasuData.cpp](file://cpp/Views/DialListRealTimeMeasuData.cpp)
- [DialListRealTimeMeasuData.h](file://h/DialListRealTimeMeasuData.h)
- [DialListRealTimeMeasuGR.cpp](file://cpp/Views/DialListRealTimeMeasuGR.cpp)
- [DialListRealTimeMeasuGR.h](file://h/DialListRealTimeMeasuGR.h)
- [DialRealTimeMeasureData.cpp](file://cpp/Views/DialRealTimeMeasureData.cpp)
- [DialRealTimeMeasureData.h](file://h/DialRealTimeMeasureData.h)
- [appdatatdlistview.cpp](file://cpp/Views/appdatatdlistview.cpp)
- [appdatatdgrlistview.cpp](file://cpp/Views/appdatatdgrlistview.cpp)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp)
- [NetWorkOper.cpp](file://cpp/Tools/NetWorkOper.cpp)
</cite>
## 目录
1. [引言](#引言)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构概述](#架构概述)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
## 引言
本文档深入探讨Geomative Studio软件中实时数据监控功能的实现机制。重点分析DialListRealTimeMeasuData和DialListRealTimeMeasuGR对话框如何实现测量数据的动态刷新与图形化展示,阐述DialRealTimeMeasureData对话框与设备通信模块(SComPort、NetWorkOper)的数据交互流程,包括数据帧解析、状态更新和异常处理。同时,文档将描述appdatatdlistview和appdatatdgrlistview组件在高频数据更新场景下的性能优化策略,并为用户提供操作指南,为开发者提供技术扩展路径。
## 项目结构
实时数据监控功能主要分布在`cpp/Views`目录下的多个对话框实现文件中,这些文件与`cpp/Tools`目录下的通信模块紧密协作。核心的UI组件和数据处理逻辑被清晰地分离,形成了一个模块化的架构。
```mermaid
graph TB
subgraph "UI 层"
A[DialRealTimeMeasureData] --> B[DialListRealTimeMeasuData]
A --> C[DialListRealTimeMeasuGR]
end
subgraph "通信层"
D[NetWorkOper] --> E[SComPort]
end
subgraph "数据层"
F[appdatatdlistview]
G[appdatatdgrlistview]
end
A --> D
B --> F
C --> G
```
**图表来源**
- [DialRealTimeMeasureData.cpp](file://cpp/Views/DialRealTimeMeasureData.cpp)
- [DialListRealTimeMeasuData.cpp](file://cpp/Views/DialListRealTimeMeasuData.cpp)
- [DialListRealTimeMeasuGR.cpp](file://cpp/Views/DialListRealTimeMeasuGR.cpp)
- [NetWorkOper.cpp](file://cpp/Tools/NetWorkOper.cpp)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp)
- [appdatatdlistview.cpp](file://cpp/Views/appdatatdlistview.cpp)
- [appdatatdgrlistview.cpp](file://cpp/Views/appdatatdgrlistview.cpp)
**章节来源**
- [cpp/Views](file://cpp/Views)
- [cpp/Tools](file://cpp/Tools)
## 核心组件
实时数据监控系统由多个核心组件构成,它们协同工作以实现数据的采集、处理和展示。DialRealTimeMeasureData作为主控对话框,负责协调数据流和用户交互;DialListRealTimeMeasuData和DialListRealTimeMeasuGR分别负责测量数据和接地电阻数据的列表展示;SComPort和NetWorkOper则构成了底层的通信基础设施。
**章节来源**
- [DialRealTimeMeasureData.h](file://h/DialRealTimeMeasureData.h)
- [DialListRealTimeMeasuData.h](file://h/DialListRealTimeMeasuData.h)
- [DialListRealTimeMeasuGR.h](file://h/DialListRealTimeMeasuGR.h)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp)
- [NetWorkOper.cpp](file://cpp/Tools/NetWorkOper.cpp)
## 架构概述
系统采用分层架构,将用户界面、业务逻辑和数据通信分离。主控对话框(DialRealTimeMeasureData)通过消息机制与子对话框(DialListRealTimeMeasuData/GR)进行通信,而通信模块(NetWorkOper)则通过异步线程处理网络和串口数据,确保UI的响应性。
```mermaid
graph TD
A[用户界面] --> |用户操作| B[主控对话框]
B --> |数据请求| C[通信模块]
C --> |串口/网络| D[测量设备]
D --> |实时数据| C
C --> |数据包| B
B --> |更新指令| E[数据展示组件]
E --> |刷新UI| A
```
**图表来源**
- [DialRealTimeMeasureData.cpp](file://cpp/Views/DialRealTimeMeasureData.cpp)
- [NetWorkOper.cpp](file://cpp/Tools/NetWorkOper.cpp)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp)
## 详细组件分析
### DialListRealTimeMeasuData 对话框分析
该对话框负责实时测量数据的列表展示,支持动态数据刷新和多种更新模式。
#### 动态数据刷新机制
DialListRealTimeMeasuData提供了三种数据更新方法,以适应不同的测量场景:
- `OnShowTdData`: 用于初始化时的全量数据加载。
- `OnShowTdDataAppend`: 用于在现有数据末尾追加新数据点。
- `OnShowTdDataUpdate`: 用于单点测量或从当前位置开始测量时的增量更新。
```mermaid
classDiagram
class CDialListRealTimeMeasureData {
+SetSptType(int)
+SetTaskID(int)
+SetMeasuStatus(const bool*)
+ShowMeasuStatus(CString)
+OnShowTdData(vector<STTaskDetailBasicData>)
+OnShowTdDataAppend(vector<STTaskDetailBasicData>)
+OnShowTdDataUpdate(vector<STTaskDetailBasicData>)
-m_listData CListCtrl
-m_iSptType int
-m_strMeasuStatus CString
-m_pMeasuStatus const bool*
}
```
**图表来源**
- [DialListRealTimeMeasuData.h](file://h/DialListRealTimeMeasuData.h)
- [DialListRealTimeMeasuData.cpp](file://cpp/Views/DialListRealTimeMeasuData.cpp)
**章节来源**
- [DialListRealTimeMeasuData.cpp](file://cpp/Views/DialListRealTimeMeasuData.cpp#L171-L343)
### DialRealTimeMeasureData 与通信模块交互分析
该组件是实时数据监控的核心,负责与设备通信模块进行数据交互。
#### 数据交互序列图
```mermaid
sequenceDiagram
participant UI as DialRealTimeMeasureData
participant Net as NetWorkOper
participant Dev as 测量设备
participant SCom as SComPort
UI->>Net : OnMeasureAll()
Net->>SCom : SendCtrlMsgDirect()
SCom->>Dev : 发送测量命令
Dev-->>SCom : 返回实时数据
SCom-->>Net : ReceiveDataDirectly()
Net->>UI : WM_NET_RECV_REAL_TIME_DATA
UI->>UI : 更新UI界面
```
**图表来源**
- [DialRealTimeMeasureData.cpp](file://cpp/Views/DialRealTimeMeasureData.cpp)
- [NetWorkOper.cpp](file://cpp/Tools/NetWorkOper.cpp)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp)
**章节来源**
- [DialRealTimeMeasureData.cpp](file://cpp/Views/DialRealTimeMeasureData.cpp#L485-L539)
- [NetWorkOper.cpp](file://cpp/Tools/NetWorkOper.cpp#L185-L203)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L527-L576)
### appdatatdlistview 高频数据更新优化分析
该组件在处理高频数据更新时采用了多种性能优化策略。
#### 性能优化流程图
```mermaid
flowchart TD
Start([开始数据更新]) --> CheckThread["检查是否在UI线程"]
CheckThread --> |是| UseTimer["使用定时器延迟更新"]
CheckThread --> |否| PostMessage["使用PostMessage跨线程通信"]
UseTimer --> UpdateUI["批量更新UI"]
PostMessage --> UpdateUI
UpdateUI --> End([结束])
```
**图表来源**
- [appdatatdlistview.cpp](file://cpp/Views/appdatatdlistview.cpp)
**章节来源**
- [appdatatdlistview.cpp](file://cpp/Views/appdatatdlistview.cpp#L72-L78)
## 依赖关系分析
系统各组件之间存在明确的依赖关系,形成了一个稳定的调用链。
```mermaid
graph LR
A[DialRealTimeMeasureData] --> B[DialListRealTimeMeasuData]
A --> C[DialListRealTimeMeasuGR]
A --> D[NetWorkOper]
D --> E[SComPort]
B --> F[appdatatdlistview]
C --> G[appdatatdgrlistview]
```
**图表来源**
- [DialRealTimeMeasureData.h](file://h/DialRealTimeMeasureData.h)
- [DialListRealTimeMeasuData.h](file://h/DialListRealTimeMeasuData.h)
- [DialListRealTimeMeasuGR.h](file://h/DialListRealTimeMeasuGR.h)
**章节来源**
- [DialRealTimeMeasureData.cpp](file://cpp/Views/DialRealTimeMeasureData.cpp#L154-L169)
## 性能考虑
在高频数据更新场景下,系统采用了多种性能优化策略来确保UI的流畅性。
### 性能优化策略表
| 优化策略 | 实现方式 | 适用场景 |
| :--- | :--- | :--- |
| 双缓冲绘图 | 使用内存中的缓冲区进行绘制,完成后一次性刷新到屏幕 | 避免UI闪烁 |
| 增量更新 | 只更新发生变化的数据项,而非全量刷新 | 减少UI重绘开销 |
| UI线程分离 | 将数据接收和处理放在独立线程,通过消息机制更新UI | 保持UI响应性 |
| 批量操作 | 将多个小的更新操作合并为一次大的更新 | 减少系统调用次数 |
**章节来源**
- [appdatatdlistview.cpp](file://cpp/Views/appdatatdlistview.cpp)
- [appdatatdgrlistview.cpp](file://cpp/Views/appdatatdgrlistview.cpp)
## 故障排除指南
本节提供常见问题的解决方案和调试建议。
### 常见问题及解决方案
| 问题现象 | 可能原因 | 解决方案 |
| :--- | :--- | :--- |
| 数据无法刷新 | 通信连接中断 | 检查设备连接状态,重新建立连接 |
| UI卡顿 | 高频数据更新导致 | 检查是否启用了性能优化策略 |
| 数据显示错误 | 数据帧解析异常 | 检查通信协议和数据格式 |
| 按钮无响应 | 状态机异常 | 检查按钮状态逻辑和状态转换 |
**章节来源**
- [DialRealTimeMeasureData.cpp](file://cpp/Views/DialRealTimeMeasureData.cpp#L484-L481)
- [NetWorkOper.cpp](file://cpp/Tools/NetWorkOper.cpp#L157-L181)
## 结论
Geomative Studio的实时数据监控功能通过精心设计的分层架构和高效的通信机制,实现了稳定可靠的数据采集和展示。系统通过DialListRealTimeMeasuData和DialListRealTimeMeasuGR对话框提供了直观的数据可视化界面,利用DialRealTimeMeasureData与SComPort、NetWorkOper等通信模块的紧密协作确保了数据的实时性。在性能方面,appdatatdlistview和appdatatdgrlistview组件通过双缓冲、增量更新和UI线程分离等策略,有效应对了高频数据更新的挑战。该系统为用户提供了完整的实时监控解决方案,同时也为开发者提供了清晰的扩展接口。
@@ -0,0 +1,251 @@
# 数据导出与导入
<cite>
**本文档引用的文件**
- [ioexpdlg.cpp](file://cpp/Views/ioexpdlg.cpp)
- [ioexpdmsdlg.cpp](file://cpp/Views/ioexpdmsdlg.cpp)
- [ioexpsptdlg.cpp](file://cpp/Views/ioexpsptdlg.cpp)
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp)
- [DialMeasureData.cpp](file://cpp/Views/DialMeasureData.cpp)
- [DownloadDataProgressDlg.cpp](file://cpp/Views/DownloadDataProgressDlg.cpp)
- [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp)
- [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp)
- [excel.cpp](file://cpp/Tools/excel.cpp)
- [ioexpdlg.h](file://h/ioexpdlg.h)
- [ioexpdmsdlg.h](file://h/ioexpdmsdlg.h)
- [ioexpsptdlg.h](file://h/ioexpsptdlg.h)
</cite>
## 目录
1. [引言](#引言)
2. [数据导出功能架构](#数据导出功能架构)
3. [导出对话框与用户交互](#导出对话框与用户交互)
4. [IOManager协调机制](#iomanager协调机制)
5. [文件操作工具实现](#文件操作工具实现)
6. [导出流程与进度反馈](#导出流程与进度反馈)
7. [用户操作指南](#用户操作指南)
8. [开发者扩展指南](#开发者扩展指南)
9. [结论](#结论)
## 引言
Geomative Studio软件提供了一套完整的数据导出与导入功能,旨在支持地质勘探数据在不同格式间的转换与共享。本系统化文档详细说明了`ioexpdlg``ioexpdmsdlg``ioexpsptdlg`三个核心对话框所支持的导出格式(包括Excel、CSV、TXT、URF)及其底层实现逻辑。文档深入解析了`IOManager`如何作为中央协调者,调用`OperTxtFile``OperUrfFile``excel`等专用文件操作工具来完成复杂的数据转换与文件生成任务。
此外,本文档阐述了从`DialMeasureData`对话框触发的完整导出流程,以及`DownloadDataProgressDlg`提供的实时进度反馈机制。为最终用户提供了关于如何选择导出范围、配置文件命名规则和验证导出完整性的详细操作说明。同时,为开发者提供了关于如何扩展支持新的导出格式(如JSON、PDF)、优化大数据量导出性能的缓冲策略,以及处理文件编码、跨平台换行符等兼容性问题的最佳实践。
**Section sources**
- [ioexpdlg.cpp](file://cpp/Views/ioexpdlg.cpp#L1-L244)
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L1-L2064)
## 数据导出功能架构
Geomative Studio的数据导出功能采用分层架构设计,由用户界面层、业务逻辑层和数据访问层协同工作。核心组件`IOManager`位于业务逻辑层,负责协调整个导出流程。当用户通过`DialMeasureData`等界面组件发起导出请求时,控制权会传递给`IOManager`
`IOManager`首先通过`CIOExpDlg`对话框收集用户的导出选项,包括选择要导出的项目、测区和测点数据。随后,它根据用户的选择,调用相应的数据提取和转换逻辑。对于数据库导出,`IOManager`使用ADOX库创建一个新的Access数据库文件(.accdb),并定义其表结构。然后,它将选定的数据从主数据库中提取出来,并插入到新创建的导出文件中。
对于其他格式(如TXT、URF、Excel),`IOManager`会实例化对应的文件操作工具类(如`OperTxtFile``OperUrfFile``excel`),并将数据流传递给它们进行格式化和写入。这种设计实现了关注点分离,使得`IOManager`可以专注于流程控制,而具体的文件格式实现则由专门的工具类负责。
```mermaid
graph TD
A[用户界面] --> B[IOManager]
B --> C[数据提取]
C --> D[格式转换]
D --> E[文件生成]
E --> F[导出文件]
B --> G[OperTxtFile]
B --> H[OperUrfFile]
B --> I[excel]
G --> E
H --> E
I --> E
```
**Diagram sources **
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L35-L98)
- [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp#L19-L35)
- [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp#L19-L29)
- [excel.cpp](file://cpp/Tools/excel.cpp#L1-L800)
**Section sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L35-L98)
- [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp#L19-L35)
- [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp#L19-L29)
- [excel.cpp](file://cpp/Tools/excel.cpp#L1-L800)
## 导出对话框与用户交互
数据导出功能通过一系列对话框与用户进行交互,其中`CIOExpDlg`是主对话框,它整合了`CIOExpDmsDlg``CIOExpSptDlg`两个子对话框,分别用于选择数据(项目、测区、测点)和脚本。
### CIOExpDlg 主对话框
`CIOExpDlg`继承自`CDialog`,其主要职责是提供一个选项卡式界面,让用户在“数据”和“脚本”两个选项卡之间切换。当用户点击“确定”按钮时,该对话框会检查用户是否在任一选项卡中选择了要导出的项目。如果未选择任何项目,会弹出提示框要求用户选择。如果选择了项目,则会弹出文件保存对话框,让用户指定导出文件的路径和名称(默认为.accdb格式)。
```mermaid
classDiagram
class CIOExpDlg {
+CString m_szFileName
+CIOExpDmsDlg m_ioDmsDlg
+CIOExpSptDlg m_ioSptDlg
-INT_PTR* m_pRet
+CIOExpDlg(CWnd* pParent)
+CIOExpDlg(INT_PTR* pRet, CWnd* pParent)
+virtual BOOL Create(UINT nID, CWnd* pParentWnd)
+virtual void OnOK()
+virtual void OnCancel()
+virtual BOOL OnInitDialog()
+afx_msg void OnSelchangeIoExpTab(NMHDR* pNMHDR, LRESULT* pResult)
}
class CIOExpDmsDlg {
+CTreeCtrl m_dmsTree
+CIOExpDmsDlg(CWnd* pParent)
+virtual BOOL OnInitDialog()
+afx_msg void OnShowWindow(BOOL bShow, UINT nStatus)
+afx_msg void OnClickTreeExpDms(NMHDR* pNMHDR, LRESULT* pResult)
+afx_msg void OnSelchangingTreeExpDms(NMHDR* pNMHDR, LRESULT* pResult)
}
class CIOExpSptDlg {
+CListCtrl m_sptList
+CIOExpSptDlg(CWnd* pParent)
+virtual BOOL OnInitDialog()
+afx_msg void OnShowWindow(BOOL bShow, UINT nStatus)
}
CIOExpDlg --> CIOExpDmsDlg : "包含"
CIOExpDlg --> CIOExpSptDlg : "包含"
```
**Diagram sources **
- [ioexpdlg.h](file://h/ioexpdlg.h#L16-L56)
- [ioexpdmsdlg.h](file://h/ioexpdmsdlg.h#L13-L44)
- [ioexpsptdlg.h](file://h/ioexpsptdlg.h#L13-L42)
### CIOExpDmsDlg 数据选择对话框
`CIOExpDmsDlg`使用一个`CTreeCtrl`(树形控件)来展示项目、测区和测点的层级结构。用户可以通过点击树节点旁的复选框来选择要导出的数据。该对话框在初始化时会设置树形控件的样式,使其显示连接线和按钮。`OnClickTreeExpDms`消息处理函数实现了智能的复选框逻辑:当用户选中一个父节点时,其所有子节点也会被自动选中;当用户取消选中一个父节点时,其所有子节点也会被取消选中。
### CIOExpSptDlg 脚本选择对话框
`CIOExpSptDlg`使用一个`CListCtrl`(列表控件)来展示所有可用的脚本。该控件被配置为支持全行选择、拖拽列头、网格线和复选框。在`OnInitDialog`函数中,它会动态地从资源文件中加载列标题(如“脚本编号”、“脚本名称”、“电极数量”等),并创建相应的列。
**Section sources**
- [ioexpdlg.cpp](file://cpp/Views/ioexpdlg.cpp#L1-L244)
- [ioexpdmsdlg.cpp](file://cpp/Views/ioexpdmsdlg.cpp#L1-L145)
- [ioexpsptdlg.cpp](file://cpp/Views/ioexpsptdlg.cpp#L1-L115)
- [ioexpdlg.h](file://h/ioexpdlg.h#L1-L62)
- [ioexpdmsdlg.h](file://h/ioexpdmsdlg.h#L1-L50)
- [ioexpsptdlg.h](file://h/ioexpsptdlg.h#L1-L48)
## IOManager协调机制
`IOManager`是整个数据导出功能的核心协调者。它通过`Export`方法启动导出流程。该方法首先创建并显示`CIOExpDlg`对话框,等待用户完成选择。一旦用户确认,`IOManager`会根据用户选择的文件路径,调用`CreateExpDatabase`方法创建一个新的Access数据库文件,并定义其表结构(如project、tz、td等)。
```mermaid
sequenceDiagram
participant User as 用户
participant CIOExpDlg as CIOExpDlg
participant IOManager as IOManager
participant Database as 数据库
participant File as 文件系统
User->>CIOExpDlg : 点击“导出”
CIOExpDlg->>CIOExpDlg : 显示对话框
User->>CIOExpDlg : 选择数据并点击“确定”
CIOExpDlg->>IOManager : 返回文件路径
IOManager->>IOManager : 创建导出数据库
IOManager->>Database : 提取选定数据
Database-->>IOManager : 返回数据
IOManager->>File : 写入数据到.accdb文件
File-->>IOManager : 写入完成
IOManager-->>User : 显示成功消息
```
**Diagram sources **
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L35-L98)
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L206-L656)
**Section sources**
- [IOManager.cpp](file://cpp/Managers/IOManager.cpp#L35-L98)
## 文件操作工具实现
### OperTxtFile 文本文件操作
`OperTxtFile`类负责将数据导出为纯文本(TXT)格式。它提供了一个`SetParamWidth`方法来设置每个字段的宽度,确保导出的文本文件具有整齐的列对齐。`OpenFileforWrite`方法用于打开或创建一个文本文件。`WriteFileContent`方法接收一个`CStringArray`,将数组中的每个字符串按照设定的宽度填充空格后写入文件,不足宽度的部分用空格补齐,每个数组元素写入后会自动添加换行符。
### OperUrfFile URF文件操作
`OperUrfFile`类专门用于生成通用电阻率数据文件(URF)。它支持多种电极阵列类型,如温纳-施伦贝谢(Wenner-Schlumberger)、跨孔(Cross-Hole)等。`WriteElecByAR`方法是核心,它根据传入的阵列类型(iAR)参数,调用不同的私有方法(如`WriteElecByWenSch``WriteElecByCrossHole`)来生成符合特定阵列几何形状的电极坐标。URF文件的头部包含固定的注释和单位信息。
### Excel 文件操作
`excel.cpp`文件包含通过MFC的`COleDispatchDriver`包装类与Microsoft Excel应用程序进行交互的代码。这些包装类(如`_Application``_Workbook``_Worksheet`)允许程序以自动化的方式创建Excel工作簿、写入数据、设置单元格格式等。虽然具体的导出逻辑未在提供的代码片段中完全展示,但可以推断`IOManager`会使用这些类来将数据写入Excel的单元格中,并生成.xlsx或.xls文件。
**Section sources**
- [OperTxtFile.cpp](file://cpp/Tools/OperTxtFile.cpp#L1-L166)
- [OperUrfFile.cpp](file://cpp/Tools/OperUrfFile.cpp#L1-L800)
- [excel.cpp](file://cpp/Tools/excel.cpp#L1-L800)
## 导出流程与进度反馈
### 从DialMeasureData触发导出
数据导出流程通常从`DialMeasureData`对话框开始,该对话框是用户进行测量操作的主要界面。当用户完成测量并希望导出数据时,可以通过菜单或按钮触发导出功能。`DialMeasureData`类本身不直接处理导出,而是通过调用`IOManager``Export`方法来启动整个流程。
### DownloadDataProgressDlg 进度反馈
在执行耗时较长的导出或导入操作时,系统会显示`DownloadDataProgressDlg`对话框来提供进度反馈。该对话框在初始化时会启动一个工作线程(`DownloadThread``UploadThread`),以避免阻塞主UI线程。工作线程会定期调用`ShowProcessPercent`方法,该方法根据已完成的工作量计算百分比,并更新对话框上的进度标签。这确保了用户界面的响应性,并让用户清楚地了解操作的进展情况。
**Section sources**
- [DialMeasureData.cpp](file://cpp/Views/DialMeasureData.cpp#L1-L800)
- [DownloadDataProgressDlg.cpp](file://cpp/Views/DownloadDataProgressDlg.cpp#L1-L479)
## 用户操作指南
### 选择导出范围
1. 在软件主界面,导航到需要导出数据的项目。
2. 右键点击项目、测区或测点,选择“导出”选项。
3. 在弹出的“数据导出”对话框中,切换到“数据”选项卡。
4. 在树形结构中,勾选您想要导出的项目、测区和测点。勾选父节点会自动包含其所有子节点。
5. 切换到“脚本”选项卡,勾选您想要导出的脚本。
### 配置文件命名规则
1. 完成选择后,点击“确定”。
2. 系统会弹出“另存为”对话框。
3. 在“文件名”输入框中,输入您希望的文件名。
4. 系统默认的文件扩展名为`.accdb`,您也可以选择其他格式(如果功能支持)。
5. 选择保存位置,然后点击“保存”。
### 验证导出完整性
1. 导出完成后,系统会显示“导出成功”的提示。
2. 前往您指定的保存位置,找到导出的文件。
3. 打开文件(例如,用Access打开.accdb文件,用文本编辑器打开.txt文件)。
4. 检查文件内容是否与您在导出对话框中选择的数据范围一致,确保所有必要的数据都已包含在内。
## 开发者扩展指南
### 新增导出格式(如JSON、PDF
要支持新的导出格式,开发者需要遵循以下步骤:
1. **创建新的工具类**:创建一个名为`OperJsonFile``OperPdfFile`的新类,类似于`OperTxtFile``OperUrfFile`
2. **实现核心方法**:在新类中实现`OpenFile``WriteData``CloseFile`等核心方法。对于JSON,可以使用第三方库(如nlohmann/json)来构建和序列化JSON对象。对于PDF,可以使用库(如libHaru或PoDoFo)来创建PDF文档并写入表格数据。
3. **扩展IOManager**:在`IOManager`类中添加新的导出方法(如`ExportToJSON``ExportToPDF`),并在`Export`方法中根据用户选择的格式调用相应的方法。
4. **更新用户界面**:在“另存为”对话框的文件类型过滤器中添加新的格式选项(如`JSON Files (*.json)|*.json||`)。
### 优化大数据量导出性能
对于大数据量的导出,应采用缓冲和分块处理策略:
1. **分批读取**:不要一次性将所有数据加载到内存中。使用数据库的分页查询(如`LIMIT``OFFSET`)或游标,分批读取数据。
2. **缓冲写入**:在文件操作工具中,使用缓冲区(buffer)来累积一定量的数据后再写入磁盘,减少I/O操作次数。
3. **异步处理**:将导出操作放在后台线程中执行,避免阻塞UI。`DownloadDataProgressDlg`的实现已经展示了如何使用`AfxBeginThread`来实现这一点。
### 处理兼容性问题
1. **文件编码**:对于文本文件(TXT、CSV),应明确指定编码格式(如UTF-8)。在`OperTxtFile`中,可以修改`fopen`调用,使用`"w+, ccs=UTF-8"`来确保文件以UTF-8编码保存,避免中文乱码。
2. **跨平台换行符**Windows使用`\r\n`,而Unix/Linux使用`\n`。在`OperTxtFile``WriteFileContent`方法中,可以根据目标平台动态选择换行符。可以通过编译宏(如`_WIN32`)来判断当前平台。
## 结论
Geomative Studio的数据导出与导入功能通过清晰的分层架构和模块化设计,实现了高效、可靠的数据交换。`IOManager`作为核心协调者,有效地整合了用户界面、数据访问和文件生成等多个组件。通过分析`ioexpdlg`系列对话框和`OperTxtFile``OperUrfFile`等工具类,我们理解了系统如何支持多种导出格式并提供良好的用户体验。
本文档不仅为用户提供了清晰的操作指南,也为开发者指明了扩展和优化的方向。通过遵循本文档中的最佳实践,可以确保新功能的顺利集成,并持续提升软件在处理复杂地质数据方面的专业性和可靠性。
@@ -0,0 +1,250 @@
# 数据管理界面
<cite>
**本文档引用的文件**
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp)
- [datamngframe.h](file://h/datamngframe.h)
- [appdatatdlistview.cpp](file://cpp/Views/appdatatdlistview.cpp)
- [appdatatdlistview.h](file://h/appdatatdlistview.h)
- [appdatatdgrlistview.cpp](file://cpp/Views/appdatatdgrlistview.cpp)
- [appdatatdgrlistview.h](file://h/appdatatdgrlistview.h)
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
- [DataOperator.h](file://h/DataOperator.h)
- [navdataview.cpp](file://cpp/Views/navdataview.cpp)
- [navdataview.h](file://h/navdataview.h)
- [excel.cpp](file://cpp/Tools/excel.cpp)
- [excel.h](file://h/excel.h)
</cite>
## 目录
1. [引言](#引言)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构概述](#架构概述)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
## 引言
数据管理界面是Geomative Studio软件的核心功能模块,负责测量数据的浏览、实时监控、数据导出与导入等关键任务。该界面通过`datamngframe`框架集成多种数据视图,如`appdatatdlistview``appdatatdgrlistview`,实现数据列表、图形化展示与详细信息面板的联动。用户可以通过该界面执行数据查询、筛选、导出(支持Excel、CSV、TXT、URF格式)和诊断报告生成等操作。开发者可以扩展数据导出格式、集成新的数据可视化组件或优化大数据量下的界面响应性能。
## 项目结构
数据管理界面的代码主要分布在`cpp/Views``h`目录下,核心文件包括`datamngframe.cpp``appdatatdlistview.cpp``appdatatdgrlistview.cpp``DataOperator.cpp`。这些文件共同构成了数据管理的框架和视图组件。
```mermaid
graph TD
subgraph "数据管理界面"
datamngframe[datamngframe.cpp]
appdatatdlistview[appdatatdlistview.cpp]
appdatatdgrlistview[appdatatdgrlistview.cpp]
DataOperator[DataOperator.cpp]
navdataview[navdataview.cpp]
end
datamngframe --> DataOperator
appdatatdlistview --> DataOperator
appdatatdgrlistview --> DataOperator
navdataview --> DataOperator
```
**Diagram sources**
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp)
- [appdatatdlistview.cpp](file://cpp/Views/appdatatdlistview.cpp)
- [appdatatdgrlistview.cpp](file://cpp/Views/appdatatdgrlistview.cpp)
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
- [navdataview.cpp](file://cpp/Views/navdataview.cpp)
**Section sources**
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp)
- [appdatatdlistview.cpp](file://cpp/Views/appdatatdlistview.cpp)
- [appdatatdgrlistview.cpp](file://cpp/Views/appdatatdgrlistview.cpp)
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
- [navdataview.cpp](file://cpp/Views/navdataview.cpp)
## 核心组件
数据管理界面的核心组件包括`CDataMngFrame``CAppDataTdListView``CAppDataTdGrListView``CDataOperator``CDataMngFrame`作为主框架,管理界面的布局和视图切换。`CAppDataTdListView``CAppDataTdGrListView`分别负责数据列表和图形化数据的展示。`CDataOperator`作为数据操作器,处理数据的加载、导出和删除等操作。
**Section sources**
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp)
- [appdatatdlistview.cpp](file://cpp/Views/appdatatdlistview.cpp)
- [appdatatdgrlistview.cpp](file://cpp/Views/appdatatdgrlistview.cpp)
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
## 架构概述
数据管理界面采用MVCModel-View-Controller)架构,`CDataOperator`作为模型层,负责数据的存取和业务逻辑。`CDataMngFrame`作为控制器,管理视图的创建和切换。`CAppDataTdListView``CAppDataTdGrListView`作为视图层,负责数据的展示。
```mermaid
classDiagram
class CDataMngFrame {
+CView* m_pAppDataView
+CView* m_pNavDataView
+bool ShowAppView(DWORD dwHandle, UINT uState)
+bool ShowContentListByPageView(DWORD dwHandle, UINT uState, UINT uPage)
}
class CDataOperator {
+_ConnectionPtr m_pConnection
+CStateProcessor m_stateProcessor
+CHandleProcessor m_handleProcessor
+bool InitialNavDataView(CNavDataView* pNavDataView)
+void ShowRsp2DTdInfo(DWORD dwTdHandle, CView* pAppDataView)
+void ShowRspCETdInfo(DWORD dwTdHandle, CView* pAppDataView)
+UINT ExportRsp2DTdToExcel(CNavDataView* pNavDataView, CString f_szFileName)
}
class CAppDataTdListView {
+CMDIChildWnd* m_pMngFrm
+void OnColumnclick(NMHDR* pNMHDR, LRESULT* pResult)
+void OnDblclk(NMHDR* pNMHDR, LRESULT* pResult)
+void OnBatchexport()
+void OnBatchDelData()
}
class CAppDataTdGrListView {
+CMDIChildWnd* m_pMngFrm
+void OnColumnclick(NMHDR* pNMHDR, LRESULT* pResult)
+void OnCustomDrawList(NMHDR* pNMHDR, LRESULT* pResult)
}
class CNavDataView {
+CTreeCtrl m_dataTree
+void Schedule()
+void LoadByPageShedule()
+void OnRclickNavDataTree(NMHDR* pNMHDR, LRESULT* pResult)
+void OnSelchangedNavDataTree(NMHDR* pNMHDR, LRESULT* pResult)
}
CDataMngFrame --> CDataOperator : "uses"
CDataMngFrame --> CAppDataTdListView : "creates"
CDataMngFrame --> CAppDataTdGrListView : "creates"
CDataOperator --> CNavDataView : "manages"
CAppDataTdListView --> CDataOperator : "delegates"
CAppDataTdGrListView --> CDataOperator : "delegates"
```
**Diagram sources**
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp)
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
- [appdatatdlistview.cpp](file://cpp/Views/appdatatdlistview.cpp)
- [appdatatdgrlistview.cpp](file://cpp/Views/appdatatdgrlistview.cpp)
- [navdataview.cpp](file://cpp/Views/navdataview.cpp)
## 详细组件分析
### 数据管理框架分析
`CDataMngFrame`是数据管理界面的主框架,继承自`CMDIChildWnd`,负责管理界面的布局和视图切换。它通过`CSplitterWnd`将界面分为导航视图和应用视图两部分。
#### 数据管理框架类图
```mermaid
classDiagram
class CDataMngFrame {
+CView* m_pAppDataView
+CView* m_pNavDataView
+CSplitterWnd m_splitter
+CDataOperator* m_pDataOperator
+bool ShowAppView(DWORD dwHandle, UINT uState)
+bool ShowContentListByPageView(DWORD dwHandle, UINT uState, UINT uPage)
}
CDataMngFrame --> CDataOperator : "owns"
CDataMngFrame --> CView : "contains"
```
**Diagram sources**
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp)
- [datamngframe.h](file://h/datamngframe.h)
### 数据列表视图分析
`CAppDataTdListView`负责展示测量数据的列表,支持列排序、双击跳转和批量导出/删除操作。
#### 数据列表视图类图
```mermaid
classDiagram
class CAppDataTdListView {
+CMDIChildWnd* m_pMngFrm
+void OnColumnclick(NMHDR* pNMHDR, LRESULT* pResult)
+void OnDblclk(NMHDR* pNMHDR, LRESULT* pResult)
+void OnBatchexport()
+void OnBatchDelData()
}
CAppDataTdListView --> CDataMngFrame : "belongs to"
```
**Diagram sources**
- [appdatatdlistview.cpp](file://cpp/Views/appdatatdlistview.cpp)
- [appdatatdlistview.h](file://h/appdatatdlistview.h)
### 图形化数据视图分析
`CAppDataTdGrListView`负责展示电极的图形化数据,支持自定义绘制,根据电极状态显示不同颜色。
#### 图形化数据视图类图
```mermaid
classDiagram
class CAppDataTdGrListView {
+CMDIChildWnd* m_pMngFrm
+void OnColumnclick(NMHDR* pNMHDR, LRESULT* pResult)
+void OnCustomDrawList(NMHDR* pNMHDR, LRESULT* pResult)
}
CAppDataTdGrListView --> CDataMngFrame : "belongs to"
```
**Diagram sources**
- [appdatatdgrlistview.cpp](file://cpp/Views/appdatatdgrlistview.cpp)
- [appdatatdgrlistview.h](file://h/appdatatdgrlistview.h)
### 数据操作器分析
`CDataOperator`是数据管理的核心,负责与数据库交互,加载和导出数据。
#### 数据操作器类图
```mermaid
classDiagram
class CDataOperator {
+_ConnectionPtr m_pConnection
+CStateProcessor m_stateProcessor
+CHandleProcessor m_handleProcessor
+bool InitialNavDataView(CNavDataView* pNavDataView)
+void ShowRsp2DTdInfo(DWORD dwTdHandle, CView* pAppDataView)
+void ShowRspCETdInfo(DWORD dwTdHandle, CView* pAppDataView)
+UINT ExportRsp2DTdToExcel(CNavDataView* pNavDataView, CString f_szFileName)
}
CDataOperator --> _ConnectionPtr : "uses"
CDataOperator --> CStateProcessor : "uses"
CDataOperator --> CHandleProcessor : "uses"
```
**Diagram sources**
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
- [DataOperator.h](file://h/DataOperator.h)
**Section sources**
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
- [DataOperator.h](file://h/DataOperator.h)
## 依赖分析
数据管理界面依赖于`CDataOperator`进行数据操作,`CDataOperator`又依赖于数据库连接和状态处理器。
```mermaid
graph TD
CDataMngFrame --> CDataOperator
CDataOperator --> _ConnectionPtr
CDataOperator --> CStateProcessor
CDataOperator --> CHandleProcessor
CAppDataTdListView --> CDataOperator
CAppDataTdGrListView --> CDataOperator
```
**Diagram sources**
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp)
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
- [appdatatdlistview.cpp](file://cpp/Views/appdatatdlistview.cpp)
- [appdatatdgrlistview.cpp](file://cpp/Views/appdatatdgrlistview.cpp)
## 性能考虑
在处理大数据量时,应优化数据加载和渲染性能。建议使用分页加载和虚拟列表技术,避免一次性加载所有数据。
## 故障排除指南
- **数据无法加载**:检查数据库连接是否正常,确认`CDataOperator``m_pConnection`是否有效。
- **导出失败**:检查文件路径和权限,确保Excel组件正确安装。
- **界面卡顿**:减少一次性加载的数据量,使用分页或虚拟列表。
**Section sources**
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
- [excel.cpp](file://cpp/Tools/excel.cpp)
## 结论
数据管理界面通过`datamngframe`框架和`DataOperator`组件,实现了测量数据的高效管理和可视化。开发者可以通过扩展`CDataOperator`来支持新的数据格式和导出功能,优化大数据量下的性能表现。
@@ -0,0 +1,225 @@
# 测量数据浏览
<cite>
**本文档引用的文件**
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp)
- [appdatatdlistview.cpp](file://cpp/Views/appdatatdlistview.cpp)
- [appdatatddetaillistview.cpp](file://cpp/Views/appdatatddetaillistview.cpp)
- [appdatatdgrlistview.cpp](file://cpp/Views/appdatatdgrlistview.cpp)
- [DialListMeasuData.cpp](file://cpp/Views/DialListMeasuData.cpp)
- [DialListMeasuGR.cpp](file://cpp/Views/DialListMeasuGR.cpp)
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
- [Ipsp2DTd.cpp](file://cpp/ProblemZone/Ipsp2DTd.cpp)
- [Ipsp2DTdRecord.cpp](file://cpp/ProblemZone/Ipsp2DTdRecord.cpp)
- [HandleProcessor.cpp](file://cpp/Tools/HandleProcessor.cpp)
</cite>
## 目录
1. [引言](#引言)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构概述](#架构概述)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
## 引言
本文档详细阐述了GeomativeStudio软件中测量数据浏览功能的实现机制。重点分析了数据管理框架(datamngframe)如何集成测试数据列表视图(appdatatdlistview)、详细信息面板(appdatatddetaillistview)和图形化展示组件(appdatatdgrlistview)的联动机制。文档描述了用户通过DialListMeasuData和DialListMeasuGR对话框进行数据查询、筛选和可视化操作的完整流程,并为开发者提供了扩展数据展示字段、自定义排序规则或集成新型图表组件的技术指导。
## 项目结构
GeomativeStudio项目是一个复杂的地质测量软件系统,其核心功能围绕数据采集、管理和可视化展开。测量数据浏览功能主要位于`cpp/Views`目录下,由一系列视图类和对话框类构成。数据管理框架`CDataMngFrame`作为主容器,负责协调各个子视图的显示和数据交互。
```mermaid
graph TD
subgraph "数据管理框架"
DMF[CDataMngFrame]
end
subgraph "视图组件"
TLV[CAppDataTdListView]
DLV[CAppDataTdDetailListView]
GLV[CAppDataTdGrListView]
end
subgraph "对话框"
DLM[CDialogListMeasuData]
DGR[CDialogListMeasuGR]
end
DMF --> TLV
DMF --> DLV
DMF --> GLV
DLM --> TLV
DGR --> GLV
```
**图表来源**
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp#L49-L81)
- [appdatatdlistview.cpp](file://cpp/Views/appdatatdlistview.cpp#L22-L33)
- [appdatatddetaillistview.cpp](file://cpp/Views/appdatatddetaillistview.cpp#L17-L34)
- [appdatatdgrlistview.cpp](file://cpp/Views/appdatatdgrlistview.cpp#L21-L38)
- [DialListMeasuData.cpp](file://cpp/Views/DialListMeasuData.cpp#L18-L39)
- [DialListMeasuGR.cpp](file://cpp/Views/DialListMeasuGR.cpp#L17-L41)
**章节来源**
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp#L1-L81)
- [appdatatdlistview.cpp](file://cpp/Views/appdatatdlistview.cpp#L1-L485)
- [appdatatddetaillistview.cpp](file://cpp/Views/appdatatddetaillistview.cpp#L1-L318)
- [appdatatdgrlistview.cpp](file://cpp/Views/appdatatdgrlistview.cpp#L1-L189)
## 核心组件
测量数据浏览功能的核心在于`CDataMngFrame`类,它作为MDI子窗口,通过分割窗口(CSplitterWnd)将界面划分为导航视图(CNavDataView)和应用数据视图(CAppDataView)。应用数据视图会根据用户选择的数据类型动态切换为不同的具体视图,如`CAppDataRsp2DTdView``CAppDataIpsp2DTdView`等。
`CAppDataTdListView`负责以列表形式展示测量数据,支持列点击排序和双击跳转。`CAppDataTdDetailListView`则以键值对的形式展示所选数据的详细信息。`CAppDataTdGrListView`用于展示电极的电阻测量结果,通过自定义绘制实现不同状态(如短路、开路)的文本颜色高亮。
**章节来源**
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp#L179-L602)
- [appdatatdlistview.cpp](file://cpp/Views/appdatatdlistview.cpp#L72-L271)
- [appdatatddetaillistview.cpp](file://cpp/Views/appdatatddetaillistview.cpp#L63-L267)
- [appdatatdgrlistview.cpp](file://cpp/Views/appdatatdgrlistview.cpp#L67-L134)
## 架构概述
整个测量数据浏览功能的架构基于MFC的文档/视图(Document/View)架构和消息映射机制。`CDataMngFrame`通过处理自定义Windows消息(如WM_SCHEDULE、WM_REFRESH)来响应用户操作和数据状态变化。
```mermaid
sequenceDiagram
participant User as 用户
participant Frame as CDataMngFrame
participant Operator as CDataOperator
participant Data as CTestingData
participant View as CAppDataTdListView
User->>Frame : 选择数据项
Frame->>Frame : OnSchedule(WM_SCHEDULE)
Frame->>Operator : ShowAppView()
Operator->>Data : ShowConList()
Data->>View : 填充列表数据
View-->>User : 显示数据列表
User->>View : 双击列表项
View->>Frame : OnDblclk()
Frame->>Frame : OnSkip()
Frame->>Frame : 跳转到对应数据
```
**图表来源**
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp#L87-L96)
- [appdatatdlistview.cpp](file://cpp/Views/appdatatdlistview.cpp#L284-L301)
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp#L539-L579)
- [Ipsp2DTd.cpp](file://cpp/ProblemZone/Ipsp2DTd.cpp#L48-L75)
## 详细组件分析
### 数据管理框架分析
`CDataMngFrame`是整个功能的核心控制器。它在`OnCreateClient`中创建分割窗口,并在`OnSchedule`消息处理函数中根据传入的句柄(handle)动态创建或切换右侧的应用视图。
```mermaid
classDiagram
class CDataMngFrame {
+CView* m_pAppDataView
+CView* m_pNavDataView
+CDataOperator* m_pDataOperator
+OnCreateClient()
+OnSchedule()
+ShowAppView()
+ShowContentListByPageView()
}
class CDataOperator {
+ShowRsp2DTdInfo()
+ShowIps2DpTdInfo()
+LoadRsp2dRecordbyPage()
+LoadIpsp2dRecordbyPage()
}
class CTestingData {
+ShowDetailInfo()
+ShowConList()
+ShowConListByPage()
}
CDataMngFrame --> CDataOperator : "使用"
CDataOperator --> CTestingData : "调用"
```
**图表来源**
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp#L51-L81)
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp#L539-L579)
- [Ipsp2DTd.cpp](file://cpp/ProblemZone/Ipsp2DTd.cpp#L48-L75)
### 对话框组件分析
`CDialListMeasuData``CDialListMeasuGR`是两个独立的对话框,用于实时显示测量过程中的数据。它们不直接与`CDataMngFrame`集成,而是通过自己的数据操作对象(如`m_taskOper`)直接从数据库或设备获取数据。
```mermaid
flowchart TD
Start([对话框初始化]) --> OnInitDialog["OnInitDialog()"]
OnInitDialog --> InsertColumns["插入列表列"]
InsertColumns --> QueryData["查询测量数据"]
QueryData --> vtData{"数据为空?"}
vtData --> |否| OnShowTdData["OnShowTdData()"]
vtData --> |是| End([结束])
OnShowTdData --> DeleteAll["清空列表"]
DeleteAll --> Loop["遍历数据"]
Loop --> FormatText["格式化文本"]
FormatText --> SetItemText["设置列表项"]
SetItemText --> NextItem["下一项"]
NextItem --> Loop
Loop --> End
```
**图表来源**
- [DialListMeasuData.cpp](file://cpp/Views/DialListMeasuData.cpp#L52-L332)
- [DialListMeasuGR.cpp](file://cpp/Views/DialListMeasuGR.cpp#L46-L112)
### 复杂逻辑组件分析
数据句柄(Handle)的解析是系统中的一个关键逻辑。`CHandleProcessor`类负责将一个32位的DWORD句柄拆解为ID和样式(Style)两部分,用于标识不同的数据对象。
```mermaid
flowchart TD
A["dwHandle = 0xF8000001"] --> B["dwTempID = dwHandle & 0x7FFFFFF"]
B --> C["dwID = 1"]
A --> D["dwTempStyle = dwHandle & 0xF8000000"]
D --> E["dwTempStyle >>= 27"]
E --> F["uStyle = 31"]
C --> G["获取数据ID"]
F --> H["获取数据类型"]
```
**图表来源**
- [HandleProcessor.cpp](file://cpp/Tools/HandleProcessor.cpp#L59-L95)
**章节来源**
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp#L250-L312)
- [HandleProcessor.cpp](file://cpp/Tools/HandleProcessor.cpp#L52-L95)
## 依赖关系分析
测量数据浏览功能依赖于多个核心模块。`CDataMngFrame`依赖于`CDataOperator`进行数据操作,`CDataOperator`又依赖于具体的`CTestingData`派生类(如`CIpsp2DTd`)来获取数据。数据持久化则通过ADODB组件与数据库进行交互。
```mermaid
graph LR
DMF[CDataMngFrame] --> DO[CDataOperator]
DO --> TD[CTestingData]
TD --> DB[(数据库)]
DO --> HP[CHandleProcessor]
DO --> SP[CStateProcessor]
TD --> RSP[CIpsp2DTdRecord]
RSP --> DB
```
**图表来源**
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp#L59-L61)
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp#L539-L579)
- [Ipsp2DTd.cpp](file://cpp/ProblemZone/Ipsp2DTd.cpp#L37-L46)
- [Ipsp2DTdRecord.cpp](file://cpp/ProblemZone/Ipsp2DTdRecord.cpp#L56-L87)
## 性能考虑
对于大规模数据集,当前实现可能存在性能瓶颈。建议采用虚拟列表控件(Virtual List Control)来优化`CAppDataTdListView`的性能。虚拟列表控件只在需要时才请求显示数据,而不是一次性加载所有数据到内存中。
异步加载策略也是优化的关键。可以在后台线程中执行数据库查询,避免阻塞UI线程。当查询完成时,再通过`PostMessage`将结果发送回UI线程进行更新,确保界面的响应性。
## 故障排除指南
如果测量数据无法正确显示,首先检查`CDataMngFrame``OnSchedule`消息是否被正确触发。确认传入的句柄(handle)是否有效,并通过`CHandleProcessor`验证其ID和样式是否正确解析。
如果详细信息面板为空,检查`CDataOperator::ShowIps2DpTdInfo`等方法是否成功获取了`CTestingData`对象,并确认`ShowDetailInfo`方法是否被正确调用。
**章节来源**
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp#L249-L312)
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp#L544-L579)
- [Ipsp2DTd.cpp](file://cpp/ProblemZone/Ipsp2DTd.cpp#L48-L75)
## 结论
GeomativeStudio的测量数据浏览功能通过一个清晰的分层架构实现了数据的展示与交互。`CDataMngFrame`作为中心枢纽,协调着列表视图、详情面板和图形化组件的联动。MFC的消息映射机制是实现这一联动的核心。对于开发者而言,扩展功能的关键在于理解句柄解析机制和数据操作流程。未来应考虑引入虚拟列表和异步加载以提升大规模数据下的用户体验。
@@ -0,0 +1,404 @@
# 用户界面指南
<cite>
**本文档引用的文件**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp)
- [MainFrm.h](file://h/MainFrm.h)
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
- [devmngframe.h](file://h/devmngframe.h)
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp)
- [datamngframe.h](file://h/datamngframe.h)
- [sptmngframe.cpp](file://cpp/Views/sptmngframe.cpp)
- [sptmngframe.h](file://h/sptmngframe.h)
- [navdevview.h](file://h/navdevview.h)
- [navdataview.h](file://h/navdataview.h)
- [blankview.cpp](file://cpp/Views/blankview.cpp)
- [blankview.h](file://h/blankview.h)
- [GeoMative.rc2](file://res/GeoMative.rc2)
</cite>
## 目录
1. [简介](#简介)
2. [主框架窗口布局](#主框架窗口布局)
3. [主要功能框架](#主要功能框架)
4. [UI组件职责与交互](#ui组件职责与交互)
5. [界面状态管理与消息处理](#界面状态管理与消息处理)
6. [多窗口协作机制](#多窗口协作机制)
7. [MFC资源文件说明](#mfc资源文件说明)
8. [用户导航指导](#用户导航指导)
9. [开发者扩展方法](#开发者扩展方法)
## 简介
Geomative Studio应用程序采用MFCMicrosoft Foundation Classes)框架构建,实现了多文档界面(MDI)架构。该应用程序主要包含设备管理、数据管理和任务管理三大功能模块,通过主框架窗口(CMainFrame)统一调度和管理各个子窗口。系统采用树形导航视图与内容视图分离的设计模式,左侧为导航树(CNavDevView、CNavDataView等),右侧为内容展示区,通过CSplitterWnd实现窗口分割。应用程序支持中文和英文双语界面切换,并通过消息映射机制处理用户交互和系统事件。
**Section sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L1-L800)
- [MainFrm.h](file://h/MainFrm.h#L1-L120)
## 主框架窗口布局
主框架窗口(CMainFrame)继承自CMDIFrameWnd,作为整个应用程序的容器窗口,负责管理所有子窗口的创建、激活和销毁。其布局结构如下:
```mermaid
graph TD
A[CMainFrame] --> B[工具栏 m_wndToolBar]
A --> C[状态栏 m_wndStatusBar]
A --> D[MDI客户区]
D --> E[CDevMngFrame]
D --> F[CDataMngFrame]
D --> G[CSptMngFrame]
B --> H[图标按钮]
C --> I[状态指示器]
```
**Diagram sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L164-L190)
- [MainFrm.h](file://h/MainFrm.h#L56-L57)
主框架在OnCreate方法中创建了工具栏和状态栏。工具栏包含多个图标按钮,用于快速访问常用功能;状态栏位于窗口底部,显示当前状态信息。MDI客户区用于容纳和管理多个子窗口,如设备管理框架、数据管理框架和任务管理框架。通过消息映射,主框架响应菜单命令和系统消息,实现窗口的创建和调度。
**Section sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L164-L223)
- [MainFrm.h](file://h/MainFrm.h#L56-L57)
## 主要功能框架
应用程序包含三个主要功能框架:设备管理框架(CDevMngFrame)、数据管理框架(CDataMngFrame)和任务管理框架(CSptMngFrame),均继承自CMDIChildWnd。
### 设备管理框架
设备管理框架(CDevMngFrame)负责设备的注册、参数配置和状态监控。其布局采用CSplitterWnd分割为左右两部分:
```mermaid
graph TD
A[CDevMngFrame] --> B[左侧: CNavDevView]
A --> C[右侧: m_pAppDevView]
C --> D[CAppDevView]
C --> E[CAppDevOLView]
C --> F[CBlankView]
B --> G[设备树 m_devTree]
D --> H[设备详细信息列表]
D --> I[设备内容列表]
E --> J[在线设备详细信息]
E --> K[在线设备GR列表]
```
**Diagram sources**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L136-L146)
- [devmngframe.h](file://h/devmngframe.h#L84)
左侧的CNavDevView包含一个CTreeCtrl控件(m_devTree),用于显示设备树形结构。右侧的内容视图根据设备状态动态切换:当设备处于离线状态时显示CAppDevView;在线状态时显示CAppDevOLView;无选中设备时显示CBlankView。框架通过ShowAppView方法实现视图的动态切换。
**Section sources**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L258-L327)
- [devmngframe.h](file://h/devmngframe.h#L81-L82)
### 数据管理框架
数据管理框架(CDataMngFrame)负责项目、测区和测量数据的管理。其布局结构与设备管理框架类似:
```mermaid
graph TD
A[CDataMngFrame] --> B[左侧: CNavDataView]
A --> C[右侧: m_pAppDataView]
C --> D[CAppDataProView]
C --> E[CAppDataTzView]
C --> F[CAppDataRsp2DTdView]
C --> G[CAppDataIpsp2DTdView]
C --> H[CAppDataSP2DTdView]
C --> I[CAppDataRspCETdView]
C --> J[CAppDataIpspCETdView]
C --> K[CAppDataSPCETdView]
C --> L[CAppDataRsp3DTdView]
C --> M[CAppDataIpsp3DTdView]
C --> N[CAppDataSP3DTdView]
C --> O[CBlankView]
B --> P[数据树 m_dataTree]
```
**Diagram sources**
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp#L183-L193)
- [datamngframe.h](file://h/datamngframe.h#L143)
右侧内容视图根据选中节点的类型动态切换,支持项目、测区以及多种类型的测量数据(2D、3D、CE等)的展示。框架通过ShowAppView方法根据数据类型创建相应的视图。
**Section sources**
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp#L604-L800)
- [datamngframe.h](file://h/datamngframe.h#L141)
### 任务管理框架
任务管理框架(CSptMngFrame)负责测量任务的创建和管理。其结构与前述框架类似,包含导航视图和内容视图:
```mermaid
graph TD
A[CSptMngFrame] --> B[左侧: CNavSptView]
A --> C[右侧: m_pAppSptView]
C --> D[CAppSptView]
C --> E[CAppSptOLView]
C --> F[CBlankView]
```
**Diagram sources**
- [sptmngframe.h](file://h/sptmngframe.h#L78)
该框架支持创建标准和非标准的测量脚本,并提供脚本浏览和管理功能。
**Section sources**
- [sptmngframe.cpp](file://cpp/Views/sptmngframe.cpp#L17-L36)
- [sptmngframe.h](file://h/sptmngframe.h#L78)
## UI组件职责与交互
应用程序的UI组件遵循MVCModel-View-Controller)设计模式,各组件职责明确。
### 导航视图组件
导航视图(CNavDevView、CNavDataView)负责显示树形结构数据,继承自CFormView。其主要职责包括:
```mermaid
classDiagram
class CNavDevView {
+CTreeCtrl m_devTree
+OnInitialUpdate()
+DoDataExchange()
+OnRclickNavDevTree()
+OnSelchangedNavDevTree()
+OnSelchangingNavDevTree()
}
class CNavDataView {
+CTreeCtrl m_dataTree
+OnInitialUpdate()
+DoDataExchange()
+OnRclickNavDataTree()
+OnSelchangedNavDataTree()
+OnSelchangingNavDataTree()
}
CNavDevView <|-- CFormView
CNavDataView <|-- CFormView
```
**Diagram sources**
- [navdevview.h](file://h/navdevview.h#L17-L70)
- [navdataview.h](file://h/navdataview.h#L19-L74)
这些视图通过OnInitialUpdate方法初始化树形控件,通过消息映射处理右键点击、选择改变等用户交互事件,并向父框架发送调度消息。
### 内容视图组件
内容视图(CAppDevView、CAppDataProView等)负责显示具体数据内容,继承自CView。其主要职责包括:
```mermaid
classDiagram
class CAppDevView {
+CView* m_pDevDetailListView
+CView* m_pDevContentListView
+OnDraw()
+OnSize()
}
class CAppDataProView {
+CView* m_pProDetailListView
+CView* m_pProContentListView
+OnDraw()
+OnSize()
}
CAppDevView <|-- CView
CAppDataProView <|-- CView
```
**Diagram sources**
- [appdevview.h](file://h/appdevview.h#L13-L60)
- [appdatadevview.h](file://h/appdatadevview.h#L16-L64)
这些视图通常包含一个CSplitterWnd,用于进一步分割窗口,显示详细信息列表和内容列表。
### 空白视图组件
CBlankView是一个占位视图,用于在没有选中任何项目时显示空白区域:
```mermaid
classDiagram
class CBlankView {
+CBlankView()
+~CBlankView()
+DoDataExchange()
+AssertValid()
+Dump()
}
CBlankView <|-- CFormView
```
**Diagram sources**
- [blankview.cpp](file://cpp/Views/blankview.cpp#L1-L63)
- [blankview.h](file://h/blankview.h#L17-L63)
**Section sources**
- [blankview.cpp](file://cpp/Views/blankview.cpp#L1-L63)
- [blankview.h](file://h/blankview.h#L17-L63)
## 界面状态管理与消息处理
应用程序通过消息映射和状态管理机制实现复杂的用户交互。
### 消息处理机制
主框架和各子框架通过MFC的消息映射机制处理各种消息:
```mermaid
sequenceDiagram
participant User as 用户
participant MainFrame as CMainFrame
participant DevFrame as CDevMngFrame
participant DataFrame as CDataMngFrame
User->>MainFrame : 点击"设备管理"菜单
MainFrame->>MainFrame : OnMngDevWin()
MainFrame->>DevFrame : CreateNewChild()
DevFrame->>DevFrame : OnCreateClient()
DevFrame->>DevFrame : 创建分割窗口和视图
User->>DevFrame : 在设备树中选择设备
DevFrame->>DevFrame : OnSelchangedNavDevTree()
DevFrame->>DevFrame : OnSchedule()
DevFrame->>DevFrame : ShowAppView()
DevFrame->>MainFrame : 发送状态更新消息
```
**Diagram sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L624-L668)
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L212-L240)
### 状态管理
应用程序定义了多种状态常量来管理界面状态:
```mermaid
stateDiagram-v2
[*] --> PZ_STATE_NEW
[*] --> PZ_STATE_ONLINE
[*] --> PZ_STATE_OFFLINE
[*] --> PZ_STATE_ZERO
PZ_STATE_NEW --> PZ_STATE_ONLINE : 注册成功
PZ_STATE_NEW --> PZ_STATE_OFFLINE : 注册失败
PZ_STATE_ONLINE --> PZ_STATE_OFFLINE : 设备断开
PZ_STATE_OFFLINE --> PZ_STATE_ONLINE : 设备重连
PZ_STATE_OFFLINE --> PZ_STATE_NEW : 重新注册
```
**Diagram sources**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L258-L327)
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp#L604-L800)
**Section sources**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L258-L327)
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp#L604-L800)
## 多窗口协作机制
应用程序通过父-子窗口协作机制实现多窗口间的通信和数据共享。
### 窗口创建与激活
主框架通过CreateNewChild方法创建子窗口:
```mermaid
flowchart TD
Start([开始]) --> CheckNull["检查 m_pDevMngFrm 是否为空"]
CheckNull --> |为空| CreateChild["创建 CDevMngFrame 子窗口"]
CheckNull --> |不为空| ActivateFrame["激活现有窗口"]
CreateChild --> ShowWindow["显示窗口最大化"]
ActivateFrame --> End([结束])
ShowWindow --> End
```
**Diagram sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L624-L635)
### 消息传递
子窗口通过SendMessage向主框架发送消息,实现状态同步:
```mermaid
sequenceDiagram
participant DevFrame as CDevMngFrame
participant MainFrame as CMainFrame
DevFrame->>DevFrame : OnMDIActivate(TRUE)
DevFrame->>MainFrame : SendMessage(WM_SCHEDULE)
MainFrame->>MainFrame : 更新工具栏和菜单状态
DevFrame->>MainFrame : SendMessage(WM_REFRESH_NAV_DEVICE)
MainFrame->>DevFrame : 刷新设备树
```
**Diagram sources**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L151-L195)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L64-L94)
**Section sources**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L151-L195)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L64-L94)
## MFC资源文件说明
MFC资源文件定义了应用程序的界面元素。
### 资源文件结构
GeoMative.rc2文件是MFC资源文件,包含手动编辑的资源:
```mermaid
erDiagram
RESOURCE_FILE {
string name "GeoMative.rc2"
string type "MFC Resource File"
string description "手动编辑的资源文件"
}
DIALOG_TEMPLATE {
int id "IDD_NAV_DEV"
string title "设备导航"
string type "CFormView"
}
DIALOG_TEMPLATE {
int id "IDD_NAV_DATA"
string title "数据导航"
string type "CFormView"
}
DIALOG_TEMPLATE {
int id "IDD_BLANK"
string title "空白视图"
string type "CFormView"
}
RESOURCE_FILE ||--o{ DIALOG_TEMPLATE : "包含"
```
**Diagram sources**
- [GeoMative.rc2](file://res/GeoMative.rc2#L1-L14)
**Section sources**
- [GeoMative.rc2](file://res/GeoMative.rc2#L1-L14)
这些对话框模板在相应的视图类中通过AFX_DATA宏引用,如CNavDevView中的IDD = IDD_NAV_DEV。
## 用户导航指导
用户可以通过以下步骤进行界面导航:
1. **启动应用程序**:程序启动时显示启动画面,自动检测连接的设备。
2. **访问功能模块**
- 点击菜单"设备管理"打开设备管理窗口
- 点击菜单"数据管理"打开数据管理窗口
- 点击菜单"任务管理"打开任务管理窗口
3. **设备管理**
- 在左侧设备树中选择设备
- 右侧显示设备详细信息
- 通过右键菜单进行设备注册、参数修改等操作
4. **数据管理**
- 在左侧数据树中选择项目或测区
- 右侧显示相应的测量数据列表
- 可以进行数据导出、删除等操作
5. **任务管理**
- 创建新的测量任务
- 配置任务参数
- 生成测量脚本
## 开发者扩展方法
开发者可以通过以下方式扩展应用程序功能:
### 添加新的功能框架
1. 创建新的MDI子窗口类,继承自CMDIChildWnd
2. 实现OnCreateClient方法,创建分割窗口和视图
3. 在主框架中添加菜单命令和消息处理函数
4. 实现窗口创建和激活逻辑
### 扩展现有视图
1. 在现有视图类中添加新的控件成员变量
2. 在对话框资源中添加相应的控件
3. 在DoDataExchange方法中添加DDX/DDV绑定
4. 添加消息处理函数处理用户交互
### 添加新的消息类型
1. 定义新的WM_USER消息常量
2. 在消息映射中添加新的消息处理条目
3. 实现消息处理函数
4. 在需要的地方发送消息
通过遵循MFC框架的设计模式和应用程序的现有架构,开发者可以有效地扩展和维护Geomative Studio应用程序的用户界面功能。
@@ -0,0 +1,324 @@
# 设备参数管理
<cite>
**本文档引用的文件**
- [DialShowDevParam.cpp](file://cpp/Views/DialShowDevParam.cpp)
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp)
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h)
- [DialShowDevParam.h](file://h/DialShowDevParam.h)
- [DevOperator.h](file://h/DevOperator.h)
- [devmngframe.h](file://h/devmngframe.h)
- [DevManager.h](file://h/DevManager.h)
</cite>
## 目录
1. [简介](#简介)
2. [核心功能概述](#核心功能概述)
3. [UI结构与数据绑定](#ui结构与数据绑定)
4. [消息处理链分析](#消息处理链分析)
5. [参数读取、修改与持久化机制](#参数读取修改与持久化机制)
6. [用户操作指南](#用户操作指南)
7. [开发者扩展指南](#开发者扩展指南)
8. [安全访问与异常处理](#安全访问与异常处理)
9. [结论](#结论)
## 简介
设备参数管理功能是Geomative Studio系统中的核心模块之一,负责设备基本信息查看、运行参数配置和固件升级流程。该功能通过DialShowDevParam对话框提供用户界面,结合CDevMngFrame的消息处理机制和DevOperator类的操作接口,实现了对设备参数的全面管理。系统支持参数查询、配置修改、设备注册/注销等操作,并提供了安全访问控制和异常处理策略。
## 核心功能概述
设备参数管理模块主要包含以下功能:
- 设备基本信息查看:显示设备序列号、硬件/软件版本、温度、电池电压等信息
- 运行参数配置:配置电源频率、电缆类型、接地电阻阈值、迭代次数等运行参数
- 固件升级流程:支持设备固件的在线升级
- 参数持久化:将修改后的参数保存到设备和云端
- 安全验证:在关键操作前进行用户确认和参数合法性验证
该模块通过STSynDevParam数据结构统一管理设备参数,确保了数据的一致性和完整性。
**Section sources**
- [DialShowDevParam.cpp](file://cpp/Views/DialShowDevParam.cpp#L1-L500)
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L1-L800)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp#L1-L800)
## UI结构与数据绑定
### DialShowDevParam对话框UI结构
DialShowDevParam对话框采用标准的MFC对话框设计,包含以下主要控件:
```mermaid
flowchart TD
A["DialShowDevParam对话框"] --> B["基本信息显示区"]
A --> C["可配置参数区"]
A --> D["操作按钮区"]
B --> B1["设备SN: 编辑框"]
B --> B2["硬件版本: 编辑框"]
B --> B3["软件版本: 编辑框"]
B --> B4["温度: 编辑框"]
B --> B5["电池电压: 编辑框"]
C --> C1["电源频率: 下拉框"]
C --> C2["电缆类型: 下拉框"]
C --> C3["接地电阻阈值: 编辑框"]
C --> C4["电量报警: 下拉框"]
C --> C5["迭代次数: 编辑框"]
C --> C6["最大下发点数: 编辑框"]
D --> D1["配置设备参数按钮"]
D --> D2["检查服务器信息按钮"]
D --> D3["关闭按钮"]
```
**Diagram sources**
- [DialShowDevParam.cpp](file://cpp/Views/DialShowDevParam.cpp#L52-L251)
- [DialShowDevParam.h](file://h/DialShowDevParam.h#L1-L50)
### 数据绑定机制
DialShowDevParam类通过以下机制实现UI与数据的绑定:
1. **初始化绑定**:在OnInitDialog方法中,将STSynDevParam结构体中的数据绑定到相应的UI控件
2. **双向同步**:支持从UI读取数据到结构体,以及从结构体更新UI显示
3. **状态管理**:通过m_iOperStatus变量管理编辑状态,区分查看模式和编辑模式
数据绑定的关键代码路径:
- 初始化数据绑定:`DialShowDevParam::OnInitDialog()`
- 控件数据映射:`DDX_Control`宏定义
- 状态切换逻辑:`OnButtonCfgDevParam()`方法
**Section sources**
- [DialShowDevParam.cpp](file://cpp/Views/DialShowDevParam.cpp#L52-L251)
- [DialShowDevParam.h](file://h/DialShowDevParam.h#L49)
## 消息处理链分析
### CDevMngFrame::OnModifyDeviceParameter消息处理链
CDevMngFrame类的OnModifyDeviceParameter方法是设备参数修改的入口点,其处理链如下:
```mermaid
sequenceDiagram
participant 用户 as 用户
participant CDevMngFrame as CDevMngFrame
participant DevOperator as CDevOperator
participant Device as CDevice
participant DialShowDevParam as CDialShowDevParam
用户->>CDevMngFrame : 点击"修改设备参数"
CDevMngFrame->>DevOperator : ModifyDeviceParameter()
DevOperator->>Device : GetDeviceByID()
Device->>Device : ModifyParameter()
Device->>DialShowDevParam : 创建对话框实例
DialShowDevParam->>DialShowDevParam : SetDevParam()
DialShowDevParam->>用户 : 显示参数配置对话框
用户->>DialShowDevParam : 修改参数并确认
DialShowDevParam->>CDevMngFrame : DoModal()返回IDOK
CDevMngFrame->>网络 : 发送参数修改请求
CDevMngFrame->>云端 : 上传设备信息
```
**Diagram sources**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L533-L537)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp#L435-L461)
- [DialShowDevParam.cpp](file://cpp/Views/DialShowDevParam.cpp#L268-L403)
### 消息处理流程详解
1. **用户触发**:用户在设备管理界面点击"修改设备参数"菜单项
2. **框架处理**CDevMngFrame接收到IDM_OP_DE_REG_O_MP命令消息
3. **操作委托**:调用DevOperator的ModifyDeviceParameter方法
4. **设备获取**:通过设备句柄获取对应的CDevice实例
5. **参数修改**:调用设备实例的ModifyParameter方法
6. **对话框显示**:创建并显示DialShowDevParam对话框
7. **结果处理**:根据用户操作结果决定是否发送参数修改请求
**Section sources**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L92-L93)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp#L435-L461)
## 参数读取修改与持久化机制
### 参数数据结构
设备参数通过STSynDevParam结构体进行管理,主要包含以下字段:
| 字段名 | 类型 | 描述 | 范围 |
|-------|------|------|------|
| uiMachineID | UINT32 | 设备机器ID | 无限制 |
| ucHWVer[2] | BYTE | 硬件版本 | 0-99 |
| ucSWVer[4] | BYTE | 软件版本 | 0-99 |
| fTemperature | float | 温度 | 0.0-150.0℃ |
| fBatteryVol | float | 电池电压 | 0.0-10.0V |
| ucPowerFreq | BYTE | 电源频率 | 0(50Hz), 1(60Hz) |
| ucCableType | BYTE | 电缆类型 | 0-2 |
| iGrThreshold | int | 接地电阻阈值 | 0-30000Ω |
| ucBatteryAlarm | BYTE | 电量报警 | 0(关闭), 1(开启) |
| ucStacking | BYTE | 迭代次数 | 0-255 |
| ucChannelNum | BYTE | 通道数 | 无限制 |
| ucDownLoadNum | BYTE | 最大下发点数 | 通道数-20 |
**Diagram sources**
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L78)
- [DialShowDevParam.h](file://h/DialShowDevParam.h#L49)
### 参数读取流程
参数读取主要通过以下步骤实现:
```mermaid
flowchart TD
A[开始] --> B[选择目标设备]
B --> C[发送同步请求 EN_CTRL_SYN_DEV_PARAM]
C --> D{网络请求成功?}
D --> |是| E[接收STSynDevParam数据]
D --> |否| F[显示错误信息]
E --> G[字节序转换]
G --> H[温度/电压范围验证]
H --> I[创建DialShowDevParam实例]
I --> J[调用SetDevParam方法]
J --> K[显示参数对话框]
K --> L[结束]
F --> L
```
**Diagram sources**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L670-L723)
- [DialShowDevParam.cpp](file://cpp/Views/DialShowDevParam.cpp#L442-L495)
### 参数修改与持久化
参数修改和持久化过程包含客户端验证、设备更新和云端同步三个阶段:
```mermaid
flowchart TD
A[用户修改参数] --> B[客户端验证]
B --> C{验证通过?}
C --> |否| D[显示错误提示]
C --> |是| E[准备STModifyDevParam结构]
E --> F[发送EN_CTRL_SET_DEV_PARAM命令]
F --> G{设备响应成功?}
G --> |否| H[显示设置失败]
G --> |是| I[更新本地缓存]
I --> J[上传到云端]
J --> K[更新UI显示]
K --> L[完成]
D --> L
H --> L
```
**Diagram sources**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L421-L532)
- [DialShowDevParam.cpp](file://cpp/Views/DialShowDevParam.cpp#L268-L403)
**Section sources**
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L78-L89)
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L421-L532)
## 用户操作指南
### 参数查询操作
1. 在设备管理界面选择目标设备
2. 右键点击设备或通过菜单选择"查看设备参数"
3. 系统自动从设备读取参数并显示在对话框中
4. 查看设备基本信息和运行参数
### 配置修改操作
1. 在设备管理界面选择目标设备
2. 点击"修改设备参数"菜单项
3. 在弹出的对话框中修改所需参数
4. 点击"下发"按钮提交修改
5. 系统会提示确认操作,确认后参数将被发送到设备
### 设备注册/注销操作
**设备注册流程:**
1. 点击"注册新设备"菜单项
2. 系统自动检测并注册新设备
3. 注册完成后设备将出现在设备列表中
**设备注销流程:**
1. 选择要注销的设备
2. 点击"注销设备"菜单项
3. 确认注销操作
4. 设备将从系统中移除
**Section sources**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L533-L561)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp#L435-L482)
## 开发者扩展指南
### 添加新的参数配置项
要添加新的参数配置项,需要执行以下步骤:
1. **扩展数据结构**:在STSynDevParam结构体中添加新字段
2. **更新UI界面**:在DialShowDevParam对话框中添加相应的控件
3. **实现数据绑定**:在OnInitDialog和OnButtonCfgDevParam方法中添加数据绑定逻辑
4. **更新协议**:确保新参数在网络传输中正确序列化和反序列化
示例代码路径:
- 数据结构定义:`CtrlProtocolDef.h`
- UI控件定义:`DialShowDevParam.h`
- 数据绑定实现:`DialShowDevParam.cpp`
### 扩展设备参数模型
扩展STSynDevParam模型的步骤:
1. 在`CtrlProtocolDef.h`中修改STSynDevParam结构体
2. 更新所有使用该结构体的类和方法
3. 确保字节序转换函数支持新字段
4. 更新网络协议版本号以确保兼容性
### 参数变更验证与回调机制
系统提供了多层次的参数验证机制:
```mermaid
classDiagram
class ParameterValidator {
+ValidatePowerFreq(BYTE freq) bool
+ValidateCableType(BYTE type) bool
+ValidateGrThreshold(int threshold) bool
+ValidateStacking(BYTE stacking) bool
+ValidateDownLoadNum(BYTE num, BYTE channelNum) bool
}
class ParameterCallback {
+OnBeforeModify(STSynDevParam* param) bool
+OnAfterModify(STSynDevParam* param) void
+OnModifyFailed(STSynDevParam* param, int errorCode) void
}
ParameterValidator <|-- DeviceParameterValidator
ParameterCallback <|-- DeviceParameterCallback
DeviceParameterValidator --> DeviceParameterCallback : "uses"
```
**Diagram sources**
- [DialShowDevParam.cpp](file://cpp/Views/DialShowDevParam.cpp#L296-L379)
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L433-L444)
**Section sources**
- [DialShowDevParam.cpp](file://cpp/Views/DialShowDevParam.cpp#L296-L379)
## 安全访问与异常处理
### 安全访问策略
系统通过以下机制确保设备参数操作的安全性:
1. **操作确认**:在关键操作前要求用户确认
2. **参数验证**:对所有输入参数进行范围和合法性验证
3. **状态检查**:确保设备处于可操作状态
4. **权限控制**:某些操作需要管理员权限
### 异常处理机制
系统实现了完善的异常处理策略:
```mermaid
flowchart TD
A[异常发生] --> B{异常类型}
B --> C[网络异常]
B --> D[参数验证异常]
B --> E[设备响应异常]
B --> F[其他异常]
C --> G[显示连接中断提示]
D --> H[显示具体参数错误]
E --> I[显示设备响应错误]
F --> J[记录日志并提示]
G --> K[结束]
H --> K
I --> K
J --> K
```
**Diagram sources**
- [DialShowDevParam.cpp](file://cpp/Views/DialShowDevParam.cpp#L296-L379)
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L442-L495)
**Section sources**
- [DialShowDevParam.cpp](file://cpp/Views/DialShowDevParam.cpp#L296-L379)
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L442-L495)
## 结论
设备参数管理功能通过DialShowDevParam对话框、CDevMngFrame消息处理链和DevOperator操作类的协同工作,实现了对设备参数的全面管理。系统提供了友好的用户界面、可靠的数据持久化机制和安全的访问控制策略。开发者可以通过扩展STSynDevParam数据结构和相应的验证回调机制来添加新的参数配置项,满足不断变化的业务需求。
@@ -0,0 +1,212 @@
# 设备状态监控
<cite>
**本文档引用的文件**
- [appdevolview.cpp](file://cpp/Views/appdevolview.cpp)
- [appdevolview.h](file://h/appdevolview.h)
- [appdevoldetaillistview.h](file://h/appdevoldetaillistview.h)
- [appdevolgrlistview.h](file://h/appdevolgrlistview.h)
- [appdevolacview.h](file://h/appdevolacview.h)
- [DialPlcStatusShow.cpp](file://cpp/Views/DialPlcStatusShow.cpp)
- [DialPlcStatusSetting.cpp](file://cpp/Views/DialPlcStatusSetting.cpp)
- [OperPLC.cpp](file://cpp/Tools/OperPLC.cpp)
- [StateProcessor.cpp](file://cpp/Tools/StateProcessor.cpp)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构概述](#架构概述)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
## 简介
本文档全面记录了GeomativeStudio中的设备实时状态监控系统,重点涵盖PLC状态查询、定时任务监控和运行日志显示功能。系统通过UI消息机制触发状态轮询,并在appdevolview中实现状态视图的数据刷新。文档详细描述了关键状态字段如m_bDevState、m_iPlcTimerInterval的含义与更新逻辑,为用户提供操作指南,为开发者提供扩展接口说明。
## 项目结构
设备状态监控功能主要分布在cpp/Views和h目录下,以appdevolview为核心视图容器,包含多个子视图组件。系统通过分层架构实现状态监控,包括UI层、业务逻辑层和设备通信层。
```mermaid
graph TB
subgraph "UI层"
appdevolview["appdevolview (主容器)"]
appdevoldetaillistview["appdevoldetaillistview (详情列表)"]
appdevolgrlistview["appdevolgrlistview (图形列表)"]
appdevolacview["appdevolacview (活动状态)"]
end
subgraph "业务逻辑层"
DevManager["DevManager (设备管理)"]
StateProcessor["StateProcessor (状态处理)"]
end
subgraph "设备通信层"
OperPLC["OperPLC (PLC操作)"]
SComPort["SComPort (串口通信)"]
end
appdevolview --> appdevoldetaillistview
appdevolview --> appdevolgrlistview
appdevolview --> appdevolacview
appdevolview --> DevManager
DevManager --> StateProcessor
DevManager --> OperPLC
OperPLC --> SComPort
```
**图示来源**
- [appdevolview.cpp](file://cpp/Views/appdevolview.cpp#L1-L120)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L1-L50)
**本节来源**
- [appdevolview.cpp](file://cpp/Views/appdevolview.cpp#L1-L120)
- [h](file://h#L1-L10)
## 核心组件
设备状态监控系统的核心组件包括主视图容器CAppDevOLView及其三个子视图:设备详情列表视图、图形列表视图和活动状态视图。这些组件通过CSplitterWnd实现分屏布局,提供一体化的状态监控界面。
**本节来源**
- [appdevolview.cpp](file://cpp/Views/appdevolview.cpp#L18-L120)
- [appdevolview.h](file://h/appdevolview.h#L13-L54)
## 架构概述
系统采用MVC架构模式,CAppDevOLView作为视图控制器,管理三个子视图的布局和显示。状态数据通过DevManager从底层设备获取,经由StateProcessor处理后更新到UI组件。
```mermaid
sequenceDiagram
participant UI as "UI界面"
participant View as "CAppDevOLView"
participant Manager as "DevManager"
participant PLC as "OperPLC"
participant Device as "PLC设备"
UI->>View : OnRemQueryPlcStatus消息
View->>Manager : 请求PLC状态
Manager->>PLC : 执行查询命令
PLC->>Device : 发送查询指令
Device-->>PLC : 返回状态数据
PLC-->>Manager : 解析状态数据
Manager-->>View : 返回设备状态
View->>View : 更新m_bDevState等状态字段
View->>UI : 刷新视图显示
```
**图示来源**
- [appdevolview.cpp](file://cpp/Views/appdevolview.cpp#L68-L105)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L15-L80)
## 详细组件分析
### 主视图容器分析
CAppDevOLView是设备在线状态监控的主视图容器,负责创建和管理三个子视图的分屏布局。通过CSplitterWnd实现灵活的窗口分割,提供最佳的用户体验。
```mermaid
classDiagram
class CAppDevOLView {
+CView* m_pDevOLDetailListView
+CView* m_pDevOLGRListView
+CView* m_pDevOLACListView
-CSplitterWnd m_firstSplitter
-CSplitterWnd m_secondSplitter
+Create() bool
+OnSize() void
+OnDraw() void
}
class CAppDevOLDetailListView {
+int m_iRowCount
-CListCtrl* m_pDetailList
+OnInitialUpdate() void
+OnDraw() void
}
class CAppDevOLGRListView {
+OnInitialUpdate() void
+OnRButtonDown() void
+OnOpDevRefreshGR() void
}
class CAppDevOLACView {
+OnInitialUpdate() void
+OnDraw() void
}
CAppDevOLView --> CAppDevOLDetailListView : "包含"
CAppDevOLView --> CAppDevOLGRListView : "包含"
CAppDevOLView --> CAppDevOLACView : "包含"
```
**图示来源**
- [appdevolview.h](file://h/appdevolview.h#L13-L54)
- [appdevoldetaillistview.h](file://h/appdevoldetaillistview.h#L13-L53)
- [appdevolgrlistview.h](file://h/appdevolgrlistview.h#L13-L52)
- [appdevolacview.h](file://h/appdevolacview.h#L13-L51)
**本节来源**
- [appdevolview.cpp](file://cpp/Views/appdevolview.cpp#L18-L120)
- [appdevolview.h](file://h/appdevolview.h#L13-L54)
### 状态轮询机制分析
系统通过UI消息OnRemQueryPlcStatus和OnRemGD10TimerTdRun触发状态轮询。当用户请求或定时器触发时,系统调用PLC状态查询接口,实现设备状态的实时监控。
```mermaid
flowchart TD
Start([用户操作或定时器]) --> CheckMessage{"消息类型?"}
CheckMessage --> |OnRemQueryPlcStatus| QueryPLC["调用PLC状态查询"]
CheckMessage --> |OnRemGD10TimerTdRun| CheckInterval["检查m_iPlcTimerInterval"]
CheckInterval --> Valid{"间隔有效?"}
Valid --> |是| QueryPLC
Valid --> |否| End
QueryPLC --> SendCommand["发送PLC查询指令"]
SendCommand --> ReceiveData["接收PLC响应数据"]
ReceiveData --> ParseData["解析状态数据"]
ParseData --> UpdateState["更新m_bDevState等字段"]
UpdateState --> RefreshView["刷新appdevolview显示"]
RefreshView --> End([完成])
```
**图示来源**
- [DialPlcStatusShow.cpp](file://cpp/Views/DialPlcStatusShow.cpp#L1-L50)
- [OperPLC.cpp](file://cpp/Tools/OperPLC.cpp#L15-L100)
**本节来源**
- [DialPlcStatusShow.cpp](file://cpp/Views/DialPlcStatusShow.cpp#L1-L50)
- [OperPLC.cpp](file://cpp/Tools/OperPLC.cpp#L15-L100)
## 依赖分析
设备状态监控系统依赖于多个核心组件和工具类,形成完整的监控链条。系统通过清晰的依赖关系确保各组件职责分明,便于维护和扩展。
```mermaid
graph TD
appdevolview --> DevManager
DevManager --> StateProcessor
DevManager --> OperPLC
OperPLC --> SComPort
DevManager --> TdManager
appdevolview --> DialPlcStatusShow
DialPlcStatusShow --> DialPlcStatusSetting
StateProcessor --> FileOperTools
DevManager --> IOManager
style appdevolview fill:#f9f,stroke:#333
style DevManager fill:#bbf,stroke:#333
style OperPLC fill:#f96,stroke:#333
```
**图示来源**
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L1-L30)
- [OperPLC.cpp](file://cpp/Tools/OperPLC.cpp#L1-L20)
- [StateProcessor.cpp](file://cpp/Tools/StateProcessor.cpp#L1-L15)
**本节来源**
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp#L1-L50)
- [OperPLC.cpp](file://cpp/Tools/OperPLC.cpp#L1-L30)
## 性能考虑
系统在设计时充分考虑了性能因素,通过合理的更新频率控制和数据缓存机制,确保监控系统的高效运行。m_iPlcTimerInterval字段控制PLC状态查询的间隔,避免频繁查询导致的性能问题。
## 故障排除指南
当设备状态显示异常时,应首先检查串口通信是否正常,然后验证PLC设备是否在线。可通过DialPlcStatusShow对话框手动触发状态查询,诊断通信问题。日志文件位于Install/Geomative Studio/LOG目录下,可用于分析历史问题。
**本节来源**
- [DialPlcStatusShow.cpp](file://cpp/Views/DialPlcStatusShow.cpp#L10-L50)
- [OperPLC.cpp](file://cpp/Tools/OperPLC.cpp#L45-L80)
## 结论
GeomativeStudio的设备状态监控系统通过分层架构和模块化设计,实现了PLC状态查询、定时任务监控和运行日志显示等核心功能。系统具有良好的可扩展性,开发者可以基于现有框架添加新的监控指标和告警规则,满足不断变化的监控需求。
@@ -0,0 +1,291 @@
# 设备管理界面
<cite>
**本文档引用的文件**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
- [devmngframe.h](file://h/devmngframe.h)
- [appdevview.cpp](file://cpp/Views/appdevview.cpp)
- [appdevview.h](file://h/appdevview.h)
- [appdevolview.cpp](file://cpp/Views/appdevolview.cpp)
- [appdevolview.h](file://h/appdevolview.h)
- [navdevview.cpp](file://cpp/Views/navdevview.cpp)
- [navdevview.h](file://h/navdevview.h)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp)
- [DevOperator.h](file://h/DevOperator.h)
- [appdevdetaillistview.cpp](file://cpp/Views/appdevdetaillistview.cpp)
- [appdevoldetaillistview.cpp](file://cpp/Views/appdevoldetaillistview.cpp)
- [appdevolgrlistview.cpp](file://cpp/ProblemZone/appdevolgrlistview.cpp)
- [appdevolacview.cpp](file://cpp/Views/appdevolacview.cpp)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构概述](#架构概述)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
## 简介
设备管理界面是Geomative Studio软件中的一个核心功能模块,负责设备的连接状态监控、串口配置、PLC状态查询与参数显示。该界面通过`devmngframe`框架与多个视图(如`appdevview``appdevolview`)协同工作,为用户提供设备列表、详细信息面板和实时状态窗口。用户可以通过该界面执行设备发现、参数查看与状态诊断等操作。对于开发者而言,该框架提供了扩展设备信息展示、添加新的诊断功能或集成新型硬件协议的接口。
## 项目结构
设备管理界面的相关文件主要分布在`cpp/Views``h`目录下。`devmngframe.cpp``devmngframe.h`定义了设备管理框架的核心逻辑,而`appdevview.cpp``appdevolview.cpp`等文件则实现了具体的应用视图。`DevOperator.cpp``DevOperator.h`提供了设备操作的业务逻辑,包括设备注册、参数修改和状态查询等功能。
```mermaid
graph TB
subgraph "视图层"
devmngframe["devmngframe (设备管理框架)"]
appdevview["appdevview (应用设备视图)"]
appdevolview["appdevolview (在线设备视图)"]
navdevview["navdevview (导航设备视图)"]
end
subgraph "业务逻辑层"
DevOperator["DevOperator (设备操作器)"]
end
subgraph "数据模型"
Device["Device (设备类)"]
end
devmngframe --> appdevview
devmngframe --> appdevolview
devmngframe --> navdevview
devmngframe --> DevOperator
DevOperator --> Device
```
**图表来源**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L1-L1806)
- [appdevview.cpp](file://cpp/Views/appdevview.cpp#L1-L102)
- [appdevolview.cpp](file://cpp/Views/appdevolview.cpp#L1-L120)
- [navdevview.cpp](file://cpp/Views/navdevview.cpp#L1-L180)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp#L1-L1604)
**章节来源**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L1-L1806)
- [appdevview.cpp](file://cpp/Views/appdevview.cpp#L1-L102)
- [appdevolview.cpp](file://cpp/Views/appdevolview.cpp#L1-L120)
- [navdevview.cpp](file://cpp/Views/navdevview.cpp#L1-L180)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp#L1-L1604)
## 核心组件
设备管理界面的核心组件包括`CDevMngFrame``CAppDevView``CAppDevOLView``CNavDevView``CDevMngFrame`是设备管理框架的主窗口,负责协调各个视图的显示和交互。`CAppDevView``CAppDevOLView`分别用于显示离线和在线设备的详细信息,而`CNavDevView`则提供设备的导航树视图。`CDevOperator`类封装了设备操作的业务逻辑,如设备注册、参数修改和状态查询。
**章节来源**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L1-L1806)
- [appdevview.cpp](file://cpp/Views/appdevview.cpp#L1-L102)
- [appdevolview.cpp](file://cpp/Views/appdevolview.cpp#L1-L120)
- [navdevview.cpp](file://cpp/Views/navdevview.cpp#L1-L180)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp#L1-L1604)
## 架构概述
设备管理界面采用MVCModel-View-Controller)架构模式。`CDevMngFrame`作为控制器,负责协调视图和模型之间的交互。`CAppDevView``CAppDevOLView``CNavDevView`作为视图,负责显示设备信息和用户界面。`CDevOperator``CDevice`作为模型,负责处理设备数据和业务逻辑。这种架构使得界面逻辑与业务逻辑分离,提高了代码的可维护性和可扩展性。
```mermaid
classDiagram
class CDevMngFrame {
+CView* m_pAppDevView
+CView* m_pNavDevView
+CDevOperator* m_pDevOperator
+ShowAppView(DWORD, UINT)
+OnModifyDeviceParameter()
+OnRegisterNewDevice()
}
class CAppDevView {
+CView* m_pDevDetailListView
+CView* m_pDevContentListView
}
class CAppDevOLView {
+CView* m_pDevOLDetailListView
+CView* m_pDevOLGRListView
+CView* m_pDevOLACListView
}
class CNavDevView {
+CTreeCtrl m_devTree
}
class CDevOperator {
+CStateProcessor m_stateProcessor
+CHandleProcessor m_handleProcessor
+InitialNavDevView(CNavDevView*)
+ShowFLDeviceInfo(DWORD, CView*)
+ShowOLDeviceInfo(DWORD, CView*)
+ModifyDeviceParameter(CNavDevView*, CListCtrl&)
}
class CDevice {
+CString m_szDevSN
+UINT m_uState
+DWORD m_dwID
+ShowOLDetailInfo(CListCtrl&)
+ShowGRInfo(CListCtrl&)
+ShowACInfo(CListCtrl&)
}
CDevMngFrame --> CAppDevView : "包含"
CDevMngFrame --> CAppDevOLView : "包含"
CDevMngFrame --> CNavDevView : "包含"
CDevMngFrame --> CDevOperator : "使用"
CDevOperator --> CDevice : "操作"
CAppDevView --> CDevice : "显示"
CAppDevOLView --> CDevice : "显示"
```
**图表来源**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L1-L1806)
- [appdevview.cpp](file://cpp/Views/appdevview.cpp#L1-L102)
- [appdevolview.cpp](file://cpp/Views/appdevolview.cpp#L1-L120)
- [navdevview.cpp](file://cpp/Views/navdevview.cpp#L1-L180)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp#L1-L1604)
## 详细组件分析
### CDevMngFrame 分析
`CDevMngFrame`是设备管理框架的主窗口类,继承自`CMDIChildWnd`。它负责创建和管理设备管理界面的布局,包括导航视图和应用视图。通过`OnCreateClient`方法,它使用`CSplitterWnd`将窗口分割为左右两部分,左侧为`CNavDevView`,右侧为`CAppDevView``CAppDevOLView``ShowAppView`方法根据设备状态动态切换右侧视图。
#### 类图
```mermaid
classDiagram
class CDevMngFrame {
+CView* m_pAppDevView
+CView* m_pNavDevView
+CDevOperator* m_pDevOperator
+CSplitterWnd m_splitter
+ShowAppView(DWORD, UINT)
+OnMDIActivate(BOOL, CWnd*, CWnd*)
+OnClose()
}
CDevMngFrame --|> CMDIChildWnd
```
**图表来源**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L1-L1806)
- [devmngframe.h](file://h/devmngframe.h#L1-L108)
#### 消息处理流程
```mermaid
sequenceDiagram
participant 用户
participant CDevMngFrame
participant CDevOperator
participant CDevice
用户->>CDevMngFrame : 选择设备
CDevMngFrame->>CDevMngFrame : OnSelchangedNavDevTree
CDevMngFrame->>CDevMngFrame : OnSchedule
CDevMngFrame->>CDevOperator : ShowOLDeviceInfo 或 ShowFLDeviceInfo
CDevOperator->>CDevice : 获取设备信息
CDevice-->>CDevOperator : 返回设备信息
CDevOperator-->>CDevMngFrame : 更新视图
CDevMngFrame-->>用户 : 显示设备详细信息
```
**图表来源**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L1-L1806)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp#L1-L1604)
**章节来源**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L1-L1806)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp#L1-L1604)
### CAppDevView 与 CAppDevOLView 分析
`CAppDevView``CAppDevOLView`分别用于显示离线和在线设备的详细信息。`CAppDevView`包含`CAppDevDetailListView``CAppDataTdListView`,用于显示设备基本信息和测试数据。`CAppDevOLView`包含`CAppDevOLDetailListView``CAppDevOLGRListView``CAppDevOLACView`,用于显示在线设备的详细信息、接地电阻和交流信息。
#### 布局流程图
```mermaid
flowchart TD
Start([创建视图]) --> CreateSplitter["创建分割窗口"]
CreateSplitter --> CreateDetail["创建详细信息列表"]
CreateDetail --> CreateContent["创建内容列表"]
CreateContent --> SetStyle["设置列表样式"]
SetStyle --> InsertColumns["插入列表列"]
InsertColumns --> InsertItems["插入列表项"]
InsertItems --> End([视图创建完成])
```
**图表来源**
- [appdevview.cpp](file://cpp/Views/appdevview.cpp#L1-L102)
- [appdevolview.cpp](file://cpp/Views/appdevolview.cpp#L1-L120)
**章节来源**
- [appdevview.cpp](file://cpp/Views/appdevview.cpp#L1-L102)
- [appdevolview.cpp](file://cpp/Views/appdevolview.cpp#L1-L120)
### CNavDevView 分析
`CNavDevView`提供设备的导航树视图,用户可以通过树形结构浏览和选择设备。它通过`CTreeCtrl`控件实现树形视图,并在`OnInitialUpdate`方法中初始化树的样式。`OnRclickNavDevTree`方法处理右键点击事件,弹出上下文菜单。
#### 交互流程图
```mermaid
flowchart TD
A([用户右键点击设备]) --> B{是否在设备上?}
B --> |是| C[选择设备]
C --> D[获取设备句柄和状态]
D --> E[发送调度消息]
E --> F[更新应用视图]
F --> G[显示设备详细信息]
B --> |否| H[无操作]
```
**图表来源**
- [navdevview.cpp](file://cpp/Views/navdevview.cpp#L1-L180)
- [navdevview.h](file://h/navdevview.h#L1-L70)
**章节来源**
- [navdevview.cpp](file://cpp/Views/navdevview.cpp#L1-L180)
### CDevOperator 分析
`CDevOperator`类封装了设备操作的业务逻辑,包括设备注册、参数修改和状态查询。它通过`InitialNavDevView`方法初始化导航视图,通过`ShowOLDeviceInfo``ShowFLDeviceInfo`方法显示在线和离线设备的详细信息。`ModifyDeviceParameter`方法用于修改设备参数。
#### 业务逻辑流程图
```mermaid
flowchart TD
Start([修改设备参数]) --> GetSelection["获取选中设备"]
GetSelection --> GetHandle["获取设备句柄"]
GetHandle --> GetID["获取设备ID"]
GetID --> GetDevice["获取设备对象"]
GetDevice --> ModifyParam["修改设备参数"]
ModifyParam --> ShowInfo["更新视图显示"]
ShowInfo --> End([参数修改完成])
```
**图表来源**
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp#L1-L1604)
- [DevOperator.h](file://h/DevOperator.h#L1-L59)
**章节来源**
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp#L1-L1604)
## 依赖分析
设备管理界面的组件之间存在紧密的依赖关系。`CDevMngFrame`依赖于`CDevOperator`来执行设备操作,`CDevOperator`又依赖于`CDevice`来获取设备信息。视图组件如`CAppDevView``CAppDevOLView`依赖于`CDevOperator`来更新显示内容。这种依赖关系通过指针成员变量和方法调用实现。
```mermaid
graph TD
CDevMngFrame --> CDevOperator
CDevOperator --> CDevice
CDevMngFrame --> CNavDevView
CDevMngFrame --> CAppDevView
CDevMngFrame --> CAppDevOLView
CAppDevView --> CDevice
CAppDevOLView --> CDevice
```
**图表来源**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L1-L1806)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp#L1-L1604)
- [appdevview.cpp](file://cpp/Views/appdevview.cpp#L1-L102)
- [appdevolview.cpp](file://cpp/Views/appdevolview.cpp#L1-L120)
**章节来源**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L1-L1806)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp#L1-L1604)
## 性能考虑
设备管理界面在处理大量设备时可能会遇到性能瓶颈。建议在初始化导航视图时,采用异步加载的方式,避免阻塞UI线程。此外,对于频繁更新的实时状态数据,可以采用定时器机制,定期刷新视图,而不是实时更新,以减少CPU和内存的消耗。
## 故障排除指南
当设备管理界面无法正常显示设备信息时,首先检查设备连接状态和串口配置。如果设备在线但无法通信,可以尝试重启设备或重新插拔串口线。如果问题仍然存在,可以使用`OnGetAnlyseInfo`功能获取诊断信息,分析日志文件以定位问题。
**章节来源**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L600-L640)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp#L609-L639)
## 结论
设备管理界面通过`devmngframe`框架与多个视图协同工作,为用户提供了一个功能丰富的设备管理环境。其MVC架构设计使得界面逻辑与业务逻辑分离,便于维护和扩展。开发者可以通过扩展`CDevOperator`类来添加新的诊断功能或集成新型硬件协议,满足不断变化的需求。
@@ -0,0 +1,264 @@
# 设备连接与发现
<cite>
**本文档引用的文件**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp)
- [DialFindComShow.cpp](file://cpp/Views/DialFindComShow.cpp)
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp)
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h)
- [DevManager.h](file://h/DevManager.h)
- [DetcGD10Dev.h](file://h/DetcGD10Dev.h)
- [SComPort.h](file://h/SComPort.h)
- [DevOperator.h](file://h/DevOperator.h)
</cite>
## 目录
1. [引言](#引言)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构概述](#架构概述)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
## 引言
本文档深入文档化GeomativeStudio软件中设备连接与发现功能的实现机制。重点描述了串口扫描、设备识别协议(GD10)和通信建立流程。详细解释了CDevMngFrame中OnRefreshNavDevice消息处理如何触发设备列表更新,以及DialFindComShow对话框在串口配置中的作用。提供了用户操作指南,涵盖手动/自动设备发现、串口参数设置与连接测试。为开发者说明了如何扩展支持新型设备型号、修改设备识别逻辑或集成网络设备发现协议(如UDP广播)。结合DevManager的设备枚举接口,阐述了底层通信层与UI层的数据同步机制。
## 项目结构
GeomativeStudio项目是一个用于地质勘探设备管理的桌面应用程序。项目结构清晰,主要分为以下几个部分:
- **CACHE**: 缓存文件目录
- **DB**: 数据库相关文件
- **Install**: 安装包和部署文件
- **LOG**: 日志文件目录
- **Release**: 发布版本文件
- **cpp**: C++源代码目录,包含主要的业务逻辑
- **h**: C++头文件目录
- **res**: 资源文件目录
- **tools**: 工具脚本
核心的设备连接与发现功能主要实现在`cpp/Managers``cpp/Operator``cpp/Tools`目录下的源文件中。
## 核心组件
设备连接与发现功能的核心组件包括:
- **CDevManager**: 设备管理器,负责设备的增删改查和状态管理
- **CDetcGD10Dev**: GD10设备检测器,负责通过USB接口发现和连接GD10设备
- **CSComPort**: 串口通信类,提供底层串口读写功能
- **CDevMngFrame**: 设备管理框架窗口,处理UI与设备管理的交互
- **CDevOperator**: 设备操作员,协调UI和设备管理器之间的操作
这些组件共同协作,实现了从设备发现、连接到参数配置的完整流程。
**本文档引用的文件**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp)
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp)
- [DevManager.h](file://h/DevManager.h)
- [DetcGD10Dev.h](file://h/DetcGD10Dev.h)
- [SComPort.h](file://h/SComPort.h)
- [DevOperator.h](file://h/DevOperator.h)
## 架构概述
设备连接与发现功能的架构可以分为三层:用户界面层、业务逻辑层和通信层。
```mermaid
graph TB
subgraph "用户界面层"
UI[CDevMngFrame]
Dialog[DialFindComShow]
end
subgraph "业务逻辑层"
Operator[CDevOperator]
Manager[CDevManager]
end
subgraph "通信层"
Detector[CDetcGD10Dev]
ComPort[CSComPort]
Protocol[CtrlProtocolDef]
end
UI --> Operator
Operator --> Manager
Manager --> Detector
Detector --> ComPort
ComPort --> Protocol
```
**本文档引用的文件**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp)
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp)
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h)
## 详细组件分析
### CDevMngFrame分析
CDevMngFrame是设备管理的主框架窗口,负责处理用户界面与设备管理功能的交互。
#### 消息处理机制
CDevMngFrame通过Windows消息机制与系统其他部分通信。关键的消息处理函数包括:
```mermaid
sequenceDiagram
participant User as "用户"
participant UI as "CDevMngFrame"
participant Operator as "CDevOperator"
participant Manager as "CDevManager"
User->>UI : 点击"刷新设备"
UI->>UI : 发送WM_REFRESH_NAV_DEVICE消息
UI->>Operator : 调用InitialNavDevView()
Operator->>Manager : 获取设备列表
Manager-->>Operator : 返回设备列表
Operator-->>UI : 更新设备树
UI-->>User : 显示更新后的设备列表
```
**本文档引用的文件**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
- [DevOperator.h](file://h/DevOperator.h)
#### OnRefreshNavDevice消息处理
当收到WM_REFRESH_NAV_DEVICE消息时,CDevMngFrame会触发设备列表的更新。这个过程是设备发现和状态同步的核心。
```mermaid
flowchart TD
Start([开始]) --> CheckNull["检查m_pNavDevView和m_pDevOperator是否为空"]
CheckNull --> |否| CallInitial["调用m_pDevOperator->InitialNavDevView()"]
CallInitial --> UpdateTree["更新设备树视图"]
UpdateTree --> End([结束])
CheckNull --> |是| ShowError["显示错误消息"]
ShowError --> End
```
**本文档引用的文件**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L586-L596)
### CDetcGD10Dev分析
CDetcGD10Dev类负责GD10设备的检测和连接,是设备发现功能的核心。
#### 设备检测流程
CDetcGD10Dev通过枚举系统中的可移动驱动器来发现GD10设备。
```mermaid
flowchart TD
Start([开始]) --> GetDrivers["获取所有逻辑驱动器"]
GetDrivers --> LoopDrivers["遍历每个驱动器"]
LoopDrivers --> IsRemovable["是否为可移动驱动器?"]
IsRemovable --> |是| GetVolumeInfo["获取卷信息"]
GetVolumeInfo --> CompareName["卷名是否为GD10/GD20?"]
CompareName --> |是| FoundDevice["找到设备,返回驱动器路径"]
CompareName --> |否| CheckSDFolder["检查是否存在\\SD\\equipment目录"]
CheckSDFolder --> |存在| FoundDevice
CheckSDFolder --> |不存在| NextDriver["下一个驱动器"]
IsRemovable --> |否| NextDriver
NextDriver --> LoopDrivers
FoundDevice --> End([结束])
LoopDrivers --> |所有驱动器检查完毕| End
```
**本文档引用的文件**
- [DetcGD10Dev.cpp](file://cpp/Operator/DetcGD10Dev.cpp#L100-L173)
### CSComPort分析
CSComPort类提供了底层串口通信功能,是设备通信的基础。
#### 串口初始化流程
CSComPort在打开串口时会进行一系列配置,确保通信的稳定性和可靠性。
```mermaid
flowchart TD
Start([开始]) --> CheckHandle["检查串口句柄是否已打开"]
CheckHandle --> |否| SetComName["设置串口名称"]
SetComName --> CreateFile["创建串口文件句柄"]
CreateFile --> |成功| SetupComm["设置通信缓冲区"]
SetupComm --> GetCommState["获取当前通信状态"]
GetCommState --> SetBaudRate["设置波特率为115200"]
SetBaudRate --> SetDataBits["设置数据位为8"]
SetDataBits --> SetParity["设置无奇偶校验"]
SetParity --> SetStopBits["设置停止位为1"]
SetStopBits --> SetCommState["应用通信设置"]
SetCommState --> SetCommMask["设置事件掩码"]
SetCommMask --> End([结束])
CreateFile --> |失败| ReturnFalse["返回FALSE"]
ReturnFalse --> End
```
**本文档引用的文件**
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp#L127-L196)
## 依赖分析
设备连接与发现功能的组件之间存在明确的依赖关系。
```mermaid
classDiagram
class CDevMngFrame {
+CDevOperator* m_pDevOperator
+OnRefreshNavDevice()
+PreNetResponse()
}
class CDevOperator {
+CDevManager* m_pDevManager
+InitialNavDevView()
+ShowOLDeviceInfo()
}
class CDevManager {
+CLinkList<CDevice*> m_devLinkList
+InitialDevLinkList()
+AddDevice()
+DeleteDevice()
}
class CDetcGD10Dev {
+static CDetcGD10Dev* m_pDetcDev
+DetectGD10Dev()
+GetGD10DevAddr()
}
class CSComPort {
+HANDLE m_hCom
+OpenComm()
+SendDataDirectly()
+ReceiveDataDirectly()
}
CDevMngFrame --> CDevOperator : "使用"
CDevOperator --> CDevManager : "使用"
CDevManager --> CDetcGD10Dev : "使用"
CDetcGD10Dev --> CSComPort : "使用"
```
**本文档引用的文件**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
- [DevOperator.h](file://h/DevOperator.h)
- [DevManager.h](file://h/DevManager.h)
- [DetcGD10Dev.h](file://h/DetcGD10Dev.h)
- [SComPort.h](file://h/SComPort.h)
## 性能考虑
设备连接与发现功能在设计时考虑了以下性能因素:
1. **异步通信**: 使用重叠I/OOverlapped I/O)实现异步串口通信,避免阻塞UI线程
2. **缓存机制**: CDevManager维护设备链表缓存,减少数据库访问频率
3. **批量操作**: 设备列表更新采用批量处理,减少UI重绘次数
4. **资源管理**: 及时释放串口句柄和内存资源,防止资源泄漏
## 故障排除指南
### 常见问题及解决方案
| 问题现象 | 可能原因 | 解决方案 |
|---------|--------|---------|
| 无法发现GD10设备 | 设备未正确连接或驱动未安装 | 检查USB连接,安装正确的驱动程序 |
| 串口通信失败 | 波特率或参数设置不匹配 | 确认设备和软件的串口参数一致 |
| 设备列表不更新 | 消息处理异常 | 重启软件或检查日志文件 |
| 连接超时 | 设备响应慢或网络问题 | 延长超时时间或检查设备状态 |
**本文档引用的文件**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
- [SComPort.cpp](file://cpp/Tools/SComPort.cpp)
## 结论
GeomativeStudio的设备连接与发现功能通过分层架构实现了稳定可靠的设备管理。从底层的串口通信到上层的UI交互,各组件职责明确,协作良好。系统支持自动和手动设备发现,提供了完整的设备生命周期管理功能。通过理解本文档描述的实现机制,用户可以更好地使用该功能,开发者也可以在此基础上进行功能扩展和优化。
@@ -0,0 +1,146 @@
# 任务包与地形配置
<cite>
**本文档引用文件**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp)
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
</cite>
## 目录
1. [引言](#引言)
2. [任务包配置功能](#任务包配置功能)
3. [地形参数设置功能](#地形参数设置功能)
4. [任务包数据持久化机制](#任务包数据持久化机制)
5. [地形参数文件处理流程](#地形参数文件处理流程)
6. [用户界面操作指南](#用户界面操作指南)
7. [开发者实现解析](#开发者实现解析)
8. [结论](#结论)
## 引言
本文档全面阐述Geomative Studio软件中的任务包配置(DialCfgTaskPacket)与地形参数设置(DialCfgTerrain)两大核心功能。文档旨在为用户提供清晰的图形化界面操作指南,同时为开发者深入解析底层数据处理与持久化机制。通过详细说明调度参数配置、环境参数输入、数据验证规则及配置保存流程,确保用户能够高效、准确地完成地质勘探任务的前期配置工作。
## 任务包配置功能
任务包配置功能允许用户将多个测量任务组织成一个有序的执行序列。用户可以通过图形化界面选择并添加任务到任务包中,系统会自动管理任务的执行顺序。该功能的核心是调度参数的配置,包括循环次数和采集间隔,这些参数共同决定了任务包的执行时序。
**Section sources**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L1-L301)
## 地形参数设置功能
地形参数设置功能用于输入测量区域的高程和地质条件信息。用户可以通过界面直接输入或从外部文件导入地形数据点,每个数据点包含水平(X)和垂直(Y)坐标。系统支持两种地形数据标志:水平距离和垂直距离,用户可根据实际测量需求进行选择。此外,用户还需指定第一个电极对应的地形数据点编号,以建立电极位置与地形数据的映射关系。
**Section sources**
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp#L1-L843)
## 任务包数据持久化机制
任务包的配置数据通过CTaskDataOper类实现内存与数据库间的持久化。当用户在DialCfgTaskPacket界面完成配置并点击“保存”时,系统会调用CTaskDataOper::InsertTaskPacketInfo方法,将任务包信息写入数据库。
```mermaid
sequenceDiagram
participant 用户 as "用户"
participant 界面 as "DialCfgTaskPacket"
participant 操作类 as "CTaskDataOper"
participant 数据库 as "数据库"
用户->>界面 : 点击“保存”
界面->>界面 : 验证输入参数
界面->>操作类 : 调用InsertTaskPacketInfo()
操作类->>数据库 : 开始事务
操作类->>数据库 : 删除旧的tdTaskPacket记录
操作类->>数据库 : 插入新的任务包属性
操作类->>数据库 : 删除旧的tdTaskPacketInfo记录
操作类->>数据库 : 插入新的任务列表
操作类->>数据库 : 提交事务
操作类-->>界面 : 返回结果
界面-->>用户 : 显示“保存成功”消息
```
**Diagram sources**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L206-L300)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L669-L715)
## 地形参数文件处理流程
地形参数的配置最终会保存到一个.dat格式的文件中。该流程涉及文件的读取、解析和写入操作。系统首先读取.dat文件的头部信息以确定装置类型,然后根据装置类型决定是否需要添加地形数据。在保存时,系统会从文件末尾开始查找零结束符的位置,然后在该位置写入新的地形数据,确保不破坏原有的测量脚本。
```mermaid
flowchart TD
Start([开始]) --> CheckFile["检查是否已导入dat文件"]
CheckFile --> |否| ShowError1["提示:请先导入dat文件"]
CheckFile --> |是| CheckFlag["检查地形数据标志"]
CheckFlag --> |未选择| ShowError2["提示:请先选择地形数据标志"]
CheckFlag --> |已选择| CheckData["检查地形数据点"]
CheckData --> |无数据| ShowError3["提示:请输入地形数据"]
CheckData --> |有数据| CheckElectrode["验证第一个电极编号"]
CheckElectrode --> |无效| ShowError4["提示:编号必须在有效范围内"]
CheckElectrode --> |有效| OpenFile["打开dat文件"]
OpenFile --> ReadHeader["读取文件头部"]
ReadHeader --> ParseHeader["解析装置类型"]
ParseHeader --> CheckType["判断是否需要地形数据"]
CheckType --> |不需要| ShowError5["提示:该装置无需地形数据"]
CheckType --> |需要| FindEnd["查找文件末尾零结束符"]
FindEnd --> |未找到| ShowError6["提示:未找到结束符"]
FindEnd --> |找到| WriteData["写入地形数据"]
WriteData --> CloseFile["关闭文件"]
CloseFile --> ShowSuccess["提示:保存成功"]
ShowError1 --> End([结束])
ShowError2 --> End
ShowError3 --> End
ShowError4 --> End
ShowError5 --> End
ShowError6 --> End
ShowSuccess --> End
```
**Diagram sources**
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp#L539-L693)
## 用户界面操作指南
### 任务包配置操作步骤
1. **打开配置界面**:在软件主界面中,导航至任务管理模块,选择“任务包配置”功能。
2. **选择任务**:从下拉菜单中选择一个待添加的任务。
3. **添加任务**:点击“添加”按钮,将选中的任务加入任务列表。系统会自动检查任务是否重复。
4. **配置调度参数**
* **循环次数**:输入任务包需要重复执行的总次数,有效范围为1-60000。
* **采集间隔**:输入每次循环之间的等待时间(秒),有效范围为1-60000。
* **PLC ID**:输入可编程逻辑控制器的标识符。
5. **删除任务**:在任务列表中选中某项,点击“删除”按钮可将其移除。
6. **保存配置**:确认所有参数无误后,点击“确定”按钮保存配置。系统会进行输入验证,若通过则提示“保存成功”。
### 地形参数设置操作步骤
1. **打开配置界面**:在软件主界面中,导航至地形设置模块,选择“地形参数设置”功能。
2. **导入数据文件**:点击“导入文件”按钮,选择一个.dat格式的测量脚本文件。
3. **输入地形数据**
* 在列表中点击“添加”按钮。
* 在X和Y输入框中分别输入地形点的水平和垂直坐标。
* 点击“添加”确认,数据点将被加入列表。
4. **修改或删除数据**:选中列表中的数据点,可通过“修改”按钮更新坐标,或通过“删除”按钮移除。
5. **选择地形标志**:从下拉框中选择“水平距离”或“垂直距离”。
6. **设置电极映射**:在“第一个电极对应的地形数据点编号”输入框中,输入一个正整数,该编号必须在已输入的地形数据点范围内。
7. **保存数据**:点击“保存数据”按钮,系统会将地形信息写入之前导入的.dat文件。
**Section sources**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L47-L300)
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp#L450-L693)
## 开发者实现解析
### CTaskDataOper类核心方法
* **`QueryTaskPacketAttr`**: 该方法从数据库的`tdTaskPacket`表中查询当前的循环次数、采集间隔和PLC ID,并将结果填充到传入的引用参数中。它在DialCfgTaskPacket的`OnInitDialog`中被调用,用于初始化界面显示。
* **`InsertTaskPacketInfo`**: 这是任务包持久化的关键方法。它接收一个任务信息向量和一个属性结构体。方法内部使用数据库事务,首先清空`tdTaskPacket``tdTaskPacketInfo`两个表,然后重新插入新的配置数据,确保数据的一致性。
### 数据结构与映射关系
地形参数与测量脚本的空间映射关系至关重要。测量脚本(.dat文件)定义了电极的排列和测量序列,而地形数据则提供了这些电极所在位置的高程信息。通过“第一个电极对应的地形数据点编号”这一参数,系统能够将脚本中的第一个电极与地形数据列表中的某个点对齐,从而推算出所有电极的精确位置。这种映射直接影响后续数据采集的精度,尤其是在地形起伏较大的区域,准确的高程数据是进行精确电阻率反演的基础。
**Section sources**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L669-L715)
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L147-L157)
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp#L539-L693)
## 结论
任务包配置与地形参数设置是Geomative Studio软件中两个紧密关联且至关重要的功能模块。任务包配置通过循环次数和采集间隔等参数,实现了对复杂测量任务的自动化调度,极大地提升了野外作业的效率。地形参数设置则通过精确的高程数据输入,为后续的数据采集和反演分析提供了关键的环境信息,确保了测量结果的准确性。两者的结合,使得软件能够适应多样化的地质勘探场景,为用户提供了一套完整、可靠的测量解决方案。
@@ -0,0 +1,231 @@
# 任务包配置
<cite>
**本文档引用的文件**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [Constant.h](file://h/Constant.h)
- [DataMngStruct.h](file://h/DataMngStruct.h)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构概述](#架构概述)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
## 简介
本文档全面说明Geomative Studio中的任务包配置功能(DialCfgTaskPacket),涵盖调度参数配置、图形界面操作流程以及底层数据持久化机制。文档详细阐述了循环时间、采集间隔和PLC ID等关键参数的配置规则,包括输入验证范围和默认值设定。同时为用户提供任务列表管理的操作指南,并为开发者解析CTaskDataOper类中InsertTaskPacketInfo方法的实现逻辑。
## 项目结构
任务包配置功能主要分布在Views和Operator两个模块中,通过数据库持久化任务配置信息。系统采用MFC框架构建图形用户界面,通过ADO接口与数据库交互。
```mermaid
graph TB
subgraph "用户界面层"
DialCfgTaskPacket["DialCfgTaskPacket (任务包配置对话框)"]
end
subgraph "业务逻辑层"
TaskDataOper["CTaskDataOper (任务数据操作类)"]
end
subgraph "数据访问层"
Database["数据库 (Access/SQL Server)"]
end
DialCfgTaskPacket --> TaskDataOper
TaskDataOper --> Database
```
**图示来源**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L1-L301)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L1-L800)
**本节来源**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L1-L301)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L1-L800)
## 核心组件
任务包配置功能的核心组件包括DialCfgTaskPacket对话框类和CTaskDataOper数据操作类。DialCfgTaskPacket负责用户界面交互和输入验证,CTaskDataOper负责数据持久化和数据库操作。两个组件通过STTaskPacketAttr结构体和STTdBrowseInfo向量进行数据传递,实现了界面与业务逻辑的分离。
**本节来源**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L1-L301)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L668-L714)
## 架构概述
任务包配置功能采用典型的三层架构设计,包括表示层、业务逻辑层和数据访问层。用户通过图形界面输入配置参数,系统进行验证后,将任务包信息持久化到数据库中。
```mermaid
sequenceDiagram
participant 用户 as "用户"
participant 界面 as "DialCfgTaskPacket"
participant 业务逻辑 as "CTaskDataOper"
participant 数据库 as "数据库"
用户->>界面 : 打开任务包配置对话框
界面->>业务逻辑 : 查询可选任务列表
业务逻辑->>数据库 : 执行SQL查询
数据库-->>业务逻辑 : 返回任务列表
业务逻辑-->>界面 : 返回任务列表数据
界面->>界面 : 显示任务列表和配置参数
用户->>界面 : 输入循环时间、采集间隔、PLC ID
用户->>界面 : 添加/删除任务
用户->>界面 : 点击保存
界面->>界面 : 验证输入参数
界面->>业务逻辑 : 调用InsertTaskPacketInfo
业务逻辑->>数据库 : 开始事务
业务逻辑->>数据库 : 删除旧的任务包配置
业务逻辑->>数据库 : 插入新的任务包属性
业务逻辑->>数据库 : 插入任务包包含的任务
业务逻辑->>数据库 : 提交事务
数据库-->>业务逻辑 : 返回操作结果
业务逻辑-->>界面 : 返回保存结果
界面->>用户 : 显示保存成功/失败消息
```
**图示来源**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L206-L300)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L668-L714)
## 详细组件分析
### 任务包配置对话框分析
DialCfgTaskPacket类实现了任务包配置的图形用户界面,提供任务选择、参数输入和任务列表管理功能。
```mermaid
classDiagram
class CDialCfgTaskPacket {
+CListCtrl m_listTaskPacket
+CComboBox m_cmbTaskName
+OnInitDialog() bool
+OnButtonAdd() void
+OnButtonDel() void
+OnOK() void
+InitialTaskList() void
+IsRepeatTask(int) bool
}
CDialCfgTaskPacket --> CTaskDataOper : "使用"
CDialCfgTaskPacket --> STTaskPacketAttr : "使用"
CDialCfgTaskPacket --> STTdBrowseInfo : "使用"
```
**图示来源**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L18-L301)
**本节来源**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L18-L301)
### 任务数据操作类分析
CTaskDataOper类负责任务相关数据的持久化操作,包括任务包配置的保存和查询。
```mermaid
classDiagram
class CTaskDataOper {
+InsertTaskPacketInfo(vector<STTdBrowseInfo>, STTaskPacketAttr) bool
+QueryTaskPacketAttr(int&, int&, CString&) bool
+QueryTdBrowseInfo(vector<STTdBrowseInfo>&, int, int) bool
+QueryTaskPacketInfo(vector<STTdBrowseInfo>&) bool
}
class STTaskPacketAttr {
+int iLoopTimes
+int iInterval
+CString strPlcID
}
class STTdBrowseInfo {
+int iTaskID
+CString strTaskName
}
CTaskDataOper --> STTaskPacketAttr
CTaskDataOper --> STTdBrowseInfo
```
**图示来源**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L668-L714)
- [DataMngStruct.h](file://h/DataMngStruct.h#L1-L23)
**本节来源**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L668-L714)
### 调度参数配置流程分析
任务包配置涉及循环时间、采集间隔和PLC ID三个核心调度参数的配置,系统实施严格的输入验证规则。
```mermaid
flowchart TD
Start([开始配置]) --> ValidateLoopTime["验证循环时间"]
ValidateLoopTime --> LoopTimeValid{"1-60000之间?"}
LoopTimeValid --> |否| ShowLoopTimeError["显示错误消息: 循环次数的值必须在1-60000之间"]
LoopTimeValid --> |是| ValidateInterval["验证采集间隔"]
ValidateInterval --> IntervalValid{"1-60000之间?"}
IntervalValid --> |否| ShowIntervalError["显示错误消息: 时间间隔的值必须在1-60000之间"]
IntervalValid --> |是| ValidatePLCID["验证PLC ID"]
ValidatePLCID --> PLCIDValid{"已输入?"}
PLCIDValid --> |否| ShowPLCIError["显示错误消息: 请输入PLC ID"]
PLCIDValid --> |是| SaveConfig["保存配置"]
SaveConfig --> BeginTransaction["开始数据库事务"]
BeginTransaction --> DeleteOldConfig["删除旧的任务包配置"]
DeleteOldConfig --> InsertAttr["插入任务包属性"]
InsertAttr --> InsertTasks["插入任务包包含的任务"]
InsertTasks --> CommitTransaction["提交事务"]
CommitTransaction --> Success{"成功?"}
Success --> |是| ShowSuccess["显示保存成功"]
Success --> |否| ShowFail["显示保存失败"]
ShowSuccess --> End([配置完成])
ShowFail --> End
ShowLoopTimeError --> End
ShowIntervalError --> End
ShowPLCIError --> End
```
**图示来源**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L206-L300)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L668-L714)
**本节来源**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L206-L300)
## 依赖分析
任务包配置功能依赖于多个系统组件和外部库,形成复杂的依赖关系网络。
```mermaid
graph TD
DialCfgTaskPacket --> TaskDataOper
TaskDataOper --> ADO["ADO数据库接口"]
TaskDataOper --> GUCodeCreator["GUCodeCreator"]
TaskDataOper --> FileOperTools["FileOperTools"]
TaskDataOper --> AutoLock["AutoLock"]
ADO --> Database
GUCodeCreator --> UUID["UUID生成"]
FileOperTools --> FileSystem["文件系统"]
AutoLock --> Thread["多线程同步"]
style DialCfgTaskPacket fill:#f9f,stroke:#333
style TaskDataOper fill:#bbf,stroke:#333
style Database fill:#f96,stroke:#333
```
**图示来源**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L1-L301)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L1-L800)
**本节来源**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L1-L800)
## 性能考虑
任务包配置功能在设计时考虑了性能优化,特别是在数据库操作方面采用了事务处理机制,确保数据一致性的同时提高操作效率。系统在保存任务包配置时,先删除旧配置再插入新配置,避免了复杂的更新逻辑。对于大量任务的处理,建议分批操作以减少内存占用和数据库压力。
## 故障排除指南
当任务包配置功能出现问题时,可按照以下步骤进行排查:
1. **界面无法打开**:检查DialCfgTaskPacket对话框的资源定义是否正确,确认IDD常量定义无误。
2. **任务列表为空**:验证数据库连接是否正常,确认td表中存在可配置的任务。
3. **保存失败**:检查数据库事务是否被正确提交,确认tdTaskPacket和tdTaskPacketInfo表的结构是否符合预期。
4. **参数验证错误**:确认循环时间和采集间隔在1-60000的有效范围内,确保PLC ID已正确输入。
5. **重复任务无法添加**:系统已实现重复检测机制,相同任务ID的任务不能重复添加。
**本节来源**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L47-L108)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L668-L714)
## 结论
任务包配置功能为Geomative Studio提供了灵活的任务调度能力,通过DialCfgTaskPacket和CTaskDataOper组件的协同工作,实现了用户友好的界面操作和可靠的数据持久化。系统对循环时间、采集间隔和PLC ID等关键参数实施了严格的验证规则,确保配置的正确性。开发者可通过理解InsertTaskPacketInfo方法的实现逻辑,进一步扩展和定制任务包配置功能,满足特定的自动化测量需求。
@@ -0,0 +1,145 @@
# 地形配置
<cite>
**本文档引用文件**
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp)
- [DialCfgTerrain.h](file://h/DialCfgTerrain.h)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [TaskDataOper.h](file://h/TaskDataOper.h)
- [Rsp2DTd.cpp](file://cpp/ProblemZone/Rsp2DTd.cpp)
- [SP2DTd.cpp](file://cpp/ProblemZone/SP2DTd.cpp)
- [Res3DDatFile.cpp](file://cpp/Tools/Res3DDatFile.cpp)
- [Res3DDatFileRecord.cpp](file://cpp/Tools/Res3DDatFileRecord.cpp)
</cite>
## 目录
1. [简介](#简介)
2. [地形参数输入界面](#地形参数输入界面)
3. [数据格式与验证](#数据格式与验证)
4. [地形数据存储机制](#地形数据存储机制)
5. [地形参数与测量脚本的映射关系](#地形参数与测量脚本的映射关系)
6. [实际应用案例](#实际应用案例)
7. [结论](#结论)
## 简介
地形参数设置功能(DialCfgTerrain)是Geomative Studio软件中的一个关键模块,用于配置测量任务中的环境参数。该功能允许用户输入地形高程、地质条件和表面特征等信息,这些信息对于后续的数据采集精度和解释结果具有重要影响。通过图形化界面,用户可以方便地进行参数输入、验证和保存,确保测量方案的科学性和准确性。
**Section sources**
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp#L1-L843)
- [DialCfgTerrain.h](file://h/DialCfgTerrain.h#L1-L72)
## 地形参数输入界面
地形参数输入界面提供了直观的操作方式,用户可以通过该界面完成地形数据的配置。界面主要包括以下几个部分:
- **地形数据标志**:用户可以选择水平距离或垂直距离作为地形数据的标志。
- **地形数据明细**:用户可以在此列表中添加、修改和删除地形数据点,每个数据点包含ID、X坐标和Y坐标。
- **第一个电极对应的地形数据点编号**:用户需要指定第一个电极对应的地形数据点编号,以便系统正确映射地形数据与电极位置。
```mermaid
graph TD
A[地形参数输入界面] --> B[地形数据标志]
A --> C[地形数据明细]
A --> D[第一个电极对应的地形数据点编号]
B --> E[水平距离]
B --> F[垂直距离]
C --> G[添加数据点]
C --> H[修改数据点]
C --> I[删除数据点]
D --> J[输入编号]
```
**Diagram sources**
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp#L77-L81)
- [DialCfgTerrain.h](file://h/DialCfgTerrain.h#L25-L29)
## 数据格式与验证
为了确保地形数据的准确性和一致性,系统对输入的数据进行了严格的格式验证。具体要求如下:
- **X坐标和Y坐标**:必须为浮点数,且绝对值小于100000。
- **地形数据点编号**:必须为正整数,且在1到地形数据点总数之间。
- **地形数据标志**:必须选择水平距离或垂直距离之一。
```mermaid
flowchart TD
Start([开始]) --> ValidateInput["验证输入参数"]
ValidateInput --> InputValid{"输入有效?"}
InputValid --> |否| ReturnError["返回错误信息"]
InputValid --> |是| CheckDataCount["检查数据点数量"]
CheckDataCount --> DataCountValid{"数据点数量 > 0?"}
DataCountValid --> |否| ReturnError
DataCountValid --> |是| CheckFirstElectrode["检查第一个电极编号"]
CheckFirstElectrode --> FirstElectrodeValid{"编号在范围内?"}
FirstElectrodeValid --> |否| ReturnError
FirstElectrodeValid --> |是| SaveData["保存数据"]
SaveData --> End([结束])
ReturnError --> End
```
**Diagram sources**
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp#L472-L537)
- [DialCfgTerrain.h](file://h/DialCfgTerrain.h#L62)
## 地形数据存储机制
地形数据在系统中以特定的格式存储,并通过CTaskDataOper类进行管理和处理。具体存储机制如下:
- **数据结构**:地形数据以二维数组的形式存储,每个数据点包含X坐标和Y坐标。
- **文件格式**:地形数据保存在.dat文件中,文件末尾包含多个零作为结束符。
- **数据库存储**:地形数据的相关信息(如地形数据标志、数据点数量等)存储在数据库的`t2dtg`表中。
```mermaid
classDiagram
class CTaskDataOper {
+int m_iExplainStartIndex
+CString m_strDatFilePath
+bool CheckValidBeforSave()
+void OnButtonSaveData()
+int GetDevArrayFromText(const CString& strInfo)
+int GetWriteIndexFromEndTxt(CString strInfo, int &iEndZeroCnt)
+void InitUIByLanguage(int iLanguage)
}
class DialCfgTerrain {
+CEdit m_edit1stPtIndex
+CComboBox m_cmbTerrainDataFlag
+CListCtrl m_ctrlTerrainData
+CListCtrl m_ctrlRemarkHeader
+CListCtrl m_ctrlRemarkEnd
+CListCtrl m_ctrlRemarkDetail
}
CTaskDataOper --> DialCfgTerrain : "使用"
```
**Diagram sources**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L44-L817)
- [TaskDataOper.h](file://h/TaskDataOper.h#L42-L72)
## 地形参数与测量脚本的映射关系
地形参数与测量脚本之间存在紧密的映射关系,这种关系确保了测量数据的准确性和可靠性。具体映射过程如下:
- **数据读取**:系统从.dat文件中读取地形数据,并解析出地形数据标志和数据点数量。
- **数据写入**:将解析后的地形数据写入到测量脚本中,确保每个测点的地形信息与实际位置一致。
- **数据验证**:在写入过程中,系统会验证地形数据的完整性和正确性,防止数据丢失或错误。
```mermaid
sequenceDiagram
participant User as "用户"
participant Interface as "图形界面"
participant Controller as "控制器"
participant Database as "数据库"
User->>Interface : 输入地形数据
Interface->>Controller : 提交数据
Controller->>Controller : 验证数据格式
Controller->>Database : 保存地形数据
Database-->>Controller : 确认保存成功
Controller-->>Interface : 显示成功消息
Interface-->>User : 通知用户
```
**Diagram sources**
- [Rsp2DTd.cpp](file://cpp/ProblemZone/Rsp2DTd.cpp#L4672-L4823)
- [SP2DTd.cpp](file://cpp/ProblemZone/SP2DTd.cpp#L3248-L3252)
## 实际应用案例
### 案例一:复杂地形测量
在一个复杂的山区环境中,用户需要进行高精度的地质测量。通过地形参数设置功能,用户可以精确输入每个测点的地形高程和表面特征,确保测量数据的准确性。系统根据这些参数自动调整测量脚本,优化测量路径,提高数据采集效率。
### 案例二:城市地下管线探测
在城市地下管线探测项目中,地形参数设置功能帮助用户快速配置不同区域的地形条件。通过导入已有的地形数据文件,用户可以快速完成参数设置,减少现场工作量。系统根据地形数据生成最优的测量方案,确保探测结果的可靠性。
## 结论
地形参数设置功能(DialCfgTerrain)是Geomative Studio软件中不可或缺的一部分,它通过图形化界面和严格的数据验证机制,确保了地形数据的准确性和一致性。该功能不仅提高了测量任务的效率,还显著提升了数据采集的精度和解释结果的可靠性。通过合理的地形参数配置,用户可以更好地指导测量方案的设计,实现更高质量的地质勘探。
@@ -0,0 +1,183 @@
# 任务配置与调度
<cite>
**本文档引用的文件**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp)
- [DialCfgTaskPacket.h](file://h/DialCfgTaskPacket.h)
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp)
- [DialCfgTerrain.h](file://h/DialCfgTerrain.h)
- [DialTimerTask.cpp](file://cpp/Views/DialTimerTask.cpp)
- [DialTimerTask.h](file://h/DialTimerTask.h)
- [DialLoopTaskQuery.cpp](file://cpp/Views/DialLoopTaskQuery.cpp)
- [DialLoopTaskQuery.h](file://h/DialLoopTaskQuery.h)
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp)
- [DialManageLoopTask.h](file://h/DialManageLoopTask.h)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [TaskDataOper.h](file://h/TaskDataOper.h)
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h)
</cite>
## 目录
1. [引言](#引言)
2. [任务包配置 (DialCfgTaskPacket)](#任务包配置-dialcfgtaskpacket)
3. [地形参数设置 (DialCfgTerrain)](#地形参数设置-dialcfgterrain)
4. [定时任务 (DialTimerTask)](#定时任务-dialtimertask)
5. [循环任务管理 (DialLoopTaskQuery, DialManageLoopTask)](#循环任务管理-diallooptaskquery-dialmanagelooptask)
6. [任务树形结构与用户交互](#任务树形结构与用户交互)
7. [任务调度算法与状态机](#任务调度算法与状态机)
8. [任务序列化与反序列化机制](#任务序列化与反序列化机制)
9. [设备通信协议映射](#设备通信协议映射)
10. [操作指南](#操作指南)
## 引言
本系统提供了一套完整的任务配置与调度解决方案,涵盖了从任务创建、参数配置、地形数据管理到任务调度执行的全生命周期管理。系统通过任务包、定时任务和循环任务三种核心模式,实现了灵活、可靠的任务自动化。任务包允许用户将多个独立任务组合成一个有序序列,并进行循环执行;定时任务支持在指定时间点自动触发测量任务;循环任务则提供了更复杂的周期性执行策略。所有任务数据均通过统一的数据结构进行组织,并与设备通信协议紧密映射,确保了配置信息能够准确无误地传输到测量设备并执行。
## 任务包配置 (DialCfgTaskPacket)
该模块实现了任务包的创建、编辑和管理功能。用户可以从现有任务列表中选择任务,将其添加到任务包中,并设置循环次数、执行间隔和PLC ID等全局属性。任务包本质上是一个有序的任务序列,其执行遵循“循环次数”次,每次循环内按顺序执行所有任务,任务间间隔为“时间间隔”秒。
**Section sources**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L1-L301)
- [DialCfgTaskPacket.h](file://h/DialCfgTaskPacket.h#L1-L55)
- [TaskDataOper.h](file://h/TaskDataOper.h#L324-L335)
## 地形参数设置 (DialCfgTerrain)
该模块负责为测量任务配置地形数据。用户可以通过手动输入或导入.dat文件的方式,添加一系列包含X、Y坐标的地形点。系统支持两种地形数据标志:水平距离和垂直距离。配置完成后,地形数据将被写入到与任务关联的原始.dat文件末尾,供设备在测量时使用。
**Section sources**
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp#L1-L843)
- [DialCfgTerrain.h](file://h/DialCfgTerrain.h#L1-L73)
## 定时任务 (DialTimerTask)
该模块实现了基于时间的定时任务调度功能。用户可以为任意任务设置一个未来的执行时间点。系统会将这些定时任务存储在数据库中,并在到达指定时间时自动触发任务执行。为了区分由定时器自动创建的任务和用户手动创建的任务,系统使用了任务ID的最高位作为标志位(0x80000000)。
**Section sources**
- [DialTimerTask.cpp](file://cpp/Views/DialTimerTask.cpp#L1-L238)
- [DialTimerTask.h](file://h/DialTimerTask.h#L1-L61)
- [TaskDataOper.h](file://h/TaskDataOper.h#L275-L288)
## 循环任务管理 (DialLoopTaskQuery, DialManageLoopTask)
该模块提供了对循环任务的查询和管理功能。`DialLoopTaskQuery`用于从服务器查询当前存在的循环任务列表,用户可以选择一个或多个任务进行后续操作。`DialManageLoopTask`则是一个更高级的管理界面,它通过网络请求从服务器同步所有循环任务,并展示其详细信息,包括循环类型(次数循环或定时循环)、开始/结束时间以及包含的子任务列表。用户可以在此界面删除循环任务。
```mermaid
graph TD
A[用户界面] --> B[DialManageLoopTask]
B --> C{网络请求}
C --> |EN_REQ_DOWNLOAD_LOOP_TABLE| D[服务器]
D --> |返回循环任务表| C
C --> E[解析并显示任务列表]
E --> F[用户选择任务]
F --> G{用户操作}
G --> |删除| H[发送EN_CANCEL_LOOP_TASK_TRUST请求]
G --> |查看详情| I[发送EN_REQ_DOWNLOAD_LOOP_SUB_TABLE请求]
H --> D
I --> D
```
**Diagram sources**
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp#L230-L251)
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp#L520-L582)
**Section sources**
- [DialLoopTaskQuery.cpp](file://cpp/Views/DialLoopTaskQuery.cpp#L1-L145)
- [DialLoopTaskQuery.h](file://h/DialLoopTaskQuery.h#L1-L34)
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp#L1-L621)
- [DialManageLoopTask.h](file://h/DialManageLoopTask.h#L1-L70)
## 任务树形结构与用户交互
系统中的任务数据以树形结构进行组织,便于用户进行浏览和管理。任务树的根节点通常是项目或测区,其下包含不同类型的测量任务(如1D、2D、3D任务)。用户可以通过任务管理器界面直观地查看和操作这些任务。对于任务包和循环任务,它们在树形结构中表现为一个父节点,其子节点为包含的具体任务。用户交互逻辑主要通过对话框实现,例如`DialCfgTaskPacket`对话框允许用户通过“添加”、“删除”按钮来编辑任务包中的任务序列。
## 任务调度算法与状态机
系统的任务调度由多个组件协同完成。`TaskDataOper`类是核心的数据操作引擎,它负责与数据库交互,查询和管理所有任务的元数据。对于定时任务,系统在启动时会查询所有未来有效的定时任务,并在后台进行监控。当系统时间到达任务设定的执行时间时,调度器会触发任务执行流程。循环任务的调度逻辑则更为复杂,它由服务器端控制,客户端主要负责查询和管理。任务状态机的设计体现在任务的生命周期上,一个任务可以处于“待执行”、“执行中”、“已完成”或“已取消”等状态,这些状态通过数据库中的字段进行记录和同步。
## 任务序列化与反序列化机制
任务数据的序列化与反序列化主要通过`STQueryTaskBasicInfo`等结构体实现。这些结构体定义了任务的所有关键属性,如任务ID、名称、类型、脚本信息、电极配置等。当需要将任务信息从数据库读取到内存时,`TaskDataOper`类的`QueryTdBasicInfo`等方法会执行反序列化过程,将数据库记录填充到结构体实例中。反之,当需要保存任务配置时,系统会将结构体中的数据序列化为SQL语句或网络协议数据包。对于任务包,其序列化过程涉及将`STTdBrowseInfo`结构体的向量(vector)与`STTaskPacketAttr`结构体一起持久化到数据库。
**Section sources**
- [TaskDataOper.h](file://h/TaskDataOper.h#L126-L204)
- [TaskDataOper.h](file://h/TaskDataOper.h#L336-L335)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L356-L364)
## 设备通信协议映射
任务配置数据最终需要通过网络协议传输给测量设备(如GD10)。`CtrlProtocolDef.h`头文件定义了与设备通信的协议结构。例如,`STMeasuTaskParam`结构体直接映射了发送给设备的任务参数,其中包含了测试类型、发射周期、堆栈数、采样间隔等关键信息。当一个任务被调度执行时,系统会从数据库中查询该任务的详细信息,然后将其填充到`STMeasuTaskParam`等协议结构体中,最后通过TCP/IP网络发送给设备。这种映射关系确保了在软件界面上配置的参数能够准确地转化为设备可理解的指令。
```mermaid
classDiagram
class STQueryTaskBasicInfo {
+int iTaskID
+char szTaskName[60]
+int iTestType
+int iAR
+int iSptType
+float fXElecDistance
+float fYElecDistance
+UINT32 uiStartLayer
+UINT32 uiEndLayer
+UINT32 uiTimerTime
}
class STMeasuTaskParam {
+BYTE ucTestType
+BYTE ucTxPeriod
+BYTE ucSptType
+BYTE ucCableLayout
+BYTE ucStacking
+int iSAInterval
+float fElecSpace
+char ucTaskID[40]
}
class TaskDataOper {
+QueryTdBasicInfo(int, STQueryTaskBasicInfo*)
+QueryTimerTaskValiad(vector~STTimerTask~&, const SYSTEMTIME&)
}
class DialTimerTask {
+OnButtonAdd()
+OnButtonSave()
+OnInitDialog()
}
STQueryTaskBasicInfo --> TaskDataOper : "查询"
TaskDataOper --> STMeasuTaskParam : "映射"
DialTimerTask --> TaskDataOper : "调用"
```
**Diagram sources**
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L111-L123)
- [TaskDataOper.h](file://h/TaskDataOper.h#L126-L204)
## 操作指南
### 创建任务包
1. 打开“任务包配置”对话框。
2. 在下拉列表中选择一个任务,点击“添加”按钮将其加入任务包列表。
3. 重复步骤2,按顺序添加所有需要的任务。
4. 在“循环次数”框中输入希望重复执行整个任务包的次数(1-60000)。
5. 在“时间间隔”框中输入每个任务执行后的等待时间(秒,1-60000)。
6. 输入PLC ID。
7. 点击“确定”保存配置。
### 配置地形数据
1. 打开“地形参数设置”对话框。
2. 点击“导入文件”按钮,选择一个.dat格式的原始数据文件。
3. 在列表中输入或修改地形点的X、Y坐标,点击“添加”或“修改”按钮。
4. 选择“地形数据标志”(水平或垂直距离)。
5. 在“第一个电极对应的地形数据点编号”中输入起始点编号。
6. 点击“保存数据”按钮,将地形信息写入原始.dat文件。
### 设置定时任务
1. 打开“定时任务”对话框。
2. 选择一个任务、设置执行日期和时间。
3. 输入PLC ID。
4. 点击“添加”按钮,该任务将出现在定时任务列表中。
5. 点击“保存”完成所有定时任务的设置。
### 管理循环任务
1. 打开“循环任务管理”对话框。
2. 系统会自动从服务器加载所有循环任务。
3. 在列表中选择一个循环任务,其包含的子任务会显示在下方。
4. 如需删除,选中任务后点击“删除”按钮。
@@ -0,0 +1,310 @@
# 定时任务管理
<cite>
**本文档引用文件**
- [DialTimerTask.cpp](file://cpp/Views/DialTimerTask.cpp)
- [DialTimerTask.h](file://h/DialTimerTask.h)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [DialTimerTaskMeasu.cpp](file://cpp/Views/DialTimerTaskMeasu.cpp)
</cite>
## 目录
1. [定时任务管理概述](#定时任务管理概述)
2. [DialTimerTask对话框UI组件与交互逻辑](#dialtimertask对话框ui组件与交互逻辑)
3. [CTaskDataOper类技术实现细节](#ctaskdataoper类技术实现细节)
4. [定时器触发机制与任务状态机](#定时器触发机制与任务状态机)
5. [任务与设备通信协议集成](#任务与设备通信协议集成)
6. [任务执行失败处理机制](#任务执行失败处理机制)
## 定时任务管理概述
定时任务管理功能实现了任务的创建、时间规划、状态监控和执行触发的全流程控制。系统通过数据库表`task_timer`存储定时任务信息,结合系统时间进行任务触发判断。定时任务的核心流程包括:用户通过DialTimerTask对话框配置任务参数,系统将任务信息存储到数据库,定时器服务根据当前系统时间与任务计划时间的比较来触发任务执行。任务执行过程中,系统会更新任务状态,记录执行日志,并在失败时执行重试策略。
**Section sources**
- [DialTimerTask.cpp](file://cpp/Views/DialTimerTask.cpp#L1-L238)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L4426-L4455)
## DialTimerTask对话框UI组件与交互逻辑
DialTimerTask对话框提供了完整的定时任务配置界面,其UI组件布局和用户交互逻辑设计如下:
对话框主要包含以下UI组件:
- **IDC_DATETIMEPICKER_DATE**: 日期选择器,用于选择任务执行日期
- **IDC_DATETIMEPICKER_TIME**: 时间选择器,用于选择任务执行时间
- **IDC_COMBO_TASK_NAME**: 下拉组合框,用于选择要执行的任务名称
- **IDC_EDIT_PLC_ID**: 编辑框,用于输入PLC设备ID
- **IDC_LIST_TIMER_TASK**: 列表控件,显示已配置的定时任务列表,包含ID、任务名称、执行时间和PLC ID四列
- **IDC_BUTTON_ADD**: 添加按钮,用于将当前配置添加到任务列表
- **IDC_BUTTON_DEL**: 删除按钮,用于从任务列表中删除选中的任务
- **IDC_BUTTON_SAVE**: 保存按钮,用于保存所有配置的定时任务
用户交互逻辑如下:
1. 用户首先在下拉框中选择一个任务,然后输入PLC ID
2. 通过日期和时间选择器设置任务执行时间
3. 点击"添加"按钮,系统会验证输入的有效性(确保选择了任务、输入了PLC ID、时间不早于当前时间),然后将任务添加到列表中
4. 任务名称会自动生成为"原任务名_YYYYMMDDHHMM"格式,确保唯一性
5. 用户可以多次添加任务,形成任务队列
6. 点击"删除"按钮可移除选中的任务
7. 最后点击"保存"按钮,系统会先删除标记为删除的任务,然后保存新的定时任务到数据库
```mermaid
flowchart TD
Start([开始配置定时任务]) --> SelectTask["选择任务"]
SelectTask --> InputPLCID["输入PLC ID"]
InputPLCID --> SetDateTime["设置日期和时间"]
SetDateTime --> ValidateInput["验证输入有效性"]
ValidateInput --> InputValid{"输入有效?"}
InputValid --> |否| ShowError["显示错误信息"]
InputValid --> |是| AddToList["添加到任务列表"]
AddToList --> Continue{"继续添加?"}
Continue --> |是| SelectTask
Continue --> |否| SaveTasks["保存所有任务"]
SaveTasks --> End([完成定时任务配置])
ShowError --> End
```
**Diagram sources**
- [DialTimerTask.cpp](file://cpp/Views/DialTimerTask.cpp#L79-L145)
- [DialTimerTask.h](file://h/DialTimerTask.h#L49-L51)
**Section sources**
- [DialTimerTask.cpp](file://cpp/Views/DialTimerTask.cpp#L1-L238)
- [DialTimerTask.h](file://h/DialTimerTask.h#L47-L60)
## CTaskDataOper类技术实现细节
CTaskDataOper类提供了定时任务管理的核心数据操作方法,主要包括QueryTimerTaskValiad和AddTimerTask等关键方法。
### QueryTimerTaskValiad方法
`QueryTimerTaskValiad`方法用于查询有效的定时任务,其技术实现细节如下:
- 方法接收一个`std::vector<STTimerTask>`类型的引用参数`vtTimerTd`用于返回查询结果,以及一个`SYSTEMTIME`类型的`sysCurTime`参数表示当前系统时间
- 方法首先清空结果容器,然后构建SQL查询语句,从`task_timer`表中查询执行时间大于当前时间的所有任务
- SQL查询条件为:`RunDate > 当前日期` 或 (`RunDate = 当前日期``RunTime > 当前时间`)
- 查询结果按执行日期和时间排序,确保最先执行的任务排在前面
- 方法将查询到的任务信息填充到`STTimerTask`结构体中,并添加到结果向量中
### AddTimerTask方法
`AddTimerTask`方法用于添加新的定时任务,其技术实现细节如下:
- 方法接收任务ID、任务名称、执行时间和PLC ID作为参数
- 方法首先检查任务是否已存在,如果存在则更新,否则插入新记录
- 使用事务处理确保数据一致性,在插入过程中如果发生错误会回滚事务
- 任务ID采用特殊编码方式:通过将任务ID与0x80000000进行按位或操作来标记为定时任务,恢复时通过与0x7FFFFFFF进行按位与操作来获取原始ID
- 方法返回布尔值表示操作是否成功
```mermaid
classDiagram
class CTaskDataOper {
+QueryTimerTaskValiad(vtTimerTd, sysCurTime) void
+AddTimerTask(dwTdID, strTaskName, strRunTime, strPlcID) bool
+DeleteTimerTask(vtDleTimerTask) bool
-m_pRecTdData Recordset*
-m_iTdType int
-m_bIsOpenTdData bool
}
class STTimerTask {
+uiTaskID DWORD
+strTaskName CString
+strRunTime CString
+strPlcID CString
}
CTaskDataOper --> STTimerTask : "包含"
```
**Diagram sources**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L4426-L4440)
- [DialTimerTask.h](file://h/DialTimerTask.h#L49-L51)
**Section sources**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L205-L2734)
- [DialTimerTask.h](file://h/DialTimerTask.h#L47-L60)
## 定时器触发机制与任务状态机
定时任务的触发机制基于系统时间的比较和任务状态的转换,形成了一个完整的工作流程。
### 定时器触发机制
定时器触发机制的核心是`CompareTdTimer`函数,其实现逻辑如下:
- 函数接收当前系统时间和任务计划时间作为参数
- 将两个时间格式化为"YYYY-MM-DD HH:MM"格式的字符串
- 使用`strcmp`函数比较两个时间字符串
- 如果系统时间大于任务时间,说明任务已超时,记录超时日志
- 返回比较结果,用于判断是否应该执行任务
任务执行流程如下:
1. 系统定期调用`QueryTimerTaskValiad`方法获取所有待执行的任务
2. 对每个任务调用`CompareTdTimer`进行时间比较
3. 对于需要执行的任务,启动任务执行线程
4. 在执行前更新任务的测试日期和时间字段
5. 按照预设流程执行任务测量
### 任务状态机转换逻辑
定时任务执行过程中的状态机转换逻辑如下:
- **EN_TIMER_PROC_PLC_POWERON**: PLC开机状态,发送开机指令并等待响应
- **EN_TIMER_PROC_ROLLCALL**: 设备点名状态,对设备进行点名操作
- **EN_TIMER_PROC_CFG_TASK**: 任务配置状态,向设备发送任务参数
- **EN_TIMER_PROC_MEASU_DATA**: 数据测量状态,执行实际测量操作
- **EN_TIMER_PROC_MEASU_SUSPEND**: 测量暂停状态,用户暂停测量
- **EN_TIMER_PROC_MEASU_CONTINUE**: 测量继续状态,用户继续测量
- **EN_TIMER_PROC_MEASU_FIN**: 测量完成状态,任务正常结束
- **EN_TIMER_PROC_MEASU_TRMI**: 测量终止状态,任务异常终止
状态转换遵循严格的顺序,每个状态完成后自动进入下一个状态。系统还支持暂停和继续功能,允许用户在测量过程中暂停并稍后继续。
```mermaid
stateDiagram-v2
[*] --> PLC开机
PLC开机 --> 设备点名 : 开机成功
设备点名 --> 任务配置 : 点名成功
任务配置 --> 数据测量 : 配置成功
数据测量 --> 测量完成 : 全部测点完成
数据测量 --> 测量暂停 : 用户暂停
测量暂停 --> 数据测量 : 用户继续
数据测量 --> 测量终止 : 发生严重错误
测量暂停 --> 测量终止 : 用户取消
note right of 数据测量
包含重试机制:
- 网络超时重试
- 数据错误重试
- 最多重试90000次
end note
```
**Diagram sources**
- [DialTimerTaskMeasu.cpp](file://cpp/Views/DialTimerTaskMeasu.cpp#L815-L838)
- [DialTimerTaskMeasu.cpp](file://cpp/Views/DialTimerTaskMeasu.cpp#L626-L781)
**Section sources**
- [DialTimerTaskMeasu.cpp](file://cpp/Views/DialTimerTaskMeasu.cpp#L1-L1002)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L4426-L4440)
## 任务与设备通信协议集成
定时任务与设备通信协议的集成通过一系列标准化的通信流程实现,确保任务能够正确地在远程设备上执行。
### 通信协议集成方式
系统通过以下方式实现定时任务与设备通信协议的集成:
1. **PLC控制协议**: 使用专门的PLC控制命令与设备通信,包括开机、关机、状态查询等操作
2. **任务参数传输**: 将任务参数序列化后通过网络发送到设备端,参数包括测量周期、阵列类型、电缆布局等
3. **测量数据接收**: 设备完成测量后,将数据打包发送回主机,主机解析并存储到数据库
4. **状态同步**: 实时同步设备状态,包括告警状态、测量进度等
通信流程如下:
1. 建立与PLC设备的连接
2. 发送开机指令并等待响应
3. 执行设备点名,确认设备在线
4. 发送任务配置参数
5. 启动测量流程
6. 接收并处理测量数据
7. 关闭连接
### 通信数据结构
关键通信数据结构包括:
- **STMeasuTaskParam**: 测量任务参数结构体,包含测量周期、测试类型、阵列类型等信息
- **STSigSndDataInfo**: 信号发送数据信息,包含测点编号、电极位置等
- **STMeasuBasicDataRes**: 测量基本数据响应,包含电流、电压、电阻率等测量结果
- **STRemPlcDataInfo**: 远程PLC数据信息,包含PLC状态和控制结果
系统在发送数据前会将主机字节序转换为网络字节序(使用`htonl``tcp_htonf`等函数),接收数据时再转换回主机字节序(使用`ntohl``tcp_ntohf`等函数),确保跨平台兼容性。
```mermaid
sequenceDiagram
participant 主机 as "主机系统"
participant 网络 as "网络通信"
participant 设备 as "远程设备"
主机->>网络 : 发送PLC开机指令
网络->>设备 : 接收开机指令
设备-->>网络 : 返回开机响应
网络-->>主机 : 接收开机响应
主机->>网络 : 发送设备点名指令
网络->>设备 : 接收点名指令
设备-->>网络 : 返回点名响应
网络-->>主机 : 接收点名响应
主机->>网络 : 发送任务配置参数
网络->>设备 : 接收配置参数
设备-->>网络 : 返回配置响应
网络-->>主机 : 接收配置响应
主机->>网络 : 发送测量指令
网络->>设备 : 执行测量
设备-->>网络 : 返回测量数据
网络-->>主机 : 接收测量数据
主机->>主机 : 处理并存储数据
```
**Diagram sources**
- [DialTimerTaskMeasu.cpp](file://cpp/Views/DialTimerTaskMeasu.cpp#L685-L794)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L2713-L2734)
**Section sources**
- [DialTimerTaskMeasu.cpp](file://cpp/Views/DialTimerTaskMeasu.cpp#L485-L598)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L2713-L2734)
## 任务执行失败处理机制
系统实现了完善的任务执行失败处理机制,包括重试策略和日志记录,确保任务的可靠执行。
### 重试策略
系统采用智能重试策略处理任务执行失败:
- **重试条件**: 当遇到网络超时、数据错误、数据乱序等情况时触发重试
- **重试次数**: 最多重试90000次,通过`MAX_TIMER_REPEAT_SND_CNT`常量定义
- **重试间隔**: 单个测点的最大超时时间为60秒,给予网络充分的恢复时间
- **重试逻辑**: 在`NotifyResFunc`回调函数中处理重试逻辑,根据操作结果决定是否重试
重试流程如下:
1. 发送测量请求
2. 等待响应(最长60秒)
3. 如果超时或收到错误响应,增加重试计数
4. 如果重试计数未达到上限,重新发送请求
5. 如果重试计数达到上限,终止任务并记录错误
### 日志记录机制
系统实现了全面的日志记录机制:
- **操作日志**: 记录任务的每个关键操作,包括开始执行、状态转换、完成等
- **错误日志**: 详细记录各种错误情况,包括网络错误、数据库错误、设备告警等
- **性能日志**: 记录任务执行的时间信息,用于性能分析
- **调试日志**: 在开发和调试阶段提供详细的执行信息
日志记录的关键点包括:
- 在任务开始执行时记录"准备执行定时任务"日志
- 在时间比较发现超时时记录"定时任务超时"日志
- 在重试时记录"正在重试测量"日志
- 在遇到严重告警时记录告警信息
- 在数据库操作失败时记录详细的错误描述
日志通过`CFileOperTools::GetInstance()->WriteComLog()`方法写入日志文件,确保所有重要事件都有迹可循。
```mermaid
flowchart TD
Start([开始任务执行]) --> SendRequest["发送测量请求"]
SendRequest --> WaitForResponse["等待响应(60秒)"]
WaitForResponse --> ResponseReceived{"收到响应?"}
ResponseReceived --> |否| Timeout["超时"]
ResponseReceived --> |是| CheckData["检查数据有效性"]
CheckData --> DataValid{"数据有效?"}
DataValid --> |否| DataError["数据错误"]
DataValid --> |是| ProcessData["处理测量数据"]
ProcessData --> UpdateDB["更新数据库"]
UpdateDB --> Success["任务成功完成"]
Timeout --> Retry{"重试次数 < 90000?"}
DataError --> Retry
Retry --> |是| IncrementRetry["增加重试计数"]
IncrementRetry --> SendRequest
Retry --> |否| Fail["任务执行失败"]
Success --> End([结束])
Fail --> End
```
**Diagram sources**
- [DialTimerTaskMeasu.cpp](file://cpp/Views/DialTimerTaskMeasu.cpp#L326-L364)
- [DialTimerTaskMeasu.cpp](file://cpp/Views/DialTimerTaskMeasu.cpp#L832-L834)
**Section sources**
- [DialTimerTaskMeasu.cpp](file://cpp/Views/DialTimerTaskMeasu.cpp#L308-L380)
- [DialTimerTaskMeasu.cpp](file://cpp/Views/DialTimerTaskMeasu.cpp#L815-L838)
@@ -0,0 +1,283 @@
# 循环任务上传
<cite>
**本文档引用的文件**
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp)
- [DialUploadLoopTask.h](file://h/DialUploadLoopTask.h)
- [NetRequestDialog.cpp](file://cpp/socket/NetRequestDialog.cpp)
- [NetRequestDialog.h](file://cpp/socket/NetRequestDialog.h)
- [CDragListCtrl.cpp](file://cpp/ctrl/CDragListCtrl.cpp)
- [CDragListCtrl.h](file://cpp/ctrl/CDragListCtrl.h)
</cite>
## 目录
1. [简介](#简介)
2. [核心组件](#核心组件)
3. [网络通信架构](#网络通信架构)
4. [数据封装与上传流程](#数据封装与上传流程)
5. [拖拽排序功能实现](#拖拽排序功能实现)
6. [设备ID与PLC ID的作用](#设备id与plc-id的作用)
7. [消息响应处理](#消息响应处理)
## 简介
本文档全面文档化循环任务上传功能的技术实现,重点聚焦于`DialUploadLoopTask`类的设计。该功能允许用户创建并上传循环测量任务到GD10设备,支持通过拖拽方式对子任务进行排序,并通过网络通信协议将任务信息发送到目标设备。系统通过继承`CNetRequestDialog`类构建了完整的网络请求-响应架构,实现了从用户界面交互到数据传输的完整流程。
## 核心组件
`DialUploadLoopTask`类是循环任务上传功能的核心实现,继承自`CNetRequestDialog`,负责管理用户界面、数据封装和网络通信。该类通过`CDragListCtrl`控件实现任务列表的拖拽排序功能,使用`STTaskListItem`结构体存储任务信息,并通过`PostNetRequest`方法发起网络请求与GD10设备通信。
**本节来源**
- [DialUploadLoopTask.h](file://h/DialUploadLoopTask.h#L10-L65)
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp#L22-L30)
## 网络通信架构
### 继承关系与架构设计
`DialUploadLoopTask`类继承自`CNetRequestDialog`,后者提供了基础的网络通信能力。这种设计模式实现了网络通信功能的复用和封装,形成了清晰的职责分离:`CNetRequestDialog`处理底层网络通信机制,而`DialUploadLoopTask`专注于业务逻辑和用户界面。
```mermaid
classDiagram
class CNetRequestDialog {
+CNetRequestDialog(UINT nIDTemplate, CWnd* pParent)
+~CNetRequestDialog()
+PostNetRequest(BYTE cmd, HWND hwnd, char* pData, WORD dataLen)
-PreNetResponse(WPARAM wParam, LPARAM lParam)
-DoDataExchange(CDataExchange* pDX)
}
class DialUploadLoopTask {
+DialUploadLoopTask(CWnd* pParent)
+~DialUploadLoopTask()
+SetDeviceID(DWORD dwDeviceID)
+SetPLCID(DWORD dwPLCID)
+OnInitDialog()
+OnBnClickedUploadLoop()
+OnBnClickedExitUpload()
+OnCbnSelchangeTimerTypeCombo()
+DragMoveItem(WPARAM wParam, LPARAM lParam)
-PreNetResponse(WPARAM wParam, LPARAM lParam)
-DoDataExchange(CDataExchange* pDX)
-m_CListCtrlTask CDragListCtrl
-m_TaskList CList<STTaskListItem>
-m_dwDeviceSN DWORD
-m_dwPLCID DWORD
}
DialUploadLoopTask --|> CNetRequestDialog : 继承
```
**图表来源**
- [DialUploadLoopTask.h](file://h/DialUploadLoopTask.h#L10)
- [NetRequestDialog.h](file://cpp/socket/NetRequestDialog.h#L8)
**本节来源**
- [DialUploadLoopTask.h](file://h/DialUploadLoopTask.h#L10)
- [NetRequestDialog.h](file://cpp/socket/NetRequestDialog.h#L8)
## 数据封装与上传流程
### 任务信息结构体
循环任务上传的数据封装基于`STLoopTaskInfo`结构体,该结构体包含了任务的所有必要信息:
```mermaid
classDiagram
class STLoopTaskInfo {
+char ucTaskID[MAX_NAME_LEN]
+char ucTaskName[MAX_NAME_LEN]
+UINT32 uiGD10Id
+UINT32 uiPlcId
+UINT8 ucContrlType
+UINT8 ucTimerType
+UINT64 uiLoopNum
+UINT8 ucLoopType
+UINT8 ucTimerAgsNum
+UINT8 ucTimerTimeAgs
+UINT32 uiStartTime
+UINT32 uiEndTime
+UINT32 uiStartMin
+UINT32 uiTaskSpace
+UINT32 uiSubTaskNum
}
```
### 上传流程实现
上传流程在`OnBnClickedUploadLoop`方法中实现,主要包括以下步骤:
1. **参数验证**:检查子任务数量、任务名称、循环次数等输入参数的有效性
2. **数据填充**:从界面控件获取数据并填充到`STLoopTaskInfo`结构体中
3. **字节序转换**:使用`htonl``htons`函数将主机字节序转换为网络字节序
4. **任务列表序列化**:将`STTaskListItem`列表中的任务ID按顺序序列化到发送缓冲区
5. **网络请求发起**:调用`PostNetRequest`方法发送数据
```mermaid
flowchart TD
Start([开始上传]) --> ValidateInput["验证输入参数"]
ValidateInput --> InputValid{"参数有效?"}
InputValid --> |否| ShowError["显示错误信息"]
InputValid --> |是| FillData["填充STLoopTaskInfo结构体"]
FillData --> ConvertByteOrder["转换为网络字节序"]
ConvertByteOrder --> SerializeTasks["序列化任务列表"]
SerializeTasks --> SuspendThread["暂停网络线程"]
SuspendThread --> SendRequest["调用PostNetRequest发送请求"]
SendRequest --> ResumeThread["恢复网络线程"]
ResumeThread --> End([上传完成])
ShowError --> End
```
**图表来源**
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp#L180-L377)
**本节来源**
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp#L180-L377)
## 拖拽排序功能实现
### CDragListCtrl控件应用
`CDragListCtrl`控件是实现任务拖拽排序的关键组件,它继承自`CListCtrl`并扩展了拖拽功能。该控件通过Windows消息机制处理拖拽操作,实现了直观的任务重新排序体验。
```mermaid
classDiagram
class CListCtrl {
+GetItemCount()
+GetItemText(int nItem, int nSubItem)
+SetItemText(int nItem, int nSubItem, LPCTSTR lpszText)
+InsertItem(int nItem, LPCTSTR lpszItem)
}
class CDragListCtrl {
+OnLvnBegindrag(NMHDR *pNMHDR, LRESULT *pResult)
+OnMouseMove(UINT nFlags, CPoint point)
+OnLButtonUp(UINT nFlags, CPoint point)
-m_nSelItem int
-m_pDragImageList CImageList*
-m_bDragging BOOL
}
CDragListCtrl --|> CListCtrl : 继承
```
### 拖拽事件处理流程
拖拽排序功能通过以下三个关键事件处理:
1. **开始拖拽**`OnLvnBegindrag`):当用户开始拖拽时创建拖拽图像并进入拖拽模式
2. **鼠标移动**`OnMouseMove`):在拖拽过程中更新拖拽图像位置
3. **释放鼠标**`OnLButtonUp`):完成拖拽操作,更新列表项位置
```mermaid
sequenceDiagram
participant User as 用户
participant CDragListCtrl as CDragListCtrl控件
participant DialUploadLoopTask as DialUploadLoopTask对话框
User->>CDragListCtrl : 开始拖拽操作
CDragListCtrl->>CDragListCtrl : OnLvnBegindrag事件
CDragListCtrl->>CDragListCtrl : 创建拖拽图像
CDragListCtrl->>CDragListCtrl : 进入拖拽模式
loop 拖拽过程中
User->>CDragListCtrl : 移动鼠标
CDragListCtrl->>CDragListCtrl : OnMouseMove事件
CDragListCtrl->>CDragListCtrl : 更新拖拽图像位置
end
User->>CDragListCtrl : 释放鼠标按钮
CDragListCtrl->>CDragListCtrl : OnLButtonUp事件
CDragListCtrl->>CDragListCtrl : 结束拖拽操作
CDragListCtrl->>DialUploadLoopTask : 发送WM_MOVEITEM消息
DialUploadLoopTask->>DialUploadLoopTask : DragMoveItem处理
DialUploadLoopTask->>DialUploadLoopTask : 重新排列列表项
```
**图表来源**
- [CDragListCtrl.cpp](file://cpp/ctrl/CDragListCtrl.cpp#L93-L178)
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp#L57-L58)
**本节来源**
- [CDragListCtrl.cpp](file://cpp/ctrl/CDragListCtrl.cpp#L93-L178)
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp#L481-L532)
## 设备ID与PLC ID的作用
### 设备标识符管理
`DialUploadLoopTask`类通过两个关键成员变量管理设备标识:
- `m_dwDeviceSN`:存储GD10设备的序列号(Device ID
- `m_dwPLCID`:存储PLC控制器的ID
这两个标识符在任务上传过程中起着至关重要的作用,确保任务被正确路由到目标设备。
### 标识符的设置与使用
设备ID和PLC ID通过专门的setter方法进行设置:
```mermaid
classDiagram
class DialUploadLoopTask {
+SetDeviceID(DWORD dwDeviceID)
+SetPLCID(DWORD dwPLCID)
-m_dwDeviceSN DWORD
-m_dwPLCID DWORD
}
class UsageFlow {
direction LR
A[用户选择设备] --> B[调用SetDeviceID]
B --> C[保存m_dwDeviceSN]
D[用户选择PLC] --> E[调用SetPLCID]
E --> F[保存m_dwPLCID]
C --> G[上传时填充STLoopTaskInfo]
F --> G
G --> H[发送到GD10设备]
}
```
在上传过程中,这些ID被提取自界面控件(去除"SN"和"PLC"前缀),转换为整数后填充到`STLoopTaskInfo`结构体的`uiGD10Id``uiPlcId`字段中,确保设备能够正确识别和处理上传的任务。
**图表来源**
- [DialUploadLoopTask.h](file://h/DialUploadLoopTask.h#L22-L30)
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp#L232-L238)
**本节来源**
- [DialUploadLoopTask.h](file://h/DialUploadLoopTask.h#L22-L30)
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp#L232-L238)
## 消息响应处理
### 预处理与响应机制
`DialUploadLoopTask`类实现了`CNetRequestDialog`定义的`PreNetResponse`纯虚函数,用于处理来自GD10设备的响应消息。这种设计模式遵循了模板方法模式,基类`CNetRequestDialog`定义了算法骨架,子类实现具体步骤。
```mermaid
sequenceDiagram
participant GD10 as GD10设备
participant Network as 网络模块
participant CNetRequestDialog as CNetRequestDialog
participant DialUploadLoopTask as DialUploadLoopTask
GD10->>Network : 发送响应数据包
Network->>CNetRequestDialog : OnNetResponse消息
CNetRequestDialog->>CNetRequestDialog : 调用PreNetResponse
CNetRequestDialog->>DialUploadLoopTask : 虚函数调用
DialUploadLoopTask->>DialUploadLoopTask : 处理具体响应
DialUploadLoopTask->>DialUploadLoopTask : 显示结果或错误信息
```
### 响应处理逻辑
`PreNetResponse`方法根据响应命令类型和状态码进行相应的处理:
```mermaid
flowchart TD
Start([收到响应]) --> CheckCommand["检查命令类型 EN_REQ_LOOP_TASK_TRUST"]
CheckCommand --> IsMatch{"命令匹配?"}
IsMatch --> |否| Exit[忽略响应]
IsMatch --> |是| CheckStatus["检查状态码"]
CheckStatus --> Success{"状态码=0?"}
Success --> |是| ShowSuccess["显示成功消息"]
Success --> |否| CheckConflict["检查是否为时间冲突"]
CheckConflict --> IsConflict{"状态码=2?"}
IsConflict --> |是| ShowConflict["显示时间冲突消息"]
IsConflict --> |否| ShowUnknownError["显示未知错误"]
ShowSuccess --> CloseDialog["关闭对话框"]
ShowConflict --> Exit
ShowUnknownError --> Exit
CloseDialog --> Exit
```
成功的响应会显示"循环任务创建完成"的消息并关闭对话框,而错误响应则会根据具体错误码显示相应的错误信息,如"此时段已创建其他任务"。
**图表来源**
- [NetRequestDialog.cpp](file://cpp/socket/NetRequestDialog.cpp#L37-L41)
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp#L387-L447)
**本节来源**
- [NetRequestDialog.cpp](file://cpp/socket/NetRequestDialog.cpp#L37-L41)
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp#L387-L447)
@@ -0,0 +1,265 @@
# 循环任务查询
<cite>
**本文档引用的文件**
- [DialLoopTaskQuery.cpp](file://cpp/Views/DialLoopTaskQuery.cpp)
- [DialLoopTaskQuery.h](file://h/DialLoopTaskQuery.h)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [TaskDataOper.h](file://h/TaskDataOper.h)
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h)
</cite>
## 目录
1. [引言](#引言)
2. [核心组件](#核心组件)
3. [架构概述](#架构概述)
4. [详细组件分析](#详细组件分析)
5. [依赖分析](#依赖分析)
6. [性能考虑](#性能考虑)
7. [故障排除指南](#故障排除指南)
8. [结论](#结论)
## 引言
本文档系统化地描述了Geomative Studio软件中循环任务查询功能的实现机制。重点分析了DialLoopTaskQuery对话框作为CDialog派生类的生命周期管理,包括其初始化流程、数据交换机制以及消息映射处理。文档详细阐述了CListCtrl控件在任务列表展示中的应用,以及STLoopTaskTable结构体在内存中的数据组织方式。同时,深入探讨了查询功能与数据库的交互逻辑,特别是如何通过CTaskDataOper组件访问tdTaskPacket和tdTaskPacketInfo表来获取循环任务数据。
## 核心组件
循环任务查询功能的核心组件是DialLoopTaskQuery对话框类,该类继承自MFC的CDialog类,负责提供用户界面以查询和选择循环任务。该对话框通过m_LoopTablelist成员变量管理内存中的循环任务数据,并使用m_ListLoopDisplay控件在界面上展示任务列表。当用户选择任务并点击查询按钮时,系统会将选中的任务ID存储在m_szArrayLoopTaskID数组中,并关闭对话框以返回主程序进行后续处理。
**本节来源**
- [DialLoopTaskQuery.cpp](file://cpp/Views/DialLoopTaskQuery.cpp#L1-L145)
- [DialLoopTaskQuery.h](file://h/DialLoopTaskQuery.h)
## 架构概述
循环任务查询功能的架构基于MFC对话框框架,采用经典的模型-视图-控制器(MVC)模式。DialLoopTaskQuery类作为视图和控制器,负责用户交互和界面展示;STLoopTaskTable结构体作为数据模型,定义了循环任务的数据结构;CTaskDataOper类作为数据访问层,负责与数据库进行交互。整个架构通过消息映射机制实现用户操作的响应,通过DoDataExchange实现控件与成员变量的数据绑定。
```mermaid
graph TB
subgraph "用户界面层"
DialLoopTaskQuery["DialLoopTaskQuery<br/>对话框类"]
end
subgraph "数据访问层"
TaskDataOper["CTaskDataOper<br/>数据操作类"]
end
subgraph "数据存储层"
Database["数据库<br/>tdTaskPacket表"]
end
DialLoopTaskQuery --> TaskDataOper
TaskDataOper --> Database
Database --> TaskDataOper
TaskDataOper --> DialLoopTaskQuery
```
**图表来源**
- [DialLoopTaskQuery.cpp](file://cpp/Views/DialLoopTaskQuery.cpp#L1-L145)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L1-L1450)
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L700-L706)
## 详细组件分析
### DialLoopTaskQuery类分析
DialLoopTaskQuery类是循环任务查询功能的核心实现,作为CDialog的派生类,它遵循MFC对话框的标准生命周期。
#### 类生命周期管理
DialLoopTaskQuery类的生命周期由MFC框架管理,遵循标准的构造、初始化、运行和析构流程。类的构造函数负责初始化成员变量,析构函数则负责清理资源。
```mermaid
classDiagram
class DialLoopTaskQuery {
+CStatic m_StaticLoopNum
+CListCtrl m_ListLoopDisplay
+CList<STLoopTaskTable> m_LoopTablelist
+CStringArray m_szArrayLoopTaskID
+DialLoopTaskQuery(CWnd* pParent)
+~DialLoopTaskQuery()
+OnInitDialog() bool
+DoDataExchange(CDataExchange* pDX)
+OnBnClickedQuerySubLoop()
+OnBnClickedCancel()
}
DialLoopTaskQuery --|> CDialog : "继承"
```
**图表来源**
- [DialLoopTaskQuery.h](file://h/DialLoopTaskQuery.h)
- [DialLoopTaskQuery.cpp](file://cpp/Views/DialLoopTaskQuery.cpp#L1-L145)
#### OnInitDialog初始化流程
OnInitDialog方法是对话框初始化的核心,负责设置界面控件的初始状态和加载数据。该方法首先调用基类的OnInitDialog进行基本初始化,然后配置CListCtrl控件的扩展样式,设置列标题,并根据m_LoopTablelist中的数据填充列表控件。
```mermaid
flowchart TD
Start([OnInitDialog入口]) --> SetExtendedStyle["设置CListCtrl扩展样式<br/>LVS_EX_FULLROWSELECT等"]
SetExtendedStyle --> SetStaticText["设置静态文本控件<br/>m_StaticLoopNum初始值为0"]
SetStaticText --> AddColumns["添加列表控件列<br/>任务名称、任务ID等"]
AddColumns --> CheckData["检查m_LoopTablelist<br/>是否有数据"]
CheckData --> |是| LoopData["遍历m_LoopTablelist<br/>填充列表控件"]
CheckData --> |否| SetTaskNum["设置任务数量为0"]
LoopData --> FormatTime["格式化时间显示<br/>使用Tm2LocalStr函数"]
FormatTime --> InsertItem["插入列表项<br/>SetItemText设置各列值"]
InsertItem --> UpdateTaskNum["更新任务数量显示"]
UpdateTaskNum --> End([返回TRUE])
SetTaskNum --> End
```
**图表来源**
- [DialLoopTaskQuery.cpp](file://cpp/Views/DialLoopTaskQuery.cpp#L82-L144)
#### DoDataExchange数据交换机制
DoDataExchange方法实现了对话框控件与类成员变量之间的数据交换,这是MFC数据绑定的核心机制。该方法使用DDX_Control宏将界面控件与类的成员变量关联起来,确保界面状态与程序数据的一致性。
```mermaid
sequenceDiagram
participant Framework as "MFC框架"
participant Dialog as "DialLoopTaskQuery"
Framework->>Dialog : OnInitDialog()
Dialog->>Dialog : CDialog : : OnInitDialog()
Dialog->>Dialog : DoDataExchange(pDX)
Dialog->>Dialog : DDX_Control(pDX, IDC_STATIC_LOOP_Q_NUM, m_StaticLoopNum)
Dialog->>Dialog : DDX_Control(pDX, IDC_LIST_QUERY, m_ListLoopDisplay)
Dialog->>Framework : 控件与成员变量绑定完成
```
**图表来源**
- [DialLoopTaskQuery.cpp](file://cpp/Views/DialLoopTaskQuery.cpp#L29-L34)
#### 消息映射处理
消息映射机制使DialLoopTaskQuery类能够响应用户的操作。通过BEGIN_MESSAGE_MAP宏定义,将特定的Windows消息映射到相应的处理函数。当用户点击"查询"或"取消"按钮时,框架会自动调用对应的处理函数。
```mermaid
flowchart LR
A["用户点击查询按钮"] --> B["WM_COMMAND消息"]
B --> C["MFC框架查找消息映射"]
C --> D["找到ON_BN_CLICKED(IDOK_QUERY_SUB_LOOP)"]
D --> E["调用OnBnClickedQuerySubLoop函数"]
E --> F["处理查询逻辑"]
F --> G["关闭对话框"]
H["用户点击取消按钮"] --> I["WM_COMMAND消息"]
I --> J["MFC框架查找消息映射"]
J --> K["找到ON_BN_CLICKED(IDCANCEL)"]
K --> L["调用OnBnClickedCancel函数"]
L --> M["清理资源"]
M --> N["关闭对话框"]
```
**图表来源**
- [DialLoopTaskQuery.cpp](file://cpp/Views/DialLoopTaskQuery.cpp#L37-L40)
### CListCtrl控件应用分析
m_ListLoopDisplay是CListCtrl类型的控件,用于在界面上展示循环任务列表。该控件通过插入列和设置项文本的方式组织和显示数据。
#### 任务列表展示机制
CListCtrl控件通过多列列表的形式展示任务信息,每行代表一个循环任务,每列代表任务的一个属性。控件的初始化和数据填充在OnInitDialog方法中完成。
```mermaid
erDiagram
TASK ||--o{ COLUMN : "包含"
TASK {
string 任务名称
string 任务ID
string 任务类型
string 开始时间
string 结束时间
}
COLUMN {
string 列标题
int 列宽度
int 对齐方式
}
DISPLAY : "m_ListLoopDisplay"
DISPLAY --> TASK : "显示"
DISPLAY --> COLUMN : "管理"
```
**图表来源**
- [DialLoopTaskQuery.cpp](file://cpp/Views/DialLoopTaskQuery.cpp#L90-L137)
### STLoopTaskTable结构体分析
STLoopTaskTable结构体定义了循环任务在内存中的数据组织方式,是连接界面展示和数据库存储的关键数据模型。
#### 内存数据组织
STLoopTaskTable结构体包含了循环任务的所有必要信息,通过CList模板类进行管理,形成一个任务列表。
```mermaid
classDiagram
class STLoopTaskTable {
+char ucTaskID[40]
+char ucTaskName[40]
+BYTE ucLoopType
+UINT32 uiStartTime
+UINT32 uiEndTime
}
class CList {
+AddHead()
+AddTail()
+RemoveAll()
+GetHeadPosition()
+GetNext()
}
CList<STLoopTaskTable> --|> CList : "模板实例化"
CList<STLoopTaskTable> --> STLoopTaskTable : "存储"
```
**图表来源**
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L700-L706)
- [DialLoopTaskQuery.h](file://h/DialLoopTaskQuery.h#L28)
### 数据库交互逻辑分析
循环任务查询功能通过CTaskDataOper组件与数据库进行交互,获取循环任务的相关数据。
#### 查询功能与数据库交互
查询功能通过CTaskDataOper类的QueryTaskPacketInfo方法访问数据库,获取tdTaskPacketInfo表中的任务信息,并将其转换为STTdBrowseInfo结构体数组。
```mermaid
sequenceDiagram
participant Dialog as "DialLoopTaskQuery"
participant DataOper as "CTaskDataOper"
participant Database as "数据库"
Dialog->>DataOper : QueryTaskPacketInfo(vtTdBrowseInfo)
DataOper->>Database : SELECT * FROM tdTaskPacketInfo
Database-->>DataOper : 返回任务数据
DataOper->>DataOper : 转换为STTdBrowseInfo数组
DataOper-->>Dialog : 填充vtTdBrowseInfo
Dialog->>Dialog : 将数据加载到m_LoopTablelist
```
**图表来源**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L1112-L1139)
- [TaskDataOper.h](file://h/TaskDataOper.h#L308-L306)
## 依赖分析
循环任务查询功能依赖于多个核心组件和外部资源。主要依赖包括MFC框架提供的对话框和控件类、CTaskDataOper数据操作类、全局应用程序对象theApp以及数据库连接。这些依赖关系确保了功能的完整性和稳定性。
```mermaid
graph TD
DialLoopTaskQuery --> CDialog
DialLoopTaskQuery --> CListCtrl
DialLoopTaskQuery --> CStatic
DialLoopTaskQuery --> CTaskDataOper
DialLoopTaskQuery --> theApp
CTaskDataOper --> ADODB
CTaskDataOper --> Database
theApp --> NetworkOper
theApp --> Connection
```
**图表来源**
- [DialLoopTaskQuery.cpp](file://cpp/Views/DialLoopTaskQuery.cpp#L10-L13)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L25-L38)
## 性能考虑
循环任务查询功能在性能方面主要考虑数据加载效率和界面响应速度。由于任务列表数据通常不会太大,因此采用一次性加载所有数据的方式。通过合理设置CListCtrl控件的扩展样式,如LVS_EX_GRIDLINES和LVS_EX_FULLROWSELECT,提升了用户体验。在数据交换过程中,使用_bstr_t类型转换确保了字符串处理的效率。
## 故障排除指南
当循环任务查询功能出现问题时,可以按照以下步骤进行排查:
1. 检查数据库连接是否正常
2. 验证tdTaskPacket和tdTaskPacketInfo表是否存在且有数据
3. 确认m_LoopTablelist是否正确填充了数据
4. 检查OnInitDialog方法中的列设置是否正确
5. 验证消息映射是否正确配置
**本节来源**
- [DialLoopTaskQuery.cpp](file://cpp/Views/DialLoopTaskQuery.cpp#L55-L58)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L79-L81)
## 结论
循环任务查询功能通过DialLoopTaskQuery对话框实现了用户友好的任务选择界面。该功能充分利用了MFC框架的特性,通过标准的对话框生命周期管理、数据交换机制和消息映射,实现了稳定可靠的用户交互。内存中的STLoopTaskTable结构体和CList容器有效组织了任务数据,而CTaskDataOper组件则确保了与数据库的高效交互。整体设计遵循了良好的软件工程原则,具有良好的可维护性和扩展性。
@@ -0,0 +1,292 @@
# 循环任务管理
<cite>
**本文档引用的文件**
- [DialLoopTaskQuery.cpp](file://cpp/Views/DialLoopTaskQuery.cpp)
- [DialLoopTaskQuery.h](file://h/DialLoopTaskQuery.h)
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp)
- [DialManageLoopTask.h](file://h/DialManageLoopTask.h)
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp)
- [DialUploadLoopTask.h](file://h/DialUploadLoopTask.h)
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h)
</cite>
## 目录
1. [引言](#引言)
2. [循环任务查询](#循环任务查询)
3. [循环任务管理](#循环任务管理)
4. [循环任务上传](#循环任务上传)
5. [数据结构与协议](#数据结构与协议)
6. [生命周期与同步机制](#生命周期与同步机制)
7. [异常处理与数据完整性](#异常处理与数据完整性)
8. [与PLC状态监控的集成](#与plc状态监控的集成)
9. [结论](#结论)
## 引言
循环任务管理功能是Geomative Studio系统中的核心模块之一,负责实现定时任务的创建、查询、管理和批量上传。该功能通过三个主要界面组件实现:`DialLoopTaskQuery`(任务查询)、`DialManageLoopTask`(任务管理)和`DialUploadLoopTask`(任务上传)。这些组件共同构成了一个完整的循环任务生命周期管理系统,支持用户对设备端的定时测量任务进行精细化控制。
系统通过网络协议与设备端通信,实现任务信息的双向同步。任务数据结构设计考虑了时间控制、执行策略、子任务调度等多个维度,确保任务能够在指定时间窗口内按预定规则执行。同时,系统集成了PLC状态监控功能,确保任务执行环境的稳定性。
**本文档来源**
- [DialLoopTaskQuery.cpp](file://cpp/Views/DialLoopTaskQuery.cpp#L1-L145)
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp#L1-L621)
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp#L1-L532)
## 循环任务查询
`DialLoopTaskQuery`组件提供了循环任务的查询功能,允许用户从设备端获取已存在的循环任务列表。该组件通过`CListCtrl`控件展示任务信息,包括任务名称、任务ID、任务类型、开始时间和结束时间等关键字段。
在初始化过程中,组件通过`OnInitDialog`方法设置列表控件的列标题和显示样式。由于该组件仅用于查询和选择任务,其核心逻辑集中在`OnBnClickedQuerySubLoop`事件处理函数中。当用户选择一个或多个任务并点击确认按钮时,系统会将选中的任务ID存储在`m_szArrayLoopTaskID`数组中,并关闭对话框,将选择结果返回给调用方。
该组件的设计体现了单一职责原则,专注于任务查询功能,不涉及任务的创建或修改操作。通过与`STLoopTaskTable`数据结构的绑定,实现了任务信息的结构化展示。
**本文档来源**
- [DialLoopTaskQuery.cpp](file://cpp/Views/DialLoopTaskQuery.cpp#L82-L144)
- [DialLoopTaskQuery.h](file://h/DialLoopTaskQuery.h#L29)
## 循环任务管理
`DialManageLoopTask`组件提供了循环任务的管理功能,包括任务的删除和详细信息查看。该组件继承自`CNetRequestDialog`,具备网络请求处理能力,能够与设备端进行双向通信。
组件的核心功能包括:
- **任务列表初始化**:通过`InitLoopTaskList`方法向设备端发送`EN_REQ_DOWNLOAD_LOOP_TABLE`命令,获取指定时间范围内的循环任务列表。
- **任务删除**:用户选择一个或多个任务后,点击删除按钮,系统会向设备端发送`EN_CANCEL_LOOP_TASK_TRUST`命令,请求删除选中的循环任务。
- **子任务查看**:当用户点击某个循环任务时,系统会发送`EN_REQ_DOWNLOAD_LOOP_SUB_TABLE`命令,获取该循环任务包含的子任务列表。
该组件使用`std::map<CString, STLoopTaskTable>`数据结构`m_mapSaveLoopList`来缓存从设备端获取的任务列表,提高了数据访问效率。同时,通过`CRITICAL_SECTION`临界区对象`m_cs`确保多线程环境下的数据安全。
**本文档来源**
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp#L230-L621)
- [DialManageLoopTask.h](file://h/DialManageLoopTask.h#L63)
## 循环任务上传
`DialUploadLoopTask`组件提供了新建循环任务的功能,允许用户配置任务参数并上传到设备端。该组件提供了丰富的用户界面元素,包括组合框、日期时间选择器和编辑框,用于收集任务配置信息。
任务创建流程包括以下关键步骤:
1. **参数收集**:从用户界面收集任务名称、循环类型(次数循环或定时循环)、循环次数、开始时间、结束时间、每日开始时间和任务间隔等参数。
2. **数据验证**:对用户输入进行验证,确保循环次数在1-60000范围内,结束时间不早于开始时间。
3. **数据结构填充**:将验证后的参数填充到`STLoopTaskInfo`数据结构中,并进行网络字节序转换。
4. **任务上传**:通过`PostNetRequest`方法发送`EN_REQ_LOOP_TASK_TRUST`命令,将任务信息上传到设备端。
该组件还支持子任务的拖拽排序功能,通过`DragMoveItem`消息处理函数实现。用户可以通过拖拽调整子任务的执行顺序,系统会按照调整后的顺序生成任务ID列表并上传。
**本文档来源**
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp#L180-L378)
- [DialUploadLoopTask.h](file://h/DialUploadLoopTask.h#L42)
## 数据结构与协议
循环任务管理功能依赖于一系列精心设计的数据结构和通信协议。核心数据结构包括:
### STLoopTaskTable
该结构体用于表示循环任务的基本信息,包括:
- `ucTaskID`:任务ID
- `ucTaskName`:任务名称
- `ucLoopType`:循环类型(0:一次, 1:按天, 2:按月, 3:按周)
- `uiStartTime`:开始测试时间
- `uiEndTime`:结束测试时间
### STLoopTaskInfo
该结构体用于表示循环任务的详细配置信息,包含:
- `ucTaskID`:循环任务名
- `ucTaskName`:循环备用任务名
- `uiPlcId`PLC设备ID
- `uiGD10Id`GD10设备ID
- `ucContrlType`:控制类型(0:次数循环, 1:定时循环)
- `uiLoopNum`:循环次数
- `uiStartTime`:开始测试时间
- `uiEndTime`:结束测试时间
- `uiStartMin`:每天或每周相对0点开始的分钟数
- `uiTaskSpace`:任务间间隔(秒)
- `uiSubTaskNum`:子任务数
### 通信协议
系统定义了专门的网络命令用于循环任务管理:
- `EN_REQ_LOOP_TASK_TRUST` (0x58):请求创建循环任务
- `EN_CANCEL_LOOP_TASK_TRUST` (0x59):请求取消循环任务
- `EN_REQ_DOWNLOAD_TASK_ARG` (0x73):请求下载任务参数
- `EN_REQ_DOWNLOAD_LOOP_TABLE` (0x77):请求下载循环任务表
- `EN_REQ_DOWNLOAD_LOOP_SUB_TABLE` (0x78):请求下载循环子任务表
这些数据结构和协议共同构成了循环任务管理功能的基础,确保了任务信息在客户端和设备端之间的一致性和完整性。
```mermaid
classDiagram
class STLoopTaskTable {
+char ucTaskID[40]
+char ucTaskName[40]
+BYTE ucLoopType
+UINT32 uiStartTime
+UINT32 uiEndTime
}
class STLoopTaskInfo {
+char ucTaskID[40]
+char ucTaskName[60]
+UINT32 uiPlcId
+UINT32 uiGD10Id
+BYTE ucContrlType
+BYTE ucTimerType
+UINT16 uiLoopNum
+UINT16 uiRemainLoopNum
+BYTE ucLoopType
+BYTE ucTimerAgsNum
+BYTE ucTimerTimeAgs
+UINT32 uiStartTime
+UINT32 uiEndTime
+UINT32 uiStartMin
+UINT32 uiTaskSpace
+UINT32 uiSubTaskNum
}
class STTaskListItem {
+char szTaskID[40]
+char szTDName[60]
+BYTE byTestStatus
+EN_TASK_LOCAL_STATUSE eSynStatus
}
class EN_TASK_LOCAL_STATUSE {
<<enumeration>>
EN_TASK_NO_UPLOAD = 0
EN_TASK_NO_DOWNLOAD
EN_TASK_YES_SYN
}
class EN_TASK_SERVER_STATUSE {
<<enumeration>>
EN_TASK_STATE_NO_TRUST = 0
EN_TASK_STATE_TESTING
EN_TASK_STATE_STOP_TEST = 20
EN_TASK_STATE_TEST_FAILED = 30
EN_TASK_STATE_FINISH = 40
}
STLoopTaskInfo --> STTaskListItem : "包含"
STTaskListItem --> EN_TASK_LOCAL_STATUSE : "引用"
STLoopTaskInfo --> EN_TASK_SERVER_STATUSE : "引用"
```
**图表来源**
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L705-L729)
- [CtrlProtocolDef.h](file://h/CtrlProtocolDef.h#L698)
## 生命周期与同步机制
循环任务的生命周期管理涉及创建、查询、执行和删除四个阶段,每个阶段都有相应的同步机制确保数据一致性。
### 创建阶段
当用户通过`DialUploadLoopTask`创建新任务时,系统会生成唯一的任务ID,格式为"LOOPYYYYMMDDHHMMSS_任务名"。这个ID结合了时间戳和任务名,确保全局唯一性。创建请求通过`EN_REQ_LOOP_TASK_TRUST`命令发送到设备端,设备端验证参数合法性后返回响应。
### 查询阶段
`DialManageLoopTask`组件通过分页机制查询任务列表。初始查询时间范围为当前时间前30天到当前时间后1小时,如果查询结果跨越多天,则按5天为单位分批加载,避免单次请求数据量过大。
### 执行阶段
任务执行由设备端的PLC控制器负责调度。系统通过`STLoopTaskInfo`中的`uiStartMin``uiTaskSpace`参数精确控制任务的启动时间和间隔。任务执行状态通过`EN_TASK_SERVER_STATUSE`枚举值反映,包括测试中、测试停止、测试失败和完成等状态。
### 删除阶段
任务删除操作是不可逆的。当用户请求删除任务时,系统会向设备端发送`EN_CANCEL_LOOP_TASK_TRUST`命令,设备端验证后删除任务并释放相关资源。删除操作会同时清除任务的所有子任务和测量数据。
整个生命周期中,系统通过网络请求-响应模式确保操作的原子性。每个关键操作都有对应的日志记录,便于故障排查和审计。
```mermaid
sequenceDiagram
participant 用户 as 用户界面
participant 客户端 as 客户端应用
participant 设备端 as 设备端
用户->>客户端 : 创建循环任务
客户端->>设备端 : 发送EN_REQ_LOOP_TASK_TRUST
设备端-->>客户端 : 返回创建结果
客户端->>用户 : 显示创建结果
用户->>客户端 : 查询循环任务
客户端->>设备端 : 发送EN_REQ_DOWNLOAD_LOOP_TABLE
设备端-->>客户端 : 返回任务列表
客户端->>用户 : 显示任务列表
用户->>客户端 : 删除循环任务
客户端->>设备端 : 发送EN_CANCEL_LOOP_TASK_TRUST
设备端-->>客户端 : 返回删除结果
客户端->>用户 : 显示删除结果
设备端->>设备端 : 按计划执行任务
设备端->>客户端 : 推送任务状态更新
客户端->>用户 : 更新界面显示
```
**图表来源**
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp#L376)
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp#L250)
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp#L172)
## 异常处理与数据完整性
系统在循环任务管理过程中实施了多层次的异常处理和数据完整性保障措施。
### 输入验证
在任务创建过程中,系统对所有用户输入进行严格验证:
- 任务名称不能为空
- 循环次数必须在1-60000范围内
- 结束时间不能早于开始时间
- 任务ID必须符合命名规范
### 网络通信保障
系统通过以下机制确保网络通信的可靠性:
- **请求重试**:关键操作支持重试机制,避免因网络抖动导致操作失败
- **超时控制**:设置合理的请求超时时间,防止长时间等待
- **错误码处理**:根据设备端返回的错误码进行针对性处理,如`FAILED_CREATE_LOOP_DURING_THIS_PERIOD`表示该时间段已存在其他任务
### 数据一致性
为确保数据一致性,系统采用以下策略:
- **事务性操作**:关键操作(如任务删除)设计为原子操作,要么全部成功,要么全部失败
- **状态同步**:通过`EN_TASK_LOCAL_STATUSE``EN_TASK_SERVER_STATUSE`两个状态枚举,分别维护本地和服务器端的任务状态,确保状态同步
- **日志记录**:所有关键操作都记录到日志文件中,便于问题追踪和审计
### 内存管理
系统在内存管理方面也做了精心设计:
- 使用`std::map``CList`等容器管理任务列表,提供高效的查找和遍历能力
- 通过`CRITICAL_SECTION`保护共享数据,避免多线程竞争
- 及时释放不再使用的资源,防止内存泄漏
这些措施共同确保了循环任务管理功能的稳定性和可靠性。
**本文档来源**
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp#L186-L271)
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp#L264-L268)
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp#L409-L418)
## 与PLC状态监控的集成
循环任务管理功能与PLC状态监控系统深度集成,确保任务执行环境的稳定性和可靠性。
### 状态依赖
循环任务的执行依赖于PLC的运行状态。系统通过`OperPLC`模块获取PLC的实时状态,只有在PLC处于正常工作状态时才允许启动新的测量任务。这种依赖关系避免了在设备异常情况下执行任务导致的数据错误或设备损坏。
### 状态同步
系统实现了PLC状态与循环任务状态的双向同步:
- 当PLC状态发生变化时,系统会更新相关任务的状态
- 当循环任务状态发生变化时,系统会向PLC发送相应的控制指令
### 故障处理
在PLC出现故障时,系统会采取以下措施:
- 暂停正在执行的循环任务
- 记录故障信息和时间戳
- 向用户发出告警通知
- 在PLC恢复正常后,根据配置决定是否恢复任务执行
### 参数传递
循环任务的配置参数会通过特定的通信协议传递给PLC,包括:
- 任务ID和名称
- 执行时间计划
- 测量参数和阈值
- 异常处理策略
这种集成设计确保了上位机软件与下位机控制器之间的协调工作,提高了整个系统的自动化水平和可靠性。
**本文档来源**
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp#L130-L133)
- [DialUploadLoopTask.cpp](file://cpp/Views/DialUploadLoopTask.cpp#L133-L136)
## 结论
循环任务管理功能通过`DialLoopTaskQuery``DialManageLoopTask``DialUploadLoopTask`三个核心组件,实现了完整的任务生命周期管理。系统采用分层架构设计,将用户界面、业务逻辑和数据访问分离,提高了代码的可维护性和可扩展性。
数据结构设计充分考虑了实际应用场景,`STLoopTaskInfo`等结构体包含了任务执行所需的所有参数。通信协议设计简洁高效,通过少量的命令码实现了复杂的功能需求。
异常处理机制完善,从输入验证到网络通信再到数据一致性,每个环节都有相应的保障措施。与PLC状态监控的深度集成,确保了任务执行的可靠性和安全性。
该功能模块的设计体现了工业控制系统对稳定性、可靠性和安全性的高要求,为地质勘探设备的自动化测量提供了坚实的基础。
@@ -0,0 +1,292 @@
# 循环任务管理界面
<cite>
**本文档引用的文件**
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [DataMngStruct.h](file://h/DataMngStruct.h)
- [NetRequestDialog.h](file://cpp/socket/NetRequestDialog.h)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构概述](#架构概述)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
## 简介
本文档深入解析循环任务管理界面的UI架构与交互逻辑,基于DialManageLoopTask类的实现。该对话框是Geomative Studio软件中用于管理定时循环任务的核心组件,提供了任务创建、编辑、删除等核心操作功能。文档重点分析了界面与底层数据模型的绑定机制,用户操作事件(如按钮点击)的处理流程,以及如何通过消息映射与CTaskDataOper服务层进行通信。同时,文档化了界面状态管理策略,包括任务列表的动态刷新机制和用户输入验证逻辑。
## 项目结构
循环任务管理功能主要分布在Views和Operator两个模块中。Views模块包含用户界面相关的实现,而Operator模块则负责数据操作和业务逻辑处理。核心文件DialManageLoopTask.cpp位于cpp/Views目录下,实现了循环任务管理对话框的完整功能。
```mermaid
graph TB
subgraph "Views"
A[DialManageLoopTask.cpp]
B[DialLoopTaskQuery.cpp]
C[DialUploadLoopTask.cpp]
end
subgraph "Operator"
D[TaskDataOper.cpp]
end
subgraph "Socket"
E[NetRequestDialog.h]
end
A --> D
A --> E
B --> D
C --> D
```
**Diagram sources**
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [NetRequestDialog.h](file://cpp/socket/NetRequestDialog.h)
**Section sources**
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
## 核心组件
循环任务管理界面的核心组件是CDialManageLoopTask类,它继承自CNetRequestDialog,实现了循环任务的管理功能。该组件集成了任务列表显示、子任务管理、任务删除等核心操作。通过与CTaskDataOper服务层的通信,实现了与底层数据模型的绑定。组件使用了消息映射机制来处理用户操作事件,如按钮点击和列表项选择。
**Section sources**
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
## 架构概述
循环任务管理界面采用典型的MVCModel-View-Controller)架构模式。视图层由CDialManageLoopTask类实现,负责用户界面的展示和用户交互。控制层通过消息映射处理用户操作,调用服务层进行数据操作。模型层由CTaskDataOper类提供,负责与数据库的交互和业务逻辑处理。
```mermaid
classDiagram
class CDialManageLoopTask {
+CListCtrl m_LoopTaskList
+CListCtrl m_subtaskList
+CEdit m_editLoopTaskName
+CEdit m_editPLCID
+CEdit m_editGDID
+OnInitDialog()
+OnBnClickedBtnDeleteLoopTask()
+OnBnClickedOk()
+OnNMClickListLoopTaskList()
+InitLoopTaskList()
+PreNetResponse()
}
class CTaskDataOper {
+Create1DTask()
+Create2DTask()
+Create3DTask()
+InsertTaskPacketInfo()
+InsertPlcStatusData()
+QueryARByTdID()
+QuerySptByAR()
}
class CNetRequestDialog {
+PostNetRequest()
+PreNetResponse()
+DoDataExchange()
}
CDialManageLoopTask --> CTaskDataOper : "uses"
CDialManageLoopTask --> CNetRequestDialog : "inherits"
```
**Diagram sources**
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [NetRequestDialog.h](file://cpp/socket/NetRequestDialog.h)
## 详细组件分析
### CDialManageLoopTask类分析
CDialManageLoopTask类是循环任务管理界面的核心实现,负责管理用户界面和用户交互。该类通过继承CNetRequestDialog获得了网络请求处理能力,能够与服务器进行通信获取和更新任务数据。
#### 用户界面初始化
在OnInitDialog方法中,组件初始化了两个列表控件:m_LoopTaskList用于显示循环任务列表,m_subtaskList用于显示选中任务的子任务列表。根据当前语言设置,组件会动态设置界面文本,支持中文和英文两种语言。
```mermaid
flowchart TD
Start([OnInitDialog]) --> SetLanguage["设置界面语言"]
SetLanguage --> CreateList["创建任务列表控件"]
CreateList --> SetColumn["设置列表列"]
SetColumn --> InitData["初始化循环任务列表"]
InitData --> Return["返回TRUE"]
```
**Diagram sources**
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp#L60-L136)
#### 任务删除功能
OnBnClickedBtnDeleteLoopTask方法处理删除按钮的点击事件。当用户选择一个或多个任务并点击删除按钮时,该方法会收集选中任务的ID,通过PostNetRequest发送删除请求到服务器,并在收到成功响应后从界面列表中移除相应任务。
```mermaid
sequenceDiagram
participant User as "用户"
participant UI as "CDialManageLoopTask"
participant Network as "CNetRequestDialog"
participant Server as "服务器"
User->>UI : 点击删除按钮
UI->>UI : 获取选中任务
UI->>Network : PostNetRequest(EN_CANCEL_LOOP_TASK_TRUST)
Network->>Server : 发送删除请求
Server-->>Network : 返回响应
Network->>UI : PreNetResponse
UI->>UI : 更新界面列表
UI-->>User : 显示操作结果
```
**Diagram sources**
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp#L138-L193)
#### 任务选择与详情显示
OnNMClickListLoopTaskList方法处理任务列表项的点击事件。当用户点击某个任务时,该方法会更新右侧的详细信息显示,并通过PostNetRequest请求该任务的子任务列表数据。
```mermaid
flowchart TD
Click["点击任务列表项"] --> GetTaskID["获取任务ID"]
GetTaskID --> UpdateUI["更新界面显示"]
UpdateUI --> RequestSubTask["PostNetRequest(EN_REQ_DOWNLOAD_LOOP_SUB_TABLE)"]
RequestSubTask --> WaitResponse["等待服务器响应"]
WaitResponse --> ShowSubTask["显示子任务列表"]
```
**Diagram sources**
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp#L202-L228)
**Section sources**
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp#L1-L621)
### CTaskDataOper服务层分析
CTaskDataOper类是数据操作的核心服务层,负责与数据库的交互和业务逻辑处理。该类提供了创建不同类型任务、查询任务信息、插入任务包信息等方法。
#### 任务创建功能
Create1DTask、Create2DTask和Create3DTask方法分别用于创建一维、二维和三维任务。这些方法通过ADO数据库操作,将任务信息插入到相应的数据库表中。
```mermaid
classDiagram
class CTaskDataOper {
+Create1DTask(ST1DTaskParam)
+Create2DTask(ST2DTaskParam)
+Create3DTask(ST3DTaskParam)
+InsertTaskPacketInfo()
+InsertPlcStatusData()
+QueryARByTdID()
+QuerySptByAR()
}
class ST1DTaskParam {
+strTDName
+iSptID
+strTestPlace
+iStacking
+iTxWave
+iTxPeriod
+iSAInterval
}
class ST2DTaskParam {
+strTDName
+iSptID
+strTestPlace
+iStartElec
+iEndElec
+iEAmount
+iStacking
+iTxWave
+iTxPeriod
+iSAInterval
+iCableLayout
+iSkipCable
+iRollCnt
+fEspace
+fHoleSpace
+ucTestGRFlag
}
class ST3DTaskParam {
+strTDName
+iSptID
+strTestPlace
+iStacking
+iTxWave
+iTxPeriod
+iSAInterval
+iCableLayout
+iSkipCable
+ucTestGRFlag
}
CTaskDataOper --> ST1DTaskParam : "uses"
CTaskDataOper --> ST2DTaskParam : "uses"
CTaskDataOper --> ST3DTaskParam : "uses"
```
**Diagram sources**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L97-L667)
#### 任务包信息管理
InsertTaskPacketInfo方法用于插入任务包信息,包括循环次数、间隔时间和PLC ID等。该方法通过事务处理确保数据的一致性。
```mermaid
flowchart TD
Start["开始插入任务包信息"] --> BeginTrans["开始数据库事务"]
BeginTrans --> DeleteOld["删除旧的任务包信息"]
DeleteOld --> InsertMain["插入主任务包信息"]
InsertMain --> DeleteOldInfo["删除旧的任务包详情"]
DeleteOldInfo --> InsertDetails["插入任务包详情"]
InsertDetails --> Commit["提交事务"]
Commit --> End["完成"]
Commit --> Rollback["回滚事务"]
```
**Diagram sources**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L669-L715)
**Section sources**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L1-L4455)
## 依赖分析
循环任务管理界面依赖于多个核心组件和服务。主要依赖关系包括:
```mermaid
graph TD
A[CDialManageLoopTask] --> B[CTaskDataOper]
A --> C[CNetRequestDialog]
A --> D[CFileOperTools]
B --> E[theApp.m_pConnection]
B --> F[theApp.m_NetWorkOper]
C --> G[theApp.m_NetWorkOper]
A --> H[g_iUILanguage]
A --> I[theApp]
style A fill:#f9f,stroke:#333
style B fill:#bbf,stroke:#333
style C fill:#f96,stroke:#333
```
**Diagram sources**
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [NetRequestDialog.h](file://cpp/socket/NetRequestDialog.h)
**Section sources**
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp#L1-L621)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L1-L4455)
## 性能考虑
循环任务管理界面在设计时考虑了多个性能因素。首先,任务列表的加载采用了分页机制,每次只加载指定时间范围内的任务,避免一次性加载过多数据导致界面卡顿。其次,网络请求采用了异步处理模式,通过消息映射机制在后台线程中处理网络通信,避免阻塞UI线程。此外,界面更新采用了增量更新策略,只更新发生变化的部分,减少不必要的重绘操作。
## 故障排除指南
在使用循环任务管理界面时,可能会遇到以下常见问题:
1. **任务列表无法加载**:检查网络连接是否正常,确保服务器正在运行。
2. **删除任务失败**:确认任务是否正在执行中,正在执行的任务无法删除。
3. **界面显示异常**:尝试重启应用程序,清除可能的界面状态错误。
4. **语言显示错误**:检查g_iUILanguage全局变量的设置是否正确。
**Section sources**
- [DialManageLoopTask.cpp](file://cpp/Views/DialManageLoopTask.cpp#L1-L621)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L1-L4455)
## 结论
循环任务管理界面通过CDialManageLoopTask类的实现,提供了一个功能完整、交互友好的任务管理解决方案。该界面成功地将UI展示、用户交互和数据操作分离,遵循了良好的软件设计原则。通过与CTaskDataOper服务层的紧密协作,实现了对循环任务的全生命周期管理。未来可以考虑增加任务批量操作、更丰富的筛选条件和导出功能,进一步提升用户体验。
@@ -0,0 +1,268 @@
# 离线任务管理
<cite>
**本文档引用的文件**
- [DialTaskManagerOffline.cpp](file://cpp/Views/DialTaskManagerOffline.cpp)
- [DialTaskTreeOffline.cpp](file://cpp/Views/DialTaskTreeOffline.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [DialTaskManagerOffline.h](file://h/DialTaskManagerOffline.h)
- [DialTaskTreeOffline.h](file://h/DialTaskTreeOffline.h)
- [FileTransfer.cpp](file://cpp/Tools/FileTransfer.cpp)
- [FileTransfer.h](file://h/FileTransfer.h)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构概述](#架构概述)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
## 简介
本文档详细描述了Geomative Studio软件中离线模式下的任务管理功能。该功能允许用户在没有网络连接的情况下创建、编辑、删除和同步测量任务。文档重点介绍了DialTaskManagerOffline和DialTaskTreeOffline组件的实现逻辑,以及与在线模式的差异。同时,文档还涵盖了离线任务数据的本地存储策略、与设备的批量传输协议(FileTransfer模块)和冲突解决机制。
## 项目结构
项目结构显示了离线任务管理功能相关的文件主要分布在cpp/Views和h/目录下,其中核心实现文件为DialTaskManagerOffline.cpp和DialTaskTreeOffline.cpp,头文件为DialTaskManagerOffline.h和DialTaskTreeOffline.h。数据操作相关的功能则在cpp/Operator/TaskDataOper.cpp中实现。
```mermaid
graph TD
A[离线任务管理] --> B[DialTaskManagerOffline]
A --> C[DialTaskTreeOffline]
A --> D[TaskDataOper]
A --> E[FileTransfer]
B --> F[任务创建]
B --> G[任务删除]
B --> H[任务测量]
C --> I[任务树显示]
C --> J[任务选择]
D --> K[数据库操作]
D --> L[任务数据查询]
E --> M[文件传输]
E --> N[数据同步]
```
**图表来源**
- [DialTaskManagerOffline.cpp](file://cpp/Views/DialTaskManagerOffline.cpp)
- [DialTaskTreeOffline.cpp](file://cpp/Views/DialTaskTreeOffline.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [FileTransfer.cpp](file://cpp/Tools/FileTransfer.cpp)
**章节来源**
- [DialTaskManagerOffline.cpp](file://cpp/Views/DialTaskManagerOffline.cpp)
- [DialTaskTreeOffline.cpp](file://cpp/Views/DialTaskTreeOffline.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
## 核心组件
离线任务管理功能的核心组件包括DialTaskManagerOffline和DialTaskTreeOffline两个类。DialTaskManagerOffline负责任务的创建、删除和测量等操作,而DialTaskTreeOffline则负责任务树的显示和用户交互。这些组件通过TaskDataOper类与数据库进行交互,实现任务数据的持久化存储。
**章节来源**
- [DialTaskManagerOffline.cpp](file://cpp/Views/DialTaskManagerOffline.cpp)
- [DialTaskTreeOffline.cpp](file://cpp/Views/DialTaskTreeOffline.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
## 架构概述
离线任务管理的架构采用MVC模式,其中DialTaskManagerOffline和DialTaskTreeOffline作为视图层,负责用户界面的显示和交互;TaskDataOper作为模型层,负责数据的存储和查询;而控制器逻辑则分散在各个组件中。这种架构使得界面和数据逻辑分离,提高了代码的可维护性。
```mermaid
classDiagram
class DialTaskManagerOffline {
+m_listTaskAttr ListCtrl
+m_listTaskData ListCtrl
+m_tabTaskChg TabCtrl
+m_dialTaskTreeOffline DialTaskTreeOffline
+m_taskOper TaskDataOper
+OnButtonCreateTask()
+OnButtonDelTask()
+OnButtonMeasureTask()
+OnClickTaskTree()
}
class DialTaskTreeOffline {
+m_treeTask TreeCtrl
+m_pParentWnd CWnd
+m_dwTaskID DWORD
+ShowTaskTree()
+OnSelchangedTreeTaskList()
}
class TaskDataOper {
+m_pRecTdData Recordset
+m_iTdType int
+m_bIsOpenTdData bool
+Create1DTask()
+Create2DTask()
+Create3DTask()
+DeleteTask()
+QueryTdAttrToCtrl()
+QueryTdDataToCtrl()
}
class FileTransfer {
+TransferFile()
+ReceiveFile()
+GetTransferStatus()
+CancelTransfer()
}
DialTaskManagerOffline --> DialTaskTreeOffline : "包含"
DialTaskManagerOffline --> TaskDataOper : "使用"
DialTaskManagerOffline --> FileTransfer : "使用"
DialTaskTreeOffline --> DialTaskManagerOffline : "通知"
```
**图表来源**
- [DialTaskManagerOffline.cpp](file://cpp/Views/DialTaskManagerOffline.cpp)
- [DialTaskTreeOffline.cpp](file://cpp/Views/DialTaskTreeOffline.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [FileTransfer.cpp](file://cpp/Tools/FileTransfer.cpp)
## 详细组件分析
### DialTaskManagerOffline分析
DialTaskManagerOffline类是离线任务管理的主要界面组件,负责处理用户对任务的各种操作。该组件通过消息映射机制响应用户界面事件,如创建任务、删除任务和开始测量等。
#### 任务创建流程
```mermaid
flowchart TD
Start([开始创建任务]) --> SelectType["选择任务类型(1D/2D/3D)"]
SelectType --> CreateDialog["创建相应任务对话框"]
CreateDialog --> ValidateInput["验证输入参数"]
ValidateInput --> InputValid{"输入有效?"}
InputValid --> |否| ShowError["显示错误信息"]
InputValid --> |是| CreateTask["调用TaskDataOper创建任务"]
CreateTask --> InsertTree["在任务树中插入新任务"]
InsertTree --> RefreshUI["刷新用户界面"]
RefreshUI --> End([任务创建完成])
ShowError --> End
```
**图表来源**
- [DialTaskManagerOffline.cpp](file://cpp/Views/DialTaskManagerOffline.cpp#L62-L112)
#### 任务删除流程
```mermaid
sequenceDiagram
用户->>DialTaskManagerOffline : 点击删除按钮
DialTaskManagerOffline->>DialTaskManagerOffline : 验证是否选择了任务
alt 未选择任务
DialTaskManagerOffline-->>用户 : 显示"请先选择任务"提示
else 已选择任务
DialTaskManagerOffline->>TaskDataOper : 调用DeleteTask方法
TaskDataOper->>数据库 : 执行删除SQL语句
alt 删除成功
数据库-->>TaskDataOper : 返回成功
TaskDataOper-->>DialTaskManagerOffline : 返回成功
DialTaskManagerOffline->>DialTaskTreeOffline : 从任务树中删除节点
DialTaskManagerOffline-->>用户 : 显示"删除任务成功"
else 删除失败
数据库-->>TaskDataOper : 返回错误
TaskDataOper-->>DialTaskManagerOffline : 返回失败
DialTaskManagerOffline-->>用户 : 显示"删除任务失败"
end
end
```
**图表来源**
- [DialTaskManagerOffline.cpp](file://cpp/Views/DialTaskManagerOffline.cpp#L114-L157)
**章节来源**
- [DialTaskManagerOffline.cpp](file://cpp/Views/DialTaskManagerOffline.cpp)
### DialTaskTreeOffline分析
DialTaskTreeOffline类负责任务树的显示和用户交互。它作为一个独立的对话框控件,被嵌入到DialTaskManagerOffline中,提供任务的层次化视图。
#### 任务树初始化流程
```mermaid
flowchart TD
Start([初始化任务树]) --> GetTaskType["获取任务类型"]
GetTaskType --> QueryTasks["调用TaskDataOper查询任务"]
QueryTasks --> CreateRoot["创建根节点"]
CreateRoot --> LoopTasks["遍历任务列表"]
LoopTasks --> CreateNode["为每个任务创建树节点"]
CreateNode --> SetNodeData["设置节点数据(任务ID)"]
SetNodeData --> AddNode["将节点添加到树中"]
AddNode --> CheckMore["还有更多任务?"]
CheckMore --> |是| LoopTasks
CheckMore --> |否| ExpandRoot["展开根节点"]
ExpandRoot --> End([任务树初始化完成])
```
**图表来源**
- [DialTaskTreeOffline.cpp](file://cpp/Views/DialTaskTreeOffline.cpp#L60-L65)
#### 任务选择通知流程
```mermaid
sequenceDiagram
用户->>DialTaskTreeOffline : 选择任务树节点
DialTaskTreeOffline->>DialTaskTreeOffline : 获取选中节点的任务ID
DialTaskTreeOffline->>DialTaskManagerOffline : 发送WM_CLICK_TASK_TREE消息
DialTaskManagerOffline->>TaskDataOper : 调用QueryTdAttrToCtrl
TaskDataOper->>数据库 : 查询任务属性
数据库-->>TaskDataOper : 返回任务属性
TaskDataOper-->>DialTaskManagerOffline : 设置任务属性到界面
DialTaskManagerOffline->>TaskDataOper : 调用QueryTdDataToCtrl
TaskDataOper->>数据库 : 查询任务数据
数据库-->>TaskDataOper : 返回任务数据
TaskDataOper-->>DialTaskManagerOffline : 设置任务数据到界面
DialTaskManagerOffline-->>用户 : 显示任务详细信息
```
**图表来源**
- [DialTaskTreeOffline.cpp](file://cpp/Views/DialTaskTreeOffline.cpp#L82-L102)
- [DialTaskManagerOffline.cpp](file://cpp/Views/DialTaskManagerOffline.cpp#L326-L335)
**章节来源**
- [DialTaskTreeOffline.cpp](file://cpp/Views/DialTaskTreeOffline.cpp)
- [DialTaskManagerOffline.cpp](file://cpp/Views/DialTaskManagerOffline.cpp)
## 依赖分析
离线任务管理功能依赖于多个组件和模块,形成了一个复杂的依赖网络。主要依赖关系包括:
```mermaid
graph TD
A[DialTaskManagerOffline] --> B[DialTaskTreeOffline]
A --> C[TaskDataOper]
A --> D[FileTransfer]
B --> A
C --> E[数据库]
D --> F[设备通信]
A --> G[TdManager]
C --> H[GUCodeCreator]
D --> I[Crc32]
A --> J[AutoLock]
style A fill:#f9f,stroke:#333
style B fill:#f9f,stroke:#333
style C fill:#f9f,stroke:#333
style D fill:#f9f,stroke:#333
```
**图表来源**
- [DialTaskManagerOffline.h](file://h/DialTaskManagerOffline.h)
- [DialTaskTreeOffline.h](file://h/DialTaskTreeOffline.h)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [FileTransfer.h](file://h/FileTransfer.h)
**章节来源**
- [DialTaskManagerOffline.h](file://h/DialTaskManagerOffline.h)
- [DialTaskTreeOffline.h](file://h/DialTaskTreeOffline.h)
## 性能考虑
离线任务管理功能在设计时考虑了性能因素,特别是在处理大量任务数据时。TaskDataOper类使用了数据库事务来确保数据操作的原子性,同时在查询大量数据时采用了分页机制。任务树的显示采用了懒加载策略,只有在用户展开节点时才加载子节点数据,减少了初始加载时间。
## 故障排除指南
当离线任务管理功能出现问题时,可以按照以下步骤进行排查:
1. 检查数据库连接是否正常
2. 验证任务数据文件是否完整
3. 检查用户权限设置
4. 查看日志文件中的错误信息
5. 确认设备通信是否正常
常见问题包括任务创建失败、任务数据无法加载和任务同步错误等。对于这些问题,应首先检查数据库状态和日志记录,然后根据具体错误信息进行针对性处理。
**章节来源**
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [DialTaskManagerOffline.cpp](file://cpp/Views/DialTaskManagerOffline.cpp)
## 结论
离线任务管理功能为Geomative Studio用户提供了一个完整的离线工作环境,使得在没有网络连接的情况下也能进行任务的创建、编辑和管理。通过DialTaskManagerOffline和DialTaskTreeOffline组件的协同工作,结合TaskDataOper的数据操作功能,实现了高效的任务管理。该功能的设计考虑了用户体验和性能优化,为地质勘探工作提供了可靠的支持。
@@ -0,0 +1,243 @@
# 项目与任务界面
<cite>
**本文档引用的文件**
- [taskmngframe.cpp](file://cpp\Views\taskmngframe.cpp)
- [taskmngframe.h](file://h\taskmngframe.h)
- [DialTaskTree.cpp](file://cpp\Views\DialTaskTree.cpp)
- [DialTaskTree.h](file://h\DialTaskTree.h)
- [DialNew1DTask.cpp](file://cpp\Views\DialNew1DTask.cpp)
- [DialNew2DTask.cpp](file://cpp\Views\DialNew2DTask.cpp)
- [DialNew3DTask.cpp](file://cpp\Views\DialNew3DTask.cpp)
- [TaskDataOper.cpp](file://cpp\Operator\TaskDataOper.cpp)
- [TaskDataOper.h](file://h\TaskDataOper.h)
- [DialTaskManager.cpp](file://cpp\Views\DialTaskManager.cpp)
- [DialTimerTask.cpp](file://cpp\Views\DialTimerTask.cpp)
- [DialManageLoopTask.cpp](file://cpp\Views\DialManageLoopTask.cpp)
- [DialLoopTaskQuery.cpp](file://cpp\Views\DialLoopTaskQuery.cpp)
- [DialUploadLoopTask.cpp](file://cpp\Views\DialUploadLoopTask.cpp)
</cite>
## 目录
1. [项目与任务管理概述](#项目与任务管理概述)
2. [任务管理框架结构](#任务管理框架结构)
3. [任务树形视图实现](#任务树形视图实现)
4. [任务创建与配置](#任务创建与配置)
5. [定时任务与循环任务管理](#定时任务与循环任务管理)
6. [任务数据持久化机制](#任务数据持久化机制)
7. [开发者技术指导](#开发者技术指导)
## 项目与任务管理概述
本系统提供全面的项目与任务管理功能,支持1D、2D和3D测量任务的创建、配置和管理。用户可以通过图形化界面完成从项目初始化到任务部署的完整操作流程。系统采用分层架构设计,核心功能包括任务管理框架、任务树形视图、任务配置对话框和任务调度逻辑。任务数据通过XML缓存和数据库同步机制实现持久化存储,确保数据的完整性和可靠性。
**Section sources**
- [taskmngframe.cpp](file://cpp\Views\taskmngframe.cpp#L1-L36)
- [taskmngframe.h](file://h\taskmngframe.h#L1-L47)
## 任务管理框架结构
任务管理框架(taskmngframe)是系统的核心组件,负责协调和管理所有任务相关的操作。该框架基于MFC的CMDIChildWnd类实现,提供多文档界面支持。框架的主要职责包括任务列表的显示、任务状态的更新、任务操作的处理以及与其他模块的通信。
任务管理框架通过消息映射机制处理用户交互事件,如任务创建、删除和刷新等操作。框架内部维护了任务操作器(TaskDataOper)的实例,用于执行具体的数据库操作和数据处理任务。框架还实现了网络响应处理,能够接收来自服务器的实时数据更新并相应地刷新界面。
```mermaid
classDiagram
class CTaskMngFrame {
+CTaskMngFrame()
+~CTaskMngFrame()
}
class CMDIChildWnd {
+Create()
+DestroyWindow()
}
CTaskMngFrame --|> CMDIChildWnd : 继承
```
**Diagram sources **
- [taskmngframe.cpp](file://cpp\Views\taskmngframe.cpp#L1-L36)
- [taskmngframe.h](file://h\taskmngframe.h#L1-L47)
**Section sources**
- [taskmngframe.cpp](file://cpp\Views\taskmngframe.cpp#L1-L36)
- [taskmngframe.h](file://h\taskmngframe.h#L1-L47)
## 任务树形视图实现
任务树形视图(DialTaskTree)是用户与任务数据交互的主要界面组件,基于MFC的CTreeCtrl控件实现。该视图以树形结构展示所有可用的任务,支持任务的筛选、排序和状态显示。视图实现了丰富的用户交互功能,包括右键菜单、复选框操作和点击事件处理。
树形视图通过网络请求从服务器获取任务列表数据,并将其组织成树形结构显示。视图支持按时间范围查询任务,能够分批加载大量任务数据以提高性能。每个任务节点包含任务ID、名称、状态等信息,并根据任务状态使用不同颜色的文字进行标识:测试中任务显示为蓝色,测试失败任务显示为红色。
视图实现了自定义绘制功能,通过OnNMCustomdrawTreeTaskList方法实现节点的自定义外观。视图还支持任务的批量操作,用户可以通过复选框选择多个任务进行统一处理。右键菜单提供了创建任务、删除任务、取消测试和刷新列表等常用操作。
```mermaid
sequenceDiagram
participant User as 用户
participant View as DialTaskTree
participant Oper as TaskDataOper
participant Server as 服务器
User->>View : 请求显示任务列表
View->>Oper : ShowTaskTree()
Oper->>Server : 发送任务查询请求
Server-->>Oper : 返回任务数据
Oper->>View : 处理任务数据
View->>View : 构建树形结构
View-->>User : 显示任务列表
```
**Diagram sources **
- [DialTaskTree.cpp](file://cpp\Views\DialTaskTree.cpp#L1-L686)
- [DialTaskTree.h](file://h\DialTaskTree.h#L1-L83)
**Section sources**
- [DialTaskTree.cpp](file://cpp\Views\DialTaskTree.cpp#L1-L686)
- [DialTaskTree.h](file://h\DialTaskTree.h#L1-L83)
## 任务创建与配置
系统提供专门的对话框用于创建和配置不同类型的任务,包括1D、2D和3D测量任务。每个任务类型都有对应的配置对话框,提供针对性的参数设置选项。
### 1D任务配置
1D任务配置对话框(DialNew1DTask)提供创建一维测量任务的界面。用户需要设置任务名称、测试地点、测试类型(电阻率、激电或自电)、装置类型、测试脚本、迭代次数、发射波形和发射周期等参数。对话框根据测试类型动态调整可用的发射周期选项,电阻率和激电测试支持多个周期选择,而自电测试则不支持周期设置。
```mermaid
flowchart TD
Start([开始]) --> InputTaskName["输入任务名称"]
InputTaskName --> SelectTestType["选择测试类型"]
SelectTestType --> CheckTestType{"测试类型?"}
CheckTestType --> |电阻率/激电| SetTxPeriod["设置发射周期"]
CheckTestType --> |自电| SkipTxPeriod["跳过发射周期"]
SetTxPeriod --> SetOtherParams["设置其他参数"]
SkipTxPeriod --> SetOtherParams
SetOtherParams --> ValidateInput["验证输入"]
ValidateInput --> CheckValid{"输入有效?"}
CheckValid --> |是| CreateTask["创建任务"]
CheckValid --> |否| ShowError["显示错误信息"]
ShowError --> InputTaskName
CreateTask --> End([结束])
```
**Diagram sources **
- [DialNew1DTask.cpp](file://cpp\Views\DialNew1DTask.cpp#L1-L381)
### 2D任务配置
2D任务配置对话框(DialNew2DTask)提供创建二维测量任务的界面。除了1D任务的基本参数外,2D任务还需要设置电缆布线方式、起始和结束电极、电极间距、孔间距(跨孔测量时)等参数。对话框根据装置类型自动调整界面元素的可见性,例如跨孔装置会显示孔间距输入框。
### 3D任务配置
3D任务配置对话框(DialNew3DTask)提供创建三维测量任务的界面。3D任务需要设置网格信息、步长、电极间距等参数。对话框能够根据选择的测试脚本自动填充网格大小信息,提高配置效率。
所有任务配置对话框都通过TaskDataOper类与数据库交互,创建任务记录并生成唯一的任务编号。任务编号遵循特定格式:ERI[任务类型][年月日时分秒]_SN[设备ID]。
**Section sources**
- [DialNew1DTask.cpp](file://cpp\Views\DialNew1DTask.cpp#L1-L381)
- [DialNew2DTask.cpp](file://cpp\Views\DialNew2DTask.cpp#L1-L665)
- [DialNew3DTask.cpp](file://cpp\Views\DialNew3DTask.cpp#L1-L570)
- [TaskDataOper.cpp](file://cpp\Operator\TaskDataOper.cpp#L97-L659)
- [TaskDataOper.h](file://h\TaskDataOper.h#L15-L112)
## 定时任务与循环任务管理
系统提供完善的定时任务和循环任务管理功能,支持自动化测量任务的创建和执行。定时任务允许用户在指定时间自动执行测量任务,而循环任务则支持按次数或时间间隔重复执行任务。
### 定时任务管理
定时任务通过DialTimerTask对话框进行管理。用户可以添加、删除和查看定时任务。每个定时任务包含任务名称、执行时间、PLC ID等信息。系统使用AddTimerTask方法将定时任务信息保存到数据库,并在指定时间自动触发任务执行。
```mermaid
classDiagram
class STTimerTask {
+UINT32 uiTaskID
+CString strTaskName
+CString strRunTime
+CString strPlcID
}
class CTaskDataOper {
+QueryTimerTaskValiad()
+AddTimerTask()
+DeleteTimerTask()
}
class CDialTimerTask {
+OnButtonAdd()
+OnButtonDel()
+OnButtonSave()
}
CTaskDataOper --> STTimerTask : 使用
CDialTimerTask --> CTaskDataOper : 调用
```
**Diagram sources **
- [DialTimerTask.cpp](file://cpp\Views\DialTimerTask.cpp#L1-L238)
- [TaskDataOper.h](file://h\TaskDataOper.h#L275-L288)
- [TaskDataOper.cpp](file://cpp\Operator\TaskDataOper.cpp#L401-L408)
### 循环任务管理
循环任务通过DialManageLoopTask对话框进行管理。循环任务支持两种模式:次数循环和定时循环。次数循环按指定次数重复执行任务,而定时循环则按指定时间间隔重复执行。用户可以查看循环任务的详细信息,包括子任务列表、执行状态和进度。
循环任务管理界面提供删除功能,用户可以选择一个或多个循环任务进行删除。删除操作通过发送EN_CANCEL_LOOP_TASK_TRUST网络请求实现,服务器收到请求后会取消相应的循环任务。
**Section sources**
- [DialTimerTask.cpp](file://cpp\Views\DialTimerTask.cpp#L1-L238)
- [DialManageLoopTask.cpp](file://cpp\Views\DialManageLoopTask.cpp#L1-L621)
- [DialLoopTaskQuery.cpp](file://cpp\Views\DialLoopTaskQuery.cpp#L1-L145)
- [DialUploadLoopTask.cpp](file://cpp\Views\DialUploadLoopTask.cpp#L72-L351)
## 任务数据持久化机制
系统采用XML缓存和数据库同步相结合的机制实现任务数据的持久化存储。核心数据存储在Access数据库中,而临时数据和缓存则使用XML文件格式。
### 数据库结构
任务相关数据主要存储在以下数据库表中:
- **td表**:存储任务基本信息,包括任务名称、类型、状态、创建时间等
- **tdchannel表**:存储任务通道信息,包括装置类型、电极配置等
- **tdxdcon表**:存储不同维度任务的具体测量点数据
- **tdTaskPacket表**:存储任务包信息,用于批量任务管理
TaskDataOper类提供了对这些数据库表的封装操作,包括任务的创建、查询、更新和删除。创建任务时,系统会同时在td表和tdchannel表中插入记录,并根据任务维度在相应的tdxdcon表中批量插入测量点数据。
### XML缓存机制
系统使用XML文件作为缓存机制,主要存储临时的任务列表和配置信息。CACHE目录下的project.xml和testzone.xml文件用于缓存项目和测区信息。这种设计提高了数据访问效率,减少了对数据库的频繁访问。
数据同步机制确保XML缓存与数据库内容保持一致。当数据库内容发生变化时,相关的XML缓存文件会被更新或重建。系统在启动时会优先读取XML缓存文件以提高加载速度,然后在后台与数据库进行同步验证。
**Section sources**
- [TaskDataOper.cpp](file://cpp\Operator\TaskDataOper.cpp#L97-L659)
- [TaskDataOper.h](file://h\TaskDataOper.h#L338-L448)
- [DialTaskManager.cpp](file://cpp\Views\DialTaskManager.cpp#L641-L664)
## 开发者技术指导
### 任务类型扩展
要扩展新的任务类型,开发者需要执行以下步骤:
1. 在TaskDataOper.h中定义新的任务参数结构体
2. 在TaskDataOper.cpp中实现相应的CreateTask方法
3. 在任务管理界面中添加新的任务类型选项
4. 更新数据库结构以支持新任务类型的特定字段
### 任务调度逻辑修改
任务调度逻辑主要在DialTimerTask和DialManageLoopTask类中实现。要修改调度逻辑,开发者可以:
1. 调整定时任务的触发条件和执行流程
2. 修改循环任务的间隔计算算法
3. 增加新的循环模式或执行策略
4. 优化任务状态检查和更新机制
### 任务数据持久化
任务数据持久化主要通过TaskDataOper类实现。开发者在修改数据持久化逻辑时应注意:
1. 保持数据库事务的完整性,确保数据一致性
2. 优化SQL查询语句,提高数据访问效率
3. 维护XML缓存与数据库的同步机制
4. 实现适当的错误处理和数据恢复机制
**Section sources**
- [TaskDataOper.cpp](file://cpp\Operator\TaskDataOper.cpp#L97-L659)
- [TaskDataOper.h](file://h\TaskDataOper.h#L338-L448)
- [DialTimerTask.cpp](file://cpp\Views\DialTimerTask.cpp#L1-L238)
- [DialManageLoopTask.cpp](file://cpp\Views\DialManageLoopTask.cpp#L1-L621)
@@ -0,0 +1,294 @@
# 1D项目创建
<cite>
**本文引用的文件**
- [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp)
- [DialNew1DTask.h](file://h/DialNew1DTask.h)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [TaskDataOper.h](file://h/TaskDataOper.h)
- [GeoMative.rc](file://GeoMative.rc)
- [DialTaskManager.cpp](file://cpp/Views/DialTaskManager.cpp)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考量](#性能考量)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本文件系统性地文档化1D项目创建流程,覆盖任务名称、测试位置、测试类型(电阻率/激电/自电)、装置类型、测试脚本、迭代次数、发射波形和发射周期等参数的配置;解释DialNew1DTask对话框的UI控件布局、数据验证逻辑与CTaskDataOper服务的交互机制;阐述不同测试类型对发射周期选项的动态影响,以及装置类型与脚本之间的关联查询逻辑;并为开发者提供界面元素扩展、参数验证规则定制与错误提示本地化的实现方法。
## 项目结构
1D项目创建涉及三个关键层次:
- 视图层:DialNew1DTask对话框负责用户输入与参数校验,并调用服务层接口创建任务。
- 服务层:CTaskDataOper封装数据库操作与业务逻辑,包括任务参数持久化、脚本与装置类型的关联查询等。
- 资源层:GeoMative.rc定义对话框控件布局与标签文本,支持多语言显示。
```mermaid
graph TB
subgraph "视图层"
D1["DialNew1DTask<br/>对话框"]
end
subgraph "服务层"
S1["CTaskDataOper<br/>任务数据操作"]
end
subgraph "资源层"
R1["GeoMative.rc<br/>控件布局/标签"]
end
D1 --> S1
D1 --- R1
```
图表来源
- [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp#L1-L120)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L97-L199)
- [GeoMative.rc](file://GeoMative.rc#L906-L929)
章节来源
- [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp#L1-L120)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L97-L199)
- [GeoMative.rc](file://GeoMative.rc#L906-L929)
## 核心组件
- DialNew1DTask:1D任务创建对话框,包含任务名称、测试地点、测试类型、装置类型、测试脚本、迭代次数、发射波形、发射周期等输入项;负责基础校验与调用服务层创建任务。
- CTaskDataOper:封装任务创建、脚本与装置类型关联查询、默认测区获取等逻辑;负责将任务参数写入数据库并返回新任务ID。
- GeoMative.rc:定义对话框控件ID与布局,支持中英文标签切换。
章节来源
- [DialNew1DTask.h](file://h/DialNew1DTask.h#L13-L71)
- [TaskDataOper.h](file://h/TaskDataOper.h#L12-L37)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L97-L199)
- [GeoMative.rc](file://GeoMative.rc#L906-L929)
## 架构总览
1D任务创建的端到端流程如下:
- 用户在DialNew1DTask中填写参数并点击“创建”。
- 对话框执行参数校验,组装ST1DTaskParam结构体。
- 调用CTaskDataOper::CreateTaskCN生成任务编号,再调用CTaskDataOper::Create1DTask持久化任务。
- 创建成功后返回新任务ID,对话框关闭。
```mermaid
sequenceDiagram
participant U as "用户"
participant V as "DialNew1DTask"
participant S as "CTaskDataOper"
participant DB as "数据库"
U->>V : 输入任务参数并点击“创建”
V->>V : 参数校验名称、测试类型、装置类型、脚本、迭代次数、发射周期
V->>S : CreateTaskCN(测试类型)
S-->>V : 返回任务编号
V->>S : Create1DTask(参数, 任务编号)
S->>DB : 插入td、tdchannel、td1dcon、gr等记录
DB-->>S : 返回新任务ID
S-->>V : 新任务ID
V-->>U : 关闭对话框
```
图表来源
- [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp#L239-L366)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L97-L199)
章节来源
- [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp#L239-L366)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L97-L199)
## 详细组件分析
### DialNew1DTask对话框
- 控件布局与标签
- 任务名称、测试地点、测试类型、装置类型、测试脚本、迭代次数、发射波形、发射周期。
- 支持中英文双语标签切换。
- 初始化逻辑
- 测试类型下拉框初始化为电阻率/激电/自电(中文或英文)。
- 装置类型下拉框通过CTaskDataOper::QueryMediumInfo加载介质信息。
- 发射波形默认固定为0+0-,不可编辑。
- 发射周期下拉框按2的幂次生成(1S、2S、4S、8S、16S、32S、64S),其中“自动”对应1S。
- 事件处理
- 装置类型变化:触发脚本下拉框重载,基于所选装置类型与脚本类型查询关联脚本。
- 测试类型变化:根据选择动态调整发射波形与发射周期可用性与内容。
- “创建”按钮:执行参数校验,组装ST1DTaskParam,调用服务层创建任务。
- 参数校验
- 任务名称非空。
- 必须选择测试类型。
- 必须选择装置类型。
- 必须选择测试脚本。
- 迭代次数必须为1~255整数。
- 电阻率/激电需选择发射周期;自电不启用发射周期。
- 采样间隔范围校验(0~30000)。
```mermaid
flowchart TD
Start(["进入对话框"]) --> Init["初始化控件<br/>加载测试类型/装置类型/发射周期"]
Init --> SelArray["选择装置类型"]
SelArray --> LoadSpt["查询关联脚本并填充下拉"]
SelArray --> ChangeType["选择测试类型"]
ChangeType --> DynaWave["动态设置发射波形"]
DynaWave --> DynaPeriod["动态设置发射周期项<br/>电阻率/激电可选;自电禁用"]
DynaPeriod --> ClickOK["点击“创建”"]
ClickOK --> Validate["参数校验<br/>名称/类型/装置/脚本/迭代次数/采样间隔"]
Validate --> Valid{"校验通过?"}
Valid -- 否 --> ShowErr["弹出错误提示并终止"]
Valid -- 是 --> CallSvc["调用服务层创建任务"]
CallSvc --> Done(["完成"])
```
图表来源
- [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp#L66-L165)
- [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp#L167-L237)
- [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp#L239-L366)
- [GeoMative.rc](file://GeoMative.rc#L906-L929)
章节来源
- [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp#L66-L165)
- [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp#L167-L237)
- [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp#L239-L366)
- [GeoMative.rc](file://GeoMative.rc#L906-L929)
### CTaskDataOper服务
- 任务创建
- CreateTaskCN:生成任务编号(含设备序列号与时间戳)。
- Create1DTask:插入td、tdchannel、td1dcon、gr等记录,返回新任务ID。
- 装置类型与脚本关联
- QuerySptByAR:根据装置类型ID与脚本类型查询可用脚本列表。
- QueryMediumInfo:查询介质(装置类型)列表。
- 默认测区
- GetDefaultTzID:获取默认测区ID。
```mermaid
classDiagram
class CTaskDataOper {
+CreateTaskCN(iTestType) CString
+Create1DTask(stTaskParam, strTaskCN) int
+QuerySptByAR(iAR, vtRes, iSptType) void
+QueryMediumInfo(iSptType, vtRes) void
+GetDefaultTzID() int
}
class ST1DTaskParam {
+strTDName
+strTestPlace
+iTestType
+iAR
+iSptID
+strSptName
+iSptType
+iStacking
+iTxWave
+iTxPeriod
+iSAInterval
}
CTaskDataOper --> ST1DTaskParam : "使用"
```
图表来源
- [TaskDataOper.h](file://h/TaskDataOper.h#L12-L37)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L97-L199)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L774-L791)
章节来源
- [TaskDataOper.h](file://h/TaskDataOper.h#L12-L37)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L97-L199)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L774-L791)
### 不同测试类型对发射周期的影响
- 电阻率:发射波形为0+0-,发射周期可选(1S、2S、4S、8S、16S、32S、64S),其中“自动”映射为1S。
- 激电:发射波形为+0-0,发射周期可选(1S、2S、4S、8S、16S、32S、64S)。
- 自电:发射波形为0,发射周期禁用且不选择。
章节来源
- [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp#L186-L237)
### 装置类型与脚本的关联查询逻辑
- 当用户选择装置类型后,对话框清空并重新加载脚本下拉框。
- 服务层根据装置类型ID与脚本类型查询关联脚本,填充下拉列表。
- 该逻辑确保仅展示与当前装置类型匹配的脚本。
章节来源
- [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp#L167-L184)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L774-L791)
### 与任务管理器的集成
- DialTaskManager在创建任务时,会将DialNew1DTask中的参数打包到任务参数结构中,随后调用服务层创建任务。
章节来源
- [DialTaskManager.cpp](file://cpp/Views/DialTaskManager.cpp#L253-L266)
## 依赖关系分析
- DialNew1DTask依赖CTaskDataOper进行数据查询与任务创建。
- 服务层依赖数据库连接与ADO记录集进行数据持久化。
- 资源层通过资源脚本定义控件布局与标签文本,支持多语言。
```mermaid
graph LR
D1["DialNew1DTask"] --> S1["CTaskDataOper"]
S1 --> DB["数据库"]
D1 --- RC["GeoMative.rc"]
```
图表来源
- [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp#L1-L40)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L97-L199)
- [GeoMative.rc](file://GeoMative.rc#L906-L929)
章节来源
- [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp#L1-L40)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L97-L199)
- [GeoMative.rc](file://GeoMative.rc#L906-L929)
## 性能考量
- 下拉框数据加载:装置类型与脚本查询应避免重复请求,建议在对话框初始化时一次性加载并缓存。
- 数据库事务:任务创建采用事务提交,异常回滚,保证一致性。
- UI响应:参数校验应在用户输入过程中及时反馈,减少无效提交。
## 故障排查指南
- 常见错误
- 未选择测试类型/装置类型/脚本:弹出相应提示并阻止提交。
- 迭代次数不在1~255范围内:提示范围错误。
- 采样间隔不在0~30000范围内:提示范围错误。
- 电阻率/激电未选择发射周期:提示必选项。
- 自电类型不启用发射周期:保持禁用状态。
- 服务端错误
- 查询脚本信息失败:提示查询失败并返回负值。
- 默认测区ID获取失败:提示获取失败。
- 数据库异常:捕获COM异常并回滚事务。
章节来源
- [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp#L239-L366)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L97-L199)
## 结论
DialNew1DTask通过清晰的UI布局与严格的参数校验,结合CTaskDataOper的服务能力,实现了1D项目的标准化创建流程。测试类型对发射周期的动态控制与装置类型到脚本的关联查询,确保了参数的一致性与可执行性。开发者可在现有基础上扩展界面元素、定制验证规则与增强本地化提示。
## 附录
### 开发者指南:界面元素扩展
- 在资源脚本中添加新的控件ID与布局,参考现有控件命名规范。
- 在对话框类中声明控件变量并在DoDataExchange中绑定。
- 在OnInitDialog中初始化控件状态与默认值。
- 在消息映射中添加事件处理函数,必要时调用服务层查询数据。
章节来源
- [GeoMative.rc](file://GeoMative.rc#L906-L929)
- [DialNew1DTask.h](file://h/DialNew1DTask.h#L13-L47)
- [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp#L43-L65)
### 开发者指南:参数验证规则定制
- 在OnOK中增加自定义校验分支,如范围检查、格式校验、互斥条件判断。
- 使用本地化字符串资源统一提示文案,便于多语言维护。
章节来源
- [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp#L239-L366)
### 开发者指南:错误提示本地化
- 将提示文案集中到资源脚本或字符串常量,通过语言标识切换显示。
- 统一使用消息框接口输出提示,确保用户体验一致。
章节来源
- [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp#L246-L251)
- [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp#L256-L262)
@@ -0,0 +1,157 @@
# 2D项目创建
<cite>
**本文档引用的文件**
- [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp)
- [DialNew2DTask.h](file://h/DialNew2DTask.h)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [TaskDataOper.h](file://h/TaskDataOper.h)
</cite>
## 目录
1. [简介](#简介)
2. [参数配置](#参数配置)
3. [控件交互逻辑](#控件交互逻辑)
4. [跨孔测量模式约束](#跨孔测量模式约束)
5. [测试脚本选择机制](#测试脚本选择机制)
6. [接地电阻测试选项](#接地电阻测试选项)
## 简介
2D项目创建功能是Geomative Studio软件中的核心功能之一,用于配置和创建二维地球物理勘探任务。该功能通过`DialNew2DTask`对话框实现,允许用户设置任务的各种参数,包括装置类型、电缆布线方式、电极间距、孔间距(跨孔测量)、起始/结束电极、采样间隔等。本文档详细说明了该功能的实现细节和交互逻辑。
**Section sources**
- [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp#L1-L665)
- [DialNew2DTask.h](file://h/DialNew2DTask.h#L1-L92)
## 参数配置
2D项目创建对话框提供了多个参数的配置选项,主要包括:
- **任务名称**:用户定义的任务标识名称
- **测试地点**:勘探任务的地理位置描述
- **测试方式**:包括电阻率(RES)、激电(IP)和自电(SP)三种模式
- **装置类型**:定义电极排列方式,如温纳、施伦贝谢等
- **测试脚本**:预定义的测量序列和参数配置
- **迭代次数**:测量数据的叠加次数,用于提高信噪比
- **发射周期**:电流发射的时间周期
- **电缆布线方式**:电缆的连接和部署方式
- **电极间距**:相邻电极之间的距离
- **采样间隔**:数据采集的时间间隔(毫秒)
这些参数共同定义了2D勘探任务的测量配置,确保数据采集的准确性和一致性。
**Section sources**
- [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp#L80-L237)
- [TaskDataOper.h](file://h/TaskDataOper.h#L40-L82)
## 控件交互逻辑
`DialNew2DTask`对话框中的控件具有复杂的交互逻辑,特别是装置类型变化时对脚本和电缆布线方式的动态过滤机制。
### 装置类型变化事件
当用户选择不同的装置类型时,系统会触发`OnSelchangeCombo2dArray`事件处理函数,该函数执行以下操作:
1. 清空测试脚本下拉框
2. 根据选定的装置类型查询可用的测试脚本
3. 动态填充测试脚本下拉框
4. 根据装置类型显示或隐藏孔间距输入框
```mermaid
flowchart TD
A[用户选择装置类型] --> B{装置类型为跨孔测量?}
B --> |是| C[显示孔间距输入框]
B --> |否| D[隐藏孔间距输入框]
E[查询对应装置类型的测试脚本] --> F[填充测试脚本下拉框]
G{装置类型为Geomative跨孔?} --> |是| H[禁用起始/结束电极输入]
G --> |否| I[启用起始/结束电极输入]
```
**Diagram sources**
- [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp#L239-L274)
### 测试方式变化事件
当测试方式(电阻率、激电、自电)发生变化时,系统会动态过滤电缆布线方式和发射周期选项:
- 电阻率模式:过滤掉激电专用的布线方式
- 激电模式:过滤掉电阻率专用的布线方式
- 自电模式:显示所有布线方式但禁用发射周期
```mermaid
flowchart TD
A[用户选择测试方式] --> B{测试方式为激电?}
B --> |是| C[过滤电阻率布线方式]
B --> |否| D{测试方式为电阻率?}
D --> |是| E[过滤激电布线方式]
D --> |否| F[显示所有布线方式]
G[更新发射周期选项] --> H[根据测试方式启用/禁用]
```
**Diagram sources**
- [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp#L312-L411)
## 跨孔测量模式约束
在跨孔测量模式下,系统对孔间距与电极间距存在严格的约束关系:
1. 当装置类型为跨孔测量(AR_CROSS_HOLE_TYPE)时,孔间距输入框会被显示
2. 系统会验证孔间距必须大于电极间距
3. 如果孔间距小于或等于电极间距,系统会弹出错误提示
```mermaid
flowchart TD
A["用户选择跨孔装置类型"] --> B["显示孔间距输入框"]
C["用户输入孔间距和电极间距"] --> D{"孔间距 > 电极间距?"}
D --> |是| E["参数有效,继续"]
D --> |否| F["显示错误提示: \"孔间距必须大于电极间距\""]
```
这种约束确保了跨孔测量的物理可行性,防止用户配置不合理的参数。
**Section sources**
- [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp#L530-L560)
## 测试脚本选择机制
当用户选择测试脚本后,系统会自动填充电极范围和层数,实现原理如下:
1. 调用`Query2DSptInfo`函数查询脚本的最小和最大层
2. 调用`QuerySptElecTpMount`函数查询脚本的电极数量和测量点数
3. 自动设置起始电极为1,结束电极为最大电极数
4. 填充起始层和结束层的值
```mermaid
sequenceDiagram
participant User as 用户
participant Dialog as DialNew2DTask对话框
participant TaskOper as CTaskDataOper
User->>Dialog : 选择测试脚本
Dialog->>TaskOper : Query2DSptInfo(iSptID)
TaskOper-->>Dialog : 返回最小/最大层
Dialog->>TaskOper : QuerySptElecTpMount(iSptID)
TaskOper-->>Dialog : 返回电极数量
Dialog->>Dialog : 设置起始电极为1
Dialog->>Dialog : 设置结束电极为最大电极数
Dialog->>Dialog : 填充层范围
```
**Diagram sources**
- [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp#L276-L309)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L986-L1019)
## 接地电阻测试选项
接地电阻测试选项具有以下默认行为和可配置性:
- **默认行为**:默认启用接地电阻测试(`((CButton*)GetDlgItem(IDC_IF_TEST_GR))->SetCheck(TRUE);`
- **用户可配置性**:用户可以通过复选框启用或禁用接地电阻测试
- **参数传递**:选中状态会作为`ucTestGRFlag`参数传递给任务创建函数
```mermaid
flowchart TD
A[对话框初始化] --> B[默认选中接地电阻测试]
C[用户操作] --> D{用户取消选中?}
D --> |是| E[ucTestGRFlag = 0]
D --> |否| F[ucTestGRFlag = 1]
G[创建任务] --> H[将ucTestGRFlag写入任务参数]
```
这种设计既保证了常规情况下进行接地电阻测试,又允许用户根据实际需求关闭该功能。
**Section sources**
- [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp#L233-L235)
- [TaskDataOper.h](file://h/TaskDataOper.h#L66-L80)
@@ -0,0 +1,317 @@
# 3D项目创建
<cite>
**本文引用的文件**
- [DialNew3DTask.cpp](file://cpp/Views/DialNew3DTask.cpp)
- [DialNew3DTask.h](file://h/DialNew3DTask.h)
- [TaskDataOper.h](file://h/TaskDataOper.h)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [DialTaskManager.cpp](file://cpp/Views/DialTaskManager.cpp)
- [DialCreateNew3DSpt.cpp](file://cpp/Views/DialCreateNew3DSpt.cpp)
- [DialCreateNew3DSpt.h](file://h/DialCreateNew3DSpt.h)
- [Script3D.cpp](file://cpp/ProblemZone/Script3D.cpp)
- [GeoMative.rc](file://GeoMative.rc)
- [Resource.h](file://Resource.h)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考量](#性能考量)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本文件系统性地文档化Geomative Studio中“3D项目创建”流程,重点覆盖:
- 三维网格信息(X/Y方向电极数量、电极步长、电极间距等)的配置与来源
- DialNew3DTask对话框如何基于选定的测试脚本自动计算并展示网格尺寸信息
- 三维测量中电缆布线方式的特殊要求与适配
- 发射周期、迭代次数等通用参数的继承与适配策略
- 三维测量任务参数结构体(ST3DTaskParam)与数据库存储的映射关系
- 任务创建成功后的ID返回机制
## 项目结构
围绕3D项目创建的关键文件组织如下:
- 视图层:DialNew3DTask3D任务创建对话框)、DialCreateNew3DSpt3D脚本创建对话框)
- 操作层:TaskDataOper(任务数据操作,含Create3DTask
- 脚本层:Script3D(脚本信息查询与展示)
- 资源与控件:GeoMative.rc、Resource.h(包含3D相关控件ID
```mermaid
graph TB
subgraph "视图层"
DNT["DialNew3DTask<br/>3D任务创建对话框"]
DCNS["DialCreateNew3DSpt<br/>3D脚本创建对话框"]
end
subgraph "操作层"
TDO["CTaskDataOper<br/>任务数据操作"]
end
subgraph "脚本层"
S3D["CScript3D<br/>脚本信息查询"]
end
subgraph "资源与控件"
RC["GeoMative.rc<br/>资源定义"]
RH["Resource.h<br/>控件ID常量"]
end
DNT --> TDO
DCNS --> S3D
DNT --> RC
DNT --> RH
DCNS --> RC
DCNS --> RH
```
图表来源
- [DialNew3DTask.cpp](file://cpp/Views/DialNew3DTask.cpp#L1-L120)
- [DialCreateNew3DSpt.cpp](file://cpp/Views/DialCreateNew3DSpt.cpp#L1-L120)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L549-L748)
- [Script3D.cpp](file://cpp/ProblemZone/Script3D.cpp#L1-L120)
- [GeoMative.rc](file://GeoMative.rc#L1662-L1681)
- [Resource.h](file://Resource.h#L759-L789)
章节来源
- [DialNew3DTask.cpp](file://cpp/Views/DialNew3DTask.cpp#L1-L120)
- [DialCreateNew3DSpt.cpp](file://cpp/Views/DialCreateNew3DSpt.cpp#L1-L120)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L549-L748)
- [Script3D.cpp](file://cpp/ProblemZone/Script3D.cpp#L1-L120)
- [GeoMative.rc](file://GeoMative.rc#L1662-L1681)
- [Resource.h](file://Resource.h#L759-L789)
## 核心组件
- DialNew3DTask:负责3D任务创建的用户交互,包括测试方式、装置类型、脚本选择、电缆布线方式、发射周期、采样间隔、迭代次数等,并将参数封装为ST3DTaskParam后交由CTaskDataOper执行创建。
- CTaskDataOper:提供Create3DTask接口,完成数据库插入、生成任务ID、写入td与tdchannel表、导入脚本点位信息等。
- CScript3D:提供脚本查询能力,用于获取脚本的Rect、PoleStep、PoleDistance、LineDirection等网格与布线相关信息。
- DialCreateNew3DSpt3D脚本创建对话框,承载X/Y网格大小、电极间距、迭代数、电缆方向等输入与绘制预览。
- 资源与控件:通过GeoMative.rc与Resource.h定义3D相关控件ID,确保UI一致性。
章节来源
- [DialNew3DTask.h](file://h/DialNew3DTask.h#L1-L51)
- [TaskDataOper.h](file://h/TaskDataOper.h#L85-L112)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L549-L748)
- [Script3D.cpp](file://cpp/ProblemZone/Script3D.cpp#L1-L120)
- [DialCreateNew3DSpt.h](file://h/DialCreateNew3DSpt.h#L83-L108)
- [GeoMative.rc](file://GeoMative.rc#L1662-L1681)
- [Resource.h](file://Resource.h#L759-L789)
## 架构总览
下图展示了3D任务创建从UI到数据库的端到端流程。
```mermaid
sequenceDiagram
participant 用户 as "用户"
participant DNT as "DialNew3DTask"
participant TDO as "CTaskDataOper"
participant DB as "数据库"
participant S3D as "CScript3D"
用户->>DNT : 选择测试方式/装置/脚本/布线方式/周期/采样间隔/迭代次数
DNT->>S3D : 查询脚本网格信息(Rect/PoleStep/PoleDistance/LineDirection)
S3D-->>DNT : 返回网格尺寸与步长/间距/方向
DNT->>DNT : 自动计算并显示网格信息
DNT->>TDO : Create3DTask(ST3DTaskParam, TaskCN)
TDO->>DB : 插入td表(含Rect/RectLoc/Espace/Edistance/Clayout等)
TDO->>DB : 插入tdchannel表
TDO->>DB : 批量导入脚本3D点位到td3dcon
TDO-->>DNT : 返回新任务ID
DNT-->>用户 : 创建成功并返回任务ID
```
图表来源
- [DialNew3DTask.cpp](file://cpp/Views/DialNew3DTask.cpp#L216-L306)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L549-L748)
- [Script3D.cpp](file://cpp/ProblemZone/Script3D.cpp#L1-L120)
章节来源
- [DialNew3DTask.cpp](file://cpp/Views/DialNew3DTask.cpp#L216-L306)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L549-L748)
- [Script3D.cpp](file://cpp/ProblemZone/Script3D.cpp#L1-L120)
## 详细组件分析
### DialNew3DTask3D任务创建对话框
- 功能要点
- 测试方式、装置类型、脚本、布线方式、发射周期、采样间隔、迭代次数等参数收集
- 基于脚本查询自动填充网格尺寸(X/Y方向电极数量、步长、间距、方向)
- 将参数封装为ST3DTaskParam并调用CTaskDataOper::Create3DTask
- 成功后返回新任务ID并在任务管理器中使用
- 关键逻辑路径
- 脚本选择事件:OnSelchangeCombo3dScript
- 通过QuerySptRectByARandSCname获取Rect、PoleStep、PoleDistance、LineDirection
- 解析并填充m_rcGridSize、m_fXElecStep、m_fYElecStep、m_fXElecDistance、m_fYElecDistance、m_byLineDirection
- 更新界面显示网络尺寸(X: right+1, Y: bottom+1
- OK事件:OnOK
- 参数校验(步长、任务名、测试方式、布线方式、迭代次数、发射周期、采样间隔)
- 组装ST3DTaskParam并调用Create3DTask
- 记录新任务ID并返回
- 三维网格参数映射
- X/Y方向电极数量:来自Rect解析后的right、bottom加一
- 电极步长:来自PoleStep(X、Y方向)
- 电极间距:来自PoleDistanceX、Y方向)
- 测线方向:来自LineDirection0:X方向,1:Y方向)
章节来源
- [DialNew3DTask.cpp](file://cpp/Views/DialNew3DTask.cpp#L216-L306)
- [DialNew3DTask.cpp](file://cpp/Views/DialNew3DTask.cpp#L411-L569)
- [DialNew3DTask.h](file://h/DialNew3DTask.h#L1-L51)
### CTaskDataOper3D任务创建与数据库映射
- Create3DTask流程
- 查询脚本基础信息(Eamount、TPamount、Rect、RectLoc、PoleStep、PoleDistance、CN、LineDirection
- 生成任务CN并开启事务
- 插入td表(含TDname、TDCN、Tlocation、TZID、SCID、SCCN、Sname、Stype、Ttype、Eamount、TPamount、CHamount、N、TRwave、TRfrequency、SAfrequency、Clayout、SkipCable、Espace、Edistance、rect、rect_loc、Cdate、Ctime、DESN、STime、ETime、TTimer、TdStatus、TestGRFlag、LineDirection、CreateTime
- 插入tdchannel表(TDID、CHnumber、AR
- 批量导入脚本3D点位到td3dcon
- 提交事务并返回任务ID
- 数据库字段与ST3DTaskParam映射要点
- ST3DTaskParam中的iSptID、iSptType、iTestType、iAR、iCableLayout、iStacking、iTxWave、iTxPeriod、iSAInterval、ucTestGRFlag等直接映射到td表对应字段
- 脚本查询返回的Rect、PoleStep、PoleDistance、LineDirection写入td表的rect、rect_loc、Espace、Edistance、LineDirection
- 任务ID通过查询td表最大ID返回
章节来源
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L549-L748)
- [TaskDataOper.h](file://h/TaskDataOper.h#L85-L112)
### DialCreateNew3DSpt3D脚本创建与网格输入
- 功能要点
- 输入X/Y网格大小、电极间距、迭代数、电缆方向等
- 初始化绘图板,根据输入更新X/Y电极数量、间距,并重绘
- 支持不同测量方法与装置类型的组合显示
- 关键参数
- m_uiXGridSize、m_uiYGridSizeX/Y方向电极数量
- m_fXPoleDistance、m_fYPoleDistanceX/Y方向电极间距
- m_uiIterationNumber:迭代次数
- m_comCableDirection:电缆方向(X或Y
章节来源
- [DialCreateNew3DSpt.cpp](file://cpp/Views/DialCreateNew3DSpt.cpp#L1-L200)
- [DialCreateNew3DSpt.cpp](file://cpp/Views/DialCreateNew3DSpt.cpp#L957-L966)
- [DialCreateNew3DSpt.h](file://h/DialCreateNew3DSpt.h#L83-L108)
### 3D脚本信息查询(CScript3D
- 作用:提供脚本Rect、PoleStep、PoleDistance、LineDirection等信息,供DialNew3DTask自动计算网格尺寸
- 影响:直接影响DialNew3DTask对话框中网格尺寸的显示与验证
章节来源
- [Script3D.cpp](file://cpp/ProblemZone/Script3D.cpp#L1-L120)
### 3D任务参数结构体(ST3DTaskParam)与数据库映射
- 结构体字段(节选)
- strTDName、strTestPlace、iTestType、iCableLayout、iAR、iSptID、strSptName、iSptType、iSkipCable、iStacking、iTxWave、iTxPeriod、iSAInterval、ucTestGRFlag
- 数据库存储映射
- td表字段与ST3DTaskParam字段一一对应,包括但不限于:Ttype、Clayout、N、TRwave、TRfrequency、SAfrequency、Espace、Edistance、rect、rect_loc、LineDirection、TestGRFlag、CreateTime等
- 任务ID返回
- 通过查询td表的最大ID返回新任务ID
章节来源
- [TaskDataOper.h](file://h/TaskDataOper.h#L85-L112)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L549-L748)
### DialTaskManager:参数继承与适配
- 在任务类型选择为3D时,DialTaskManager从DialNew3DTask读取参数并写入任务参数结构
- 关键参数继承
- 测试类型、发射周期、脚本ID、装置类型、布线方式、采样间隔、迭代次数
- 三维特有的电极步长、电极间距、网格尺寸、测线方向也从DialNew3DTask传递
章节来源
- [DialTaskManager.cpp](file://cpp/Views/DialTaskManager.cpp#L300-L341)
## 依赖分析
- DialNew3DTask依赖TaskDataOper进行脚本查询与任务创建
- TaskDataOper依赖数据库连接与ADO Recordset进行数据持久化
- DialCreateNew3DSpt与DialNew3DTask共同影响最终的网格与布线参数
- 资源文件GeoMative.rc与Resource.h为3D相关控件提供ID与布局
```mermaid
graph LR
DNT["DialNew3DTask"] --> TDO["CTaskDataOper"]
DNT --> S3D["CScript3D"]
DCNS["DialCreateNew3DSpt"] --> DNT
TDO --> DB["数据库"]
RC["GeoMative.rc"] --> DNT
RH["Resource.h"] --> DNT
```
图表来源
- [DialNew3DTask.cpp](file://cpp/Views/DialNew3DTask.cpp#L216-L306)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L549-L748)
- [Script3D.cpp](file://cpp/ProblemZone/Script3D.cpp#L1-L120)
- [GeoMative.rc](file://GeoMative.rc#L1662-L1681)
- [Resource.h](file://Resource.h#L759-L789)
章节来源
- [DialNew3DTask.cpp](file://cpp/Views/DialNew3DTask.cpp#L216-L306)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L549-L748)
- [Script3D.cpp](file://cpp/ProblemZone/Script3D.cpp#L1-L120)
- [GeoMative.rc](file://GeoMative.rc#L1662-L1681)
- [Resource.h](file://Resource.h#L759-L789)
## 性能考量
- 脚本查询与数据库访问
- DialNew3DTask在脚本切换时进行一次脚本信息查询,建议避免频繁重复查询
- TaskDataOper在Create3DTask中使用事务,减少多次提交带来的开销
- 网格尺寸计算
- 仅基于脚本返回的Rect/PoleStep/PoleDistance/LineDirection进行简单解析与显示,复杂度低
- UI更新
- DialCreateNew3DSpt在参数变化时触发重绘,建议在大量参数变更时合并更新以降低刷新频率
[本节为通用指导,无需特定文件引用]
## 故障排查指南
- 步长为空或格式错误
- 现象:OnOK中对步长进行非空与范围校验,若为空或越界会弹窗提示
- 处理:检查脚本PoleStep格式(X,Y),确保输入合法
- 任务名为空
- 现象:必填项校验失败
- 处理:填写任务名称后重试
- 测试方式/布线方式/脚本未选择
- 现象:必选项未选择导致校验失败
- 处理:按提示选择相应项
- 迭代次数越界
- 现象:范围校验失败
- 处理:将迭代次数调整至1~255范围内
- 发射周期未选择(电阻率/激电)
- 现象:测试方式切换时周期控件启用状态变化
- 处理:根据当前测试方式正确选择周期
- 采样间隔越界
- 现象:范围校验失败
- 处理:将采样间隔调整至0~30000范围内
- 任务创建失败
- 现象:Create3DTask返回负值
- 处理:检查数据库连接、事务回滚日志,确认脚本ID有效且数据库权限正常
章节来源
- [DialNew3DTask.cpp](file://cpp/Views/DialNew3DTask.cpp#L411-L569)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L549-L748)
## 结论
- 3D项目创建流程以DialNew3DTask为核心入口,结合脚本查询自动填充网格尺寸,确保X/Y方向电极数量、步长、间距与测线方向的一致性
- 电缆布线方式在不同测试方式下进行过滤与适配,保证三维测量的可行性
- 通用参数(发射周期、采样间隔、迭代次数)在对话框中进行严格校验,并在任务管理器中继承到最终任务参数
- ST3DTaskParam与数据库字段映射清晰,Create3DTask通过事务保障数据一致性,返回新任务ID供后续使用
[本节为总结,无需特定文件引用]
## 附录
### 3D网格参数与UI控件对照
- X方向电极数量:来自Rect解析后的right+1
- Y方向电极数量:来自Rect解析后的bottom+1
- X方向电极步长:来自PoleStep的X分量
- Y方向电极步长:来自PoleStep的Y分量
- X方向电极间距:来自PoleDistance的X分量
- Y方向电极间距:来自PoleDistance的Y分量
- 测线方向:来自LineDirection0:X方向,1:Y方向)
- 电缆方向:COMBOBOX控件(X或Y)
章节来源
- [DialNew3DTask.cpp](file://cpp/Views/DialNew3DTask.cpp#L216-L306)
- [GeoMative.rc](file://GeoMative.rc#L1662-L1681)
- [Resource.h](file://Resource.h#L759-L789)
@@ -0,0 +1,405 @@
# 项目创建与管理
<cite>
**本文档引用的文件**
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp)
- [Project.cpp](file://cpp/ProblemZone/Project.cpp)
- [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp)
- [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp)
- [DialNew3DTask.cpp](file://cpp/Views/DialNew3DTask.cpp)
- [opcreateprojectdlg.cpp](file://cpp/Views/opcreateprojectdlg.cpp)
- [opcreatetzdlg.cpp](file://cpp/Views/opcreatetzdlg.cpp)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
- [DataOperator.cpp](file://cpp/Operator/DataOperator.cpp)
</cite>
## 目录
1. [项目创建流程](#项目创建流程)
2. [项目类型对话框实现机制](#项目类型对话框实现机制)
3. [项目参数设置与测区定义](#项目参数设置与测区定义)
4. [项目数据模型与内存组织](#项目数据模型与内存组织)
5. [XML缓存与数据库同步](#xml缓存与数据库同步)
6. [项目类型扩展技术路径](#项目类型扩展技术路径)
## 项目创建流程
Geomative Studio的项目创建流程始于应用程序初始化阶段,在`GeoMative.cpp`中通过`InitInstance()`方法完成。系统首先建立与数据库的连接,然后初始化项目管理器(`CProManager`)、设备管理器(`CDevManager`)等核心组件。项目创建的核心入口是`CProManager::CreateProjectInDB()`方法,该方法通过显示`COpCreateProjectDlg`对话框收集用户输入的项目基本信息。
项目创建过程遵循严格的验证机制,首先检查项目名称是否已存在,若存在则提示用户"工程名称已经存在!"。项目信息包括工程编号(CN)、名称、描述、位置、日期、持续时间、监督员、管理员、负责人、品质保证员和标准等字段。系统支持自动生成唯一标识码(GUID)作为工程编号,确保项目标识的唯一性。
项目创建成功后,系统会自动为新项目创建默认测区(DefaultTestZone),并初始化相应的数据库记录。整个创建过程采用事务处理机制,确保数据的一致性和完整性。项目创建完成后,相关信息会被同步到缓存目录(CACHE/projects/)下的XML文件中,实现本地缓存与数据库的双重存储。
**Section sources**
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L159-L442)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L249-L341)
- [opcreateprojectdlg.cpp](file://cpp/Views/opcreateprojectdlg.cpp#L79-L115)
## 项目类型对话框实现机制
系统为不同维度的测量项目提供了专门的对话框实现,包括`DialNew1DTask``DialNew2DTask``DialNew3DTask`三个类,分别处理一维、二维和三维测量任务的创建。这些对话框类继承自MFC的`CDialog`基类,通过资源文件定义用户界面布局,并在运行时动态填充数据。
### 一维项目对话框(DialNew1DTask
`DialNew1DTask`对话框为用户提供了一维测量任务的配置界面。在`OnInitDialog()`方法中,系统初始化测试类型下拉框(电阻率、激电、自电),并从数据库查询可用的测量装置类型(AR)。用户选择装置类型后,系统会自动加载关联的测试脚本。发射周期选项支持从"自动"到64秒的多种选择,满足不同测量需求。
```mermaid
classDiagram
class CDialNew1DTask {
+m_strTaskName string
+m_strTestPlace string
+m_strSptName string
+m_iTestType int
+m_iAR int
+m_iSptID int
+m_iStacking int
+m_iTxWave int
+m_iTxPeriod int
+OnInitDialog() bool
+OnSelchangeCombo1dArray() void
+OnSelchangeCombo1dTestType() void
+OnOK() void
}
class CTaskDataOper {
+QueryMediumInfo() void
+QuerySptByAR() void
+Create1DTask() int
}
CDialNew1DTask --> CTaskDataOper : "uses"
```
**Diagram sources **
- [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp#L1-L381)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L97-L200)
### 二维项目对话框(DialNew2DTask
`DialNew2DTask`对话框提供了更复杂的二维测量配置功能。除了基本的测试参数外,还包含电缆布线方式、电极间距、孔间距等专业设置。系统根据选择的测试类型动态调整可用的电缆布线选项,例如电阻率测量和激电测量有不同的布线要求。对于交叉孔(Cross Hole)类型的测量,系统会显示孔间距设置字段。
```mermaid
classDiagram
class CDialNew2DTask {
+m_iCableLayout int
+m_iStatrLayer int
+m_iEndLayer int
+m_iStartElec int
+m_iEndElec int
+m_fEelcSpace float
+m_iSkipCable int
+m_iRollCnt int
+OnInitDialog() bool
+OnSelchangeCombo2dArray() void
+OnSelchangeCombo2dScript() void
+OnSelchangeCombo2dTestType() void
+OnOK() void
}
class CTaskDataOper {
+QueryCmInfo() void
+Query2DSptInfo() bool
+QuerySptElecTpMount() bool
+Create2DTask() int
}
CDialNew2DTask --> CTaskDataOper : "uses"
```
**Diagram sources **
- [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp#L1-L665)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L202-L400)
### 三维项目对话框(DialNew3DTask
`DialNew3DTask`对话框专为三维测量任务设计,提供了网格信息、步长设置等高级功能。用户选择测试脚本后,系统会自动解析并显示网格尺寸信息(X和Y方向的电极数量)。三维测量支持复杂的电极步长和距离设置,允许用户定义非均匀网格布局。
```mermaid
classDiagram
class CDialNew3DTask {
+m_rcGridSize CRect
+m_fXElecStep float
+m_fYElecStep float
+m_fXElecDistance float
+m_fYElecDistance float
+m_byLineDirection byte
+OnInitDialog() bool
+OnSelchangeCombo3dArray() void
+OnSelchangeCombo3dScript() void
+OnSelchangeCombo3dTestType() void
+OnOK() void
}
class CTaskDataOper {
+QuerySptRectByARandSCname() void
+Create3DTask() int
}
CDialNew3DTask --> CTaskDataOper : "uses"
```
**Diagram sources **
- [DialNew3DTask.cpp](file://cpp/Views/DialNew3DTask.cpp#L1-L570)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L402-L600)
**Section sources**
- [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp#L1-L381)
- [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp#L1-L665)
- [DialNew3DTask.cpp](file://cpp/Views/DialNew3DTask.cpp#L1-L570)
## 项目参数设置与测区定义
项目参数设置是测量任务创建过程中的关键环节,系统通过一系列验证规则确保输入数据的有效性。每个对话框的`OnOK()`方法都包含完整的参数验证逻辑,对必填字段进行空值检查,对数值范围进行边界验证。
### 参数验证规则
系统实施严格的参数验证机制:
- **任务名称**:不能为空,长度限制50个字符
- **迭代次数**:必须在1-255范围内
- **电极间距**:必须大于零
- **采样间隔**:必须在0-30000毫秒范围内
- **孔间距**:必须大于电极间距(仅交叉孔测量)
当用户输入不符合要求时,系统会弹出相应的错误提示,如"任务名不能为空"、"迭代次数的取值范围为1到255"等,并阻止任务创建过程继续执行。
### 测区定义机制
测区(Testing Zone)是项目的基本组成单元,系统通过`COpCreateTzDlg`对话框管理测区的创建。每个项目创建时都会自动包含一个默认测区。测区定义包含名称、位置、描述和创建日期等基本信息。系统在`ProManager.cpp`中通过`InsertDefaultTzToProject()`方法实现默认测区的自动创建。
测区与测量任务之间存在层级关系,一个项目可以包含多个测区,每个测区可以包含多个测量任务。这种层次结构通过数据库中的外键关系(PRID、TZID)来维护,确保数据的完整性和一致性。
```mermaid
flowchart TD
Start([开始创建任务]) --> ValidateInput["验证输入参数"]
ValidateInput --> InputValid{"参数有效?"}
InputValid --> |否| ReturnError["显示错误信息"]
InputValid --> |是| CheckDependencies["检查依赖项"]
CheckDependencies --> DependenciesValid{"依赖项有效?"}
DependenciesValid --> |否| HandleDependencyError["处理依赖错误"]
DependenciesValid --> |是| CreateTaskRecord["创建任务数据库记录"]
CreateTaskRecord --> CreateChannelRecord["创建通道记录"]
CreateChannelRecord --> ImportScriptData["导入脚本数据"]
ImportScriptData --> InsertGroundResistance["插入接地电阻信息"]
InsertGroundResistance --> CommitTransaction["提交事务"]
CommitTransaction --> End([任务创建完成])
ReturnError --> End
HandleDependencyError --> End
```
**Diagram sources **
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L97-L200)
- [opcreatetzdlg.cpp](file://cpp/Views/opcreatetzdlg.cpp#L54-L91)
**Section sources**
- [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp#L239-L365)
- [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp#L414-L664)
- [DialNew3DTask.cpp](file://cpp/Views/DialNew3DTask.cpp#L411-L568)
- [opcreatetzdlg.cpp](file://cpp/Views/opcreatetzdlg.cpp#L54-L91)
## 项目数据模型与内存组织
系统的项目数据模型基于面向对象设计,核心类包括`CProject``CTestingZone``CTask`等。这些类通过`CProManager`进行统一管理,并在内存中形成层次化的数据结构。
### 核心数据结构
`CProject`类封装了项目的所有属性,包括工程编号(CN)、名称、描述、位置、日期、持续时间、监督员、管理员、负责人、品质保证员和标准等。这些属性在构造函数中从数据库查询并初始化:
```mermaid
classDiagram
class CProject {
+m_szCN string
+m_szPRname string
+m_szDesc string
+m_szLocation string
+m_szPRdate string
+m_szDuration string
+m_szPS string
+m_szCS string
+m_szPM string
+m_szQAS string
+m_szStandard string
+m_dwID DWORD
+CProject(DWORD, _ConnectionPtr&) constructor
+~CProject() destructor
+ShowDetailInfo(CListCtrl&) bool
}
class CTestingZone {
+m_szCN string
+m_szTZname string
+m_szDesc string
+m_szLocation string
+m_szCdate string
+m_dwID DWORD
+m_dwPRID DWORD
+CTestingZone(DWORD, _ConnectionPtr&) constructor
+~CTestingZone() destructor
}
class CTask {
+m_strTDName string
+m_strTDCN string
+m_strTestPlace string
+m_iTZID int
+m_iSCID int
+m_strSCCN string
+m_strSptName string
+m_ucStype byte
+m_ucTtype byte
+m_iEamount int
+m_iTPmount int
+m_ucCHamount byte
+m_iN int
+m_ucTRwave byte
+m_ucTRfrequency byte
+m_iSAfrequency int
+m_strCdate string
+m_strCtime string
+m_tCreateTime time_t
+CTask(DWORD, _ConnectionPtr&) constructor
+~CTask() destructor
}
CProject --> CTestingZone : "1..*"
CTestingZone --> CTask : "1..*"
```
**Diagram sources **
- [Project.cpp](file://cpp/ProblemZone/Project.cpp#L1-L81)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L153-L182)
### 内存管理机制
系统采用智能缓存机制管理项目数据,通过`m_dmsLinkList`链表存储已加载的项目、测区和任务对象。`CProManager::GetDMS()`方法实现了对象的延迟加载和缓存重用:
1. 当请求特定数据对象时,首先在缓存链表中查找
2. 如果找到则直接返回缓存对象
3. 如果未找到则从数据库加载并创建新对象,然后加入缓存链表
这种机制避免了重复的数据库查询,提高了系统性能。同时,系统在应用程序退出时通过析构函数清理所有缓存对象,防止内存泄漏。
**Section sources**
- [Project.cpp](file://cpp/ProblemZone/Project.cpp#L1-L81)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L153-L182)
## XML缓存与数据库同步
系统采用XML文件作为本地缓存机制,与中央数据库保持同步。这种双重存储策略既保证了数据的持久性,又提高了本地访问性能。
### 缓存文件结构
项目相关的XML缓存文件存储在`CACHE/`目录下,主要包含:
- `project.xml`:项目基本信息
- `testzone.xml`:测区配置信息
- 任务特定的XML文件:测量任务参数
`project.xml`文件采用标准的XML格式,包含项目名称、编号、描述、位置、创建日期等元数据:
```xml
<?xml version="1.0" encoding="ansi"?>
<project>
<project_name>示例项目</project_name>
<cn>PRJ-2023-001</cn>
<description>项目描述</description>
<location>测量地点</location>
<create_date>2023-01-01</create_date>
<create_time>00:00:00</create_time>
<test_date>2023-01-01</test_date>
<test_time>00:00:00</test_time>
<duration>30</duration>
<PS>监督员姓名</PS>
<CS>管理员姓名</CS>
<PM>负责人姓名</PM>
<QA>品质保证员姓名</QA>
<standard>标准名称</standard>
<testzone_count>1</testzone_count>
<testzones/>
</project>
```
### 同步策略
系统在项目创建和修改时执行同步操作:
1. 首先在数据库中创建记录
2. 然后生成对应的XML缓存文件
3. 最后将文件传输到设备(如果连接)
同步过程采用事务控制,确保数据库和缓存的一致性。如果文件传输失败,系统会回滚数据库操作,保持数据完整性。`CreateProjectInDev()`方法负责处理项目到设备的同步,包括创建目录结构、生成XML文件和文件传输等步骤。
```mermaid
sequenceDiagram
participant User as "用户"
participant Dialog as "创建对话框"
participant TaskDataOper as "TaskDataOper"
participant Database as "数据库"
participant FileSystem as "文件系统"
User->>Dialog : 提交任务参数
Dialog->>TaskDataOper : 调用CreateXDTTask()
TaskDataOper->>Database : 开始事务
Database-->>TaskDataOper : 事务开始
TaskDataOper->>Database : 插入任务记录
Database-->>TaskDataOper : 记录ID
TaskDataOper->>Database : 插入通道记录
TaskDataOper->>Database : 导入脚本数据
TaskDataOper->>Database : 插入接地电阻
TaskDataOper->>FileSystem : 生成XML缓存
FileSystem-->>TaskDataOper : 文件创建成功
TaskDataOper->>Database : 提交事务
Database-->>TaskDataOper : 事务提交
TaskDataOper-->>Dialog : 返回任务ID
Dialog-->>User : 创建成功
```
**Diagram sources **
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L383-L447)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L148-L197)
**Section sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L383-L447)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L148-L197)
## 项目类型扩展技术路径
系统设计具有良好的可扩展性,开发者可以通过以下路径扩展项目类型和功能。
### 新增项目模板
要添加新的项目模板,需要执行以下步骤:
1. 在数据库的`medium`表中添加新的测量装置类型
2. 在相应的脚本表(`script1d``script2d``script3d`)中添加配套的测量脚本
3. 修改`QueryMediumInfo()`方法的查询逻辑,确保新模板能被正确检索
### 自定义参数字段
扩展自定义参数字段需要:
1. 修改数据库表结构,添加新的字段列
2. 更新`STXDTTaskParam`结构体,添加对应的成员变量
3. 在对话框资源文件中添加新的UI控件
4. 在`DoDataExchange()`方法中绑定新控件
5. 在`OnOK()`方法中添加参数验证逻辑
### 项目验证规则
自定义验证规则的实现方式:
1. 在对话框类中添加新的验证方法
2. 在`OnOK()`方法中调用验证方法
3. 使用`AfxMessageBox()``MessageBoxEx()`显示验证错误信息
4. 返回前阻止基类的`OnOK()`调用
### 扩展示例
以下是一个添加温度补偿参数的扩展示例:
```mermaid
classDiagram
class CDialNew2DTask {
+m_fTemperature float
+m_iCompensationMethod int
+AddTemperatureControls() void
+ValidateTemperature() bool
}
class ST2DTaskParam {
+fTemperature float
+iCompensationMethod int
}
CDialNew2DTask --> ST2DTaskParam : "包含"
```
开发者可以基于现有架构,通过类似的模式添加各种专业测量参数和验证规则,满足特定应用场景的需求。
**Section sources**
- [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp#L239-L365)
- [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp#L414-L664)
- [DialNew3DTask.cpp](file://cpp/Views/DialNew3DTask.cpp#L411-L568)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L97-L200)