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,118 @@
# Views模块
<cite>
**Referenced Files in This Document**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp)
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
- [taskmngframe.cpp](file://cpp/Views/taskmngframe.cpp)
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp)
- [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp)
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp)
- [CCrossHoleConfig2DMainDlg.cpp](file://cpp/crossHole/CCrossHoleConfig2DMainDlg.cpp)
- [CDialogLoggingWnd.cpp](file://cpp/logging/CDialogLoggingWnd.cpp)
- [CDragListCtrl.cpp](file://cpp/ctrl/CDragListCtrl.cpp)
</cite>
## 目录
1. [简介](#简介)
2. [主框架窗口设计](#主框架窗口设计)
3. [设备管理框架](#设备管理框架)
4. [任务管理框架](#任务管理框架)
5. [数据管理框架](#数据管理框架)
6. [对话框用户交互逻辑](#对话框用户交互逻辑)
7. [跨孔测量UI组件](#跨孔测量ui组件)
8. [测井功能UI](#测井功能ui)
9. [自定义控件实现](#自定义控件实现)
10. [UI消息映射机制](#ui消息映射机制)
## 简介
Views模块是GeomativeStudio项目的核心用户界面组件集合,负责实现所有UI相关的功能。该模块包含主框架窗口、设备管理、任务管理、数据管理等多个框架窗口,以及各种对话框和自定义控件。这些组件共同构成了应用程序的用户交互界面,通过MFC框架实现丰富的图形用户界面功能。
## 主框架窗口设计
主框架窗口由MainFrm.cpp实现,作为应用程序的主容器,管理所有子窗口和UI元素。该窗口继承自CMDIFrameWnd,支持多文档界面(MDI)架构。在OnCreate方法中,初始化了工具栏和状态栏,并创建了启动画面。主框架窗口通过成员变量m_pDataMngFrm、m_pDevMngFrm和m_pSptMngFrm分别管理数据管理、设备管理和任务管理框架窗口的实例。
消息映射系统处理各种用户操作,如菜单命令IDM_MNG_DATA_WIN、IDM_MNG_EXEC_WIN和IDM_MNG_DEV_WIN,分别用于显示数据管理、执行管理和设备管理窗口。当用户选择这些菜单项时,框架会检查相应窗口是否已存在,如果不存在则创建新的子窗口,否则激活已存在的窗口。
**Section sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L1-L800)
## 设备管理框架
设备管理框架由devmngframe.cpp实现,继承自CMDIChildWnd,作为MDI子窗口运行。该框架采用分割窗口设计,左侧为导航视图(CNavDevView),右侧为内容视图,根据设备状态动态切换显示内容。
框架通过m_splitter对象创建静态分割窗口,左侧显示设备树形结构,右侧根据设备状态显示不同的视图:在线设备显示CAppDevOLView,离线设备显示CAppDevView,无选择状态显示CBlankView。这种设计实现了灵活的UI布局,能够根据设备连接状态动态调整界面内容。
消息映射系统处理设备管理相关的各种操作,如IDM_OP_DE_REG_O_UPG(设备升级)、IDM_OP_DE_REG_O_MP(修改设备参数)和IDM_REM_GD10_TASK_MANAGER(远程任务管理)。ShowAppView方法根据设备状态决定显示哪个视图,并调用相应的操作类方法更新界面内容。
**Section sources**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L1-L800)
## 任务管理框架
任务管理框架由taskmngframe.cpp实现,同样继承自CMDIChildWnd。该框架的实现相对简单,目前仅包含基本的框架结构和消息映射,没有具体的UI元素或业务逻辑实现。
从代码结构看,该框架预留了扩展空间,但当前版本中未实现具体的功能。这表明任务管理功能可能在其他模块中实现,或者该框架将在后续版本中进一步开发。
**Section sources**
- [taskmngframe.cpp](file://cpp/Views/taskmngframe.cpp#L1-L36)
## 数据管理框架
数据管理框架由datamngframe.cpp实现,继承自CMDIChildWnd,采用与设备管理框架类似的分割窗口设计。左侧为CNavDataView导航视图,右侧为内容视图,根据数据类型动态切换。
框架支持多种数据类型的管理,包括2D电阻率数据(CAppDataRsp2DTdView)、2D激电数据(CAppDataIpsp2DTdView)、3D电阻率数据(CAppDataRsp3DTdView)等。ShowAppView和ShowContentListByPageView方法根据数据类型和状态决定显示哪个视图,并调用CDataOperator操作类的方法加载和显示数据。
消息映射系统处理数据管理的各种操作,如IDM_OP_TD_2DRSP_DB_D(删除2D电阻率数据)、IDM_OP_TD_2DRSP_DB_EXCEL(导出2D电阻率数据到Excel)和IDM_OP_TD_2DRSP_DB_GRAP(显示2D电阻率数据图表)。这些操作通过CDataOperator类与后台数据管理器进行交互,实现数据的增删改查功能。
**Section sources**
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp#L1-L800)
## 对话框用户交互逻辑
Views模块包含多个对话框实现,用于处理特定的用户交互场景。DialNew2DTask.cpp实现创建新2D任务的对话框,提供任务名称、测试地点、测试类型、装置类型等参数的输入界面。
对话框通过组合框控件实现选项选择,如m_cmbTestType用于选择测试方法(电阻率、激电、自电),m_cmbArray用于选择装置类型。OnInitDialog方法初始化界面元素,设置默认值和本地化文本。OnSelchangeCombo2dTestType等事件处理方法根据用户选择动态更新相关控件的状态。
DialCfgTaskPacket.cpp实现配置任务包的对话框,允许用户将多个任务组合成一个任务包,并设置循环次数、时间间隔等参数。对话框使用列表控件m_listTaskPacket显示已添加的任务,提供添加和删除功能。用户可以通过界面设置PLC ID、循环次数和时间间隔,然后保存到数据库。
**Section sources**
- [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp#L1-L665)
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L1-L301)
## 跨孔测量UI组件
跨孔测量功能由crossHole目录下的组件实现,主要包括CCrossHoleConfig2DMainDlg.cpp。该对话框提供跨孔测量的配置界面,包含电极坐标、井下、地面和参数四个选项卡页面。
通过m_tabChange选项卡控件实现多页面切换,每个页面对应不同的配置内容。井下和地面页面使用COption2DBoreholeDlg和COption2DSurfaceDlg等子对话框实现具体功能。CCrosshole2dDrawingBoardDlg用于显示和编辑电极坐标,C2DSimulationDlg用于模拟测量过程。
TwoBoreholeGenerateScript方法实现跨孔测量脚本的生成算法,根据两个孔的电极位置计算测量点的ABMN参数和几何因子K值。SaveTestPointToDB方法将生成的脚本保存到数据库,包括脚本基本信息、通道信息和测点信息。
**Section sources**
- [CCrossHoleConfig2DMainDlg.cpp](file://cpp/crossHole/CCrossHoleConfig2DMainDlg.cpp#L1-L800)
## 测井功能UI
测井功能由logging目录下的组件实现,主要包括CDialogLoggingWnd.cpp。该对话框实现测井数据的显示界面,采用自定义绘制方式呈现测井曲线和岩性柱状图。
OnInitDialog方法初始化界面布局,设置各静态文本控件的位置。DrawFirstColumnStatic到DrawSixColumnStatic系列方法负责绘制界面的六个列区域,包括钻孔编号、探管型号、测量时间等基本信息。OnPaint方法实现自定义绘制,绘制测井曲线、深度刻度线和岩性柱状图。
UpdateLowHighValue方法更新各测量参数的最小值和最大值显示,用于指示数据范围。对话框支持加载测井数据文件,根据数据动态调整绘图区域大小,并在界面上绘制SP(自电)、长电位电阻率、短电位电阻率和梯度电阻率等测井曲线。
**Section sources**
- [CDialogLoggingWnd.cpp](file://cpp/logging/CDialogLoggingWnd.cpp#L1-L800)
## 自定义控件实现
ctrl目录包含自定义控件的实现,主要是CDragListCtrl.cpp。该控件继承自CListCtrl,扩展了拖拽功能,允许用户通过鼠标拖拽重新排序列表项。
控件通过重写OnLvnBegindrag、OnMouseMove和OnLButtonUp等消息处理方法实现拖拽逻辑。在OnLvnBegindrag中创建拖拽图像列表,并开始拖拽操作。OnMouseMove方法更新拖拽图像的位置,OnLButtonUp方法结束拖拽操作并清理资源。
CDragList辅助类提供拖拽操作的底层支持,BeginDrag、Dragging和EndDrag方法分别处理拖拽的开始、过程和结束阶段。这种设计实现了流畅的拖拽用户体验,允许用户直观地重新排列列表项。
**Section sources**
- [CDragListCtrl.cpp](file://cpp/ctrl/CDragListCtrl.cpp#L1-L260)
## UI消息映射机制
Views模块采用MFC的消息映射机制处理用户交互。每个UI类通过BEGIN_MESSAGE_MAP和END_MESSAGE_MAP宏定义消息映射表,将Windows消息或命令ID映射到相应的处理方法。
例如,主框架窗口的消息映射表将ON_COMMAND(IDM_MNG_DATA_WIN, OnMngDataWin)映射到OnMngDataWin方法,当用户点击"数据管理"菜单时触发该方法。设备管理框架通过ON_MESSAGE(WM_SCHEDULE, OnSchedule)处理自定义的WM_SCHEDULE消息,用于更新界面状态。
消息处理方法通常先进行参数验证和状态检查,然后调用相应的业务逻辑类完成具体操作。例如,OnDevieUpgrade方法先确认用户是否要进行升级,然后调用m_pDevOperator->DevieUpgrade方法执行升级操作。这种设计实现了UI层与业务逻辑层的分离,提高了代码的可维护性。
**Section sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L1-L800)
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp#L1-L800)
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp#L1-L800)
@@ -0,0 +1,248 @@
# 专用功能界面
<cite>
**本文档引用的文件**
- [CCrossHoleConfig2DMainDlg.cpp](file://cpp/crossHole/CCrossHoleConfig2DMainDlg.cpp)
- [CCrossHoleConfig3DMainDlg.cpp](file://cpp/crossHole/CCrossHoleConfig3DMainDlg.cpp)
- [COption2DGeometryDlg.cpp](file://cpp/crossHole/COption2DGeometryDlg.cpp)
- [COption3DGeometryDlg.cpp](file://cpp/crossHole/COption3DGeometryDlg.cpp)
- [CDialogLoggingWnd.cpp](file://cpp/logging/CDialogLoggingWnd.cpp)
- [CDialogLoggingParameterSetting.cpp](file://cpp/logging/CDialogLoggingParameterSetting.cpp)
- [CDialogLoggingLithologicWnd.cpp](file://cpp/logging/CDialogLoggingLithologicWnd.cpp)
- [CDragListCtrl.cpp](file://cpp/ctrl/CDragListCtrl.cpp)
- [CListTextColorCtrl.cpp](file://cpp/ctrl/CListTextColorCtrl.cpp)
- [CCrosshole2dDrawingBoardDlg.cpp](file://cpp/crossHole/CCrosshole2dDrawingBoardDlg.cpp)
</cite>
## 目录
1. [引言](#引言)
2. [跨孔测量配置对话框设计](#跨孔测量配置对话框设计)
3. [几何参数设置逻辑](#几何参数设置逻辑)
4. [测井功能用户界面实现](#测井功能用户界面实现)
5. [自定义控件绘制与交互机制](#自定义控件绘制与交互机制)
6. [专用UI与后台算法协同工作](#专用ui与后台算法协同工作)
7. [自定义控件消息处理与重绘逻辑](#自定义控件消息处理与重绘逻辑)
8. [复杂参数配置验证与默认值管理](#复杂参数配置验证与默认值管理)
9. [跨孔测量与测井功能操作流程](#跨孔测量与测井功能操作流程)
10. [自定义控件扩展最佳实践](#自定义控件扩展最佳实践)
## 引言
本项目Geomative Studio是一款专业的地质勘探软件,专注于跨孔测量和测井功能的实现。系统通过专用的UI组件为用户提供直观、高效的操作界面,支持2D和3D跨孔测量配置、测井参数设置、数据可视化等功能。核心功能模块包括跨孔测量配置对话框、几何参数设置、测井功能界面以及自定义控件等。这些组件通过精心设计的架构和交互逻辑,实现了从用户输入到数据处理再到结果展示的完整工作流。系统采用MFC框架开发,利用对话框、列表控件等标准UI元素,并结合自定义绘制和消息处理机制,提供了高度可定制的用户界面体验。
**Section sources**
- [CCrossHoleConfig2DMainDlg.cpp](file://cpp/crossHole/CCrossHoleConfig2DMainDlg.cpp#L1-L50)
- [CDialogLoggingWnd.cpp](file://cpp/logging/CDialogLoggingWnd.cpp#L1-L50)
## 跨孔测量配置对话框设计
跨孔测量配置对话框是系统的核心功能之一,提供2D和3D两种模式的测量配置。`CCrossHoleConfig2DMainDlg``CCrossHoleConfig3DMainDlg`两个类分别实现了2D和3D模式的对话框功能。对话框采用标签页(Tab)设计,包含"电极坐标"、"井下"、"地面"和"参数"四个主要页面。用户可以通过标签页切换不同的配置视图。对话框初始化时,会创建并管理多个子对话框,如`CCrosshole2dDrawingBoardDlg`用于2D绘图,`C2DSimulationDlg`用于模拟显示,以及`COption2DGeometryDlg``COption2DBoreholeDlg`等用于具体参数设置。这种设计实现了功能的模块化和界面的层次化,提高了代码的可维护性和用户体验。
```mermaid
classDiagram
class CCrossHoleConfig2DMainDlg {
+m_tabChange CTabCtrl
+m_pConnection _ConnectionPtr
+m_vecAllBoreholeABMNInfo vector<STDatabaseABMNInfo>
+m_mapDatabaseABMNInfo map<int, map<int, map<int, STDatabaseABMNInfo>>>
+GetInstance() CCrossHoleConfig2DMainDlg*
+OnInitDialog() BOOL
+OnBnClickedBtnCreate() void
+OnBnClickedBtnLoadGeometry() void
+SaveTestPointToDB() BOOL
}
class CCrossHoleConfig3DMainDlg {
+m_tabChange CTabCtrl
+m_pConnection _ConnectionPtr
+m_vecAllBoreholeABMNInfo vector<STDatabaseABMNInfo>
+m_mapDatabaseABMNInfo map<int, map<int, map<int, STDatabaseABMNInfo>>>
+GetInstance() CCrossHoleConfig3DMainDlg*
+OnInitDialog() BOOL
+OnBnClickedBtnCreate() void
+OnBnClickedBtnLoadGeometry() void
+SaveTestPointToDB() BOOL
}
class COption2DGeometryDlg {
+m_geometryList CListCtrl
+m_vecNoSortAllPoints vector<STBoreHolePoints>
+m_mapBoreholeCoordinates map<STWellPoints, vector<STBoreHolePoints>>
+m_vecSurfaceCoordinates vector<STBoreHolePoints>
+GetInstance() COption2DGeometryDlg*
+AddCoordinatesPoints() void
+DeleteCoordinatesPoint() void
+ShowCoordinatesPoints() void
}
class COption3DGeometryDlg {
+m_geometryList CListCtrl
+m_vecNoSortAllPoints vector<STBoreHolePoints>
+m_mapBoreholeCoordinates map<STWellPoints, vector<STBoreHolePoints>>
+m_mapSurfaceXCoordinates map<float, vector<STBoreHolePoints>>
+m_mapSurfaceYCoordinates map<float, vector<STBoreHolePoints>>
+GetInstance() COption3DGeometryDlg*
+AddCoordinatesPoints() void
+DeleteCoordinatesPoint() void
+ShowCoordinatesPoints() void
}
CCrossHoleConfig2DMainDlg --> COption2DGeometryDlg : "包含"
CCrossHoleConfig3DMainDlg --> COption3DGeometryDlg : "包含"
CCrossHoleConfig2DMainDlg --> CCrosshole2dDrawingBoardDlg : "包含"
CCrossHoleConfig3DMainDlg --> CCrosshole3dDrawingBoardDlg : "包含"
```
**Diagram sources **
- [CCrossHoleConfig2DMainDlg.cpp](file://cpp/crossHole/CCrossHoleConfig2DMainDlg.cpp#L15-L20)
- [CCrossHoleConfig3DMainDlg.cpp](file://cpp/crossHole/CCrossHoleConfig3DMainDlg.cpp#L15-L20)
- [COption2DGeometryDlg.cpp](file://cpp/crossHole/COption2DGeometryDlg.cpp#L19-L20)
- [COption3DGeometryDlg.cpp](file://cpp/crossHole/COption3DGeometryDlg.cpp#L19-L20)
**Section sources**
- [CCrossHoleConfig2DMainDlg.cpp](file://cpp/crossHole/CCrossHoleConfig2DMainDlg.cpp#L11-L800)
- [CCrossHoleConfig3DMainDlg.cpp](file://cpp/crossHole/CCrossHoleConfig3DMainDlg.cpp#L11-L800)
## 几何参数设置逻辑
几何参数设置是跨孔测量配置的核心环节,主要由`COption2DGeometryDlg``COption3DGeometryDlg`两个类实现。这两个类负责管理电极的坐标信息,包括井下电极和地表电极。`COption2DGeometryDlg`使用`CListCtrl`控件`m_geometryList`以列表形式展示所有电极的ID、地址、X、Y、Z坐标。用户可以通过"加载坐标"按钮从`.geomative`文件中导入坐标数据,系统会解析CSV格式的文件内容,将电极信息存储在`m_vecNoSortAllPoints`向量中,并同步更新列表显示。对于3D模式,`COption3DGeometryDlg`还支持X方向和Y方向的电缆测线,使用`m_mapSurfaceXCoordinates``m_mapSurfaceYCoordinates`两个映射来分别管理不同方向的测线数据。当用户添加或删除坐标点时,系统会自动调用`AddCoordinatesPoints``DeleteCoordinatesPoint`方法更新内部数据结构,并通知绘图板进行重绘。
```mermaid
flowchart TD
Start([开始]) --> LoadGeometry["加载坐标文件"]
LoadGeometry --> ParseFile["解析.geomative文件"]
ParseFile --> ExtractPoints["提取电极坐标点"]
ExtractPoints --> ClassifyPoints{"分类坐标点"}
ClassifyPoints --> |地表| AddToSurface["添加到地表集合"]
ClassifyPoints --> |井下| AddToBorehole["添加到井下集合"]
AddToSurface --> UpdateList["更新列表显示"]
AddToBorehole --> UpdateList
UpdateList --> NotifyDrawingBoard["通知绘图板更新"]
NotifyDrawingBoard --> End([结束])
```
**Diagram sources **
- [COption2DGeometryDlg.cpp](file://cpp/crossHole/COption2DGeometryDlg.cpp#L78-L103)
- [COption3DGeometryDlg.cpp](file://cpp/crossHole/COption3DGeometryDlg.cpp#L78-L108)
**Section sources**
- [COption2DGeometryDlg.cpp](file://cpp/crossHole/COption2DGeometryDlg.cpp#L1-L309)
- [COption3DGeometryDlg.cpp](file://cpp/crossHole/COption3DGeometryDlg.cpp#L1-L396)
## 测井功能用户界面实现
测井功能的用户界面由`CDialogLoggingWnd``CDialogLoggingParameterSetting``CDialogLoggingLithologicWnd`三个主要对话框构成。`CDialogLoggingWnd`是主窗口,负责展示测井数据的完整报告,包括公司名称、钻孔编号、井深、测井方向等基本信息,以及自电、长电位、短电位和梯度电阻率的曲线图。`CDialogLoggingParameterSetting`用于设置测井参数,如任务名、测试地点、测井类型、采样间隔、初始深度、结束深度等。`CDialogLoggingLithologicWnd`则用于编辑和管理岩性剖面,用户可以添加、删除和修改不同深度范围的岩性信息。这些对话框通过消息映射(`BEGIN_MESSAGE_MAP`)处理用户的交互操作,如按钮点击、下拉框选择等,并通过`CMarkup`类解析和加载XML格式的参数文件和DAT格式的数据文件。
```mermaid
sequenceDiagram
participant User as "用户"
participant ParamDlg as "CDialogLoggingParameterSetting"
participant MainWnd as "CDialogLoggingWnd"
participant DataOper as "CLoggingDataOper"
User->>ParamDlg : 打开参数设置对话框
ParamDlg->>DataOper : 查询任务列表
DataOper-->>ParamDlg : 返回任务信息
ParamDlg->>ParamDlg : 填充下拉框
User->>ParamDlg : 选择任务并修改参数
ParamDlg->>DataOper : 更新任务信息到数据库
DataOper-->>ParamDlg : 返回操作结果
ParamDlg->>MainWnd : 传递测井参数
User->>MainWnd : 打开测井文件
MainWnd->>MainWnd : 加载XML参数文件
MainWnd->>MainWnd : 加载DAT数据文件
MainWnd->>MainWnd : 解析并绘制曲线图
MainWnd-->>User : 显示测井报告
```
**Diagram sources **
- [CDialogLoggingParameterSetting.cpp](file://cpp/logging/CDialogLoggingParameterSetting.cpp#L34-L37)
- [CDialogLoggingWnd.cpp](file://cpp/logging/CDialogLoggingWnd.cpp#L45-L51)
- [CDialogLoggingLithologicWnd.cpp](file://cpp/logging/CDialogLoggingLithologicWnd.cpp#L50-L59)
**Section sources**
- [CDialogLoggingWnd.cpp](file://cpp/logging/CDialogLoggingWnd.cpp#L1-L1222)
- [CDialogLoggingParameterSetting.cpp](file://cpp/logging/CDialogLoggingParameterSetting.cpp#L1-L356)
- [CDialogLoggingLithologicWnd.cpp](file://cpp/logging/CDialogLoggingLithologicWnd.cpp#L1-L304)
## 自定义控件绘制与交互机制
系统实现了两个重要的自定义控件:`CDragListCtrl``CListTextColorCtrl``CDragListCtrl`继承自`CListCtrl`,支持列表项的拖拽操作。它通过重写`OnLvnBegindrag``OnMouseMove``OnLButtonUp`消息处理函数,实现了拖拽的开始、移动和结束逻辑。当用户开始拖拽时,系统创建一个`CImageList`作为拖拽图像,并调用`DragEnter`方法显示拖拽效果。在鼠标移动过程中,`DragMove`方法会实时更新拖拽图像的位置。`CListTextColorCtrl`则是一个支持自定义文本颜色和背景颜色的列表控件。它通过将控件设置为`LVS_OWNERDRAWFIXED`风格,并重写`DrawItem`方法,实现了对每个列表项的自定义绘制。控件内部维护了`m_colTextColor``m_ItemTextColor`等链表,用于存储列和单元格的文本颜色,从而实现灵活的样式控制。
```mermaid
classDiagram
class CDragListCtrl {
+m_nSelItem int
+m_pDragImageList CImageList*
+m_bDragging BOOL
+OnLvnBegindrag() void
+OnMouseMove() void
+OnLButtonUp() void
}
class CListTextColorCtrl {
+m_nRowHeight int
+m_fontHeight int
+m_fontWith int
+m_color COLORREF
+m_ptrListCol CPtrList
+m_ptrListItem CPtrList
+m_colTextColor CPtrList
+m_ItemTextColor CPtrList
+DrawItem() void
+MeasureItem() void
+SetColTextColor() void
+SetItemTextColor() void
}
CDragListCtrl --|> CListCtrl : "继承"
CListTextColorCtrl --|> CListCtrl : "继承"
```
**Diagram sources **
- [CDragListCtrl.cpp](file://cpp/ctrl/CDragListCtrl.cpp#L9-L17)
- [CListTextColorCtrl.cpp](file://cpp/ctrl/CListTextColorCtrl.cpp#L16-L21)
**Section sources**
- [CDragListCtrl.cpp](file://cpp/ctrl/CDragListCtrl.cpp#L1-L260)
- [CListTextColorCtrl.cpp](file://cpp/ctrl/CListTextColorCtrl.cpp#L1-L399)
## 专用UI与后台算法协同工作
专用UI组件与后台算法模块通过数据结构和函数调用紧密协同工作。以跨孔测量配置为例,用户在`COption2DGeometryDlg`中设置的电极坐标,会通过`AddCoordinatesPoints`方法传递给`CCrossHoleConfig2DMainDlg`。当用户点击"创建"按钮时,`CCrossHoleConfig2DMainDlg`会调用`TwoBoreholeGenerateScript`等算法函数,根据电极的相对位置和间距,计算出测点的ABMN参数和几何因子K值。这些计算结果被存储在`m_vecAllBoreholeABMNInfo`向量中,最终通过`SaveTestPointToDB`方法写入数据库。对于测井功能,`CDialogLoggingParameterSetting`收集的参数被封装成`STLoggingParamSettingReq`结构体,传递给数据采集模块。采集到的数据则由`CDialogLoggingWnd`负责解析和可视化,实现了从用户配置到数据采集再到结果展示的完整闭环。
**Section sources**
- [CCrossHoleConfig2DMainDlg.cpp](file://cpp/crossHole/CCrossHoleConfig2DMainDlg.cpp#L734-L736)
- [CDialogLoggingParameterSetting.cpp](file://cpp/logging/CDialogLoggingParameterSetting.cpp#L353-L356)
## 自定义控件消息处理与重绘逻辑
自定义控件的消息处理和重绘逻辑是其核心功能的实现基础。`CListTextColorCtrl`通过`PreSubclassWindow`方法将控件风格修改为`LVS_OWNERDRAWFIXED`,这表示控件将自行负责绘制其内容。当需要重绘时,系统会调用`DrawItem`方法。该方法首先获取要绘制的列表项信息,然后根据项的状态(选中或未选中)设置不同的背景色。接着,它会遍历所有列,计算每列的显示位置,并从`m_colTextColor``m_ItemTextColor`链表中查找对应的文本颜色,最后使用`DrawText`函数将文本绘制到指定位置。为了支持行高设置,控件重写了`MeasureItem`方法,根据`m_nRowHeight`成员变量的值来确定每一行的高度。这种机制使得控件能够灵活地适应不同的显示需求。
**Section sources**
- [CListTextColorCtrl.cpp](file://cpp/ctrl/CListTextColorCtrl.cpp#L62-L69)
- [CListTextColorCtrl.cpp](file://cpp/ctrl/CListTextColorCtrl.cpp#L71-L234)
## 复杂参数配置验证与默认值管理
系统对复杂参数配置进行了严格的验证和默认值管理。在`CDialogLoggingParameterSetting`中,当用户点击"确定"按钮时,`OnBnClickedOk`方法会执行一系列验证检查。例如,它会检查任务名、采样间隔、初始深度等必填字段是否为空,以及测井类型是否已选择。如果验证失败,会弹出相应的错误提示。对于数值型参数,系统会使用`atof`函数将其从字符串转换为浮点数,并进行范围检查。此外,系统还实现了默认值管理,例如在`OnInitDialog`方法中,会将"迭代次数"的默认值设置为0,并将"发射波形"的默认选项设置为"0+0-"。对于跨孔测量配置,系统会根据电极的Z坐标自动计算L值的取值范围,并确保生成的测点符合物理规律。
**Section sources**
- [CDialogLoggingParameterSetting.cpp](file://cpp/logging/CDialogLoggingParameterSetting.cpp#L174-L351)
- [CCrossHoleConfig2DMainDlg.cpp](file://cpp/crossHole/CCrossHoleConfig2DMainDlg.cpp#L302-L349)
## 跨孔测量与测井功能操作流程
对于初学者,跨孔测量和测井功能的操作流程如下:
1. **跨孔测量配置**
* 打开"跨孔测量配置"对话框。
* 切换到"井下"或"地面"标签页,通过"加载坐标"按钮导入电极坐标。
* 切换到"参数"标签页,输入脚本名称、时间间隔等信息。
* 点击"创建"按钮生成测点脚本。
* 点击"开始模拟"按钮进行模拟运行。
2. **测井功能使用**
* 在主界面选择"测井"功能。
* 点击"参数设置"按钮,配置任务名、测井类型、深度范围等参数。
* 开始数据采集。
* 采集完成后,点击"打开文件"按钮加载测井数据。
* 在主窗口查看自电、电阻率等曲线图,并通过"岩性编辑"功能添加岩性剖面。
**Section sources**
- [CCrossHoleConfig2DMainDlg.cpp](file://cpp/crossHole/CCrossHoleConfig2DMainDlg.cpp#L734-L736)
- [CDialogLoggingParameterSetting.cpp](file://cpp/logging/CDialogLoggingParameterSetting.cpp#L174-L351)
## 自定义控件扩展最佳实践
对于高级开发者,扩展自定义控件的最佳实践包括:
1. **继承与重写**:从标准MFC控件(如`CListCtrl`)继承,并重写关键的虚函数,如`DrawItem``PreSubclassWindow`等。
2. **消息映射**:使用`BEGIN_MESSAGE_MAP`宏将Windows消息(如`WM_PAINT``WM_LBUTTONDOWN`)映射到自定义的消息处理函数。
3. **状态管理**:在控件类中定义私有成员变量来管理控件的内部状态,如选中的项、拖拽状态、自定义颜色等。
4. **资源管理**:注意GDI对象(如`CPen``CBrush``CFont`)的创建和销毁,避免资源泄漏。通常在`OnPaint`等函数中创建,并在函数结束前通过`SelectObject`恢复旧对象。
5. **性能优化**:对于复杂的绘制操作,考虑使用双缓冲技术(Double Buffering)来减少屏幕闪烁。可以通过在内存DC上先绘制,再一次性拷贝到屏幕DC上来实现。
**Section sources**
- [CListTextColorCtrl.cpp](file://cpp/ctrl/CListTextColorCtrl.cpp#L1-L399)
- [CDragListCtrl.cpp](file://cpp/ctrl/CDragListCtrl.cpp#L1-L260)
@@ -0,0 +1,410 @@
# 主界面
<cite>
**本文档中引用的文件**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp)
- [ChildFrm.cpp](file://cpp/Views/ChildFrm.cpp)
- [ChildView.cpp](file://cpp/Views/ChildView.cpp)
- [Splash.cpp](file://cpp/Views/Splash.cpp)
- [MainFrm.h](file://h/MainFrm.h)
- [ChildFrm.h](file://h/ChildFrm.h)
- [ChildView.h](file://h/ChildView.h)
- [Splash.h](file://h/Splash.h)
- [GeoMative.rc2](file://res/GeoMative.rc2)
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp)
</cite>
## 目录
1. [主界面架构概述](#主界面架构概述)
2. [主窗口初始化流程](#主窗口初始化流程)
3. [菜单栏、工具栏与状态栏构建](#菜单栏工具栏与状态栏构建)
4. [多文档界面(MDI)组织方式](#多文档界面mdi组织方式)
5. [子窗口创建与管理逻辑](#子窗口创建与管理逻辑)
6. [启动画面显示控制](#启动画面显示控制)
7. [UI元素资源定义与消息映射](#ui元素资源定义与消息映射)
8. [用户操作路由机制](#用户操作路由机制)
9. [主界面与其他管理模块的数据交互](#主界面与其他管理模块的数据交互)
10. [MFC框架下的窗口生命周期管理](#mfc框架下的窗口生命周期管理)
11. [性能优化建议](#性能优化建议)
## 主界面架构概述
Geomative Studio主界面采用MFCMicrosoft Foundation Classes)框架实现,基于多文档界面(MDI)架构。系统通过`CMainFrame`类作为主框架窗口,继承自`CMDIFrameWnd`,负责管理整个应用程序的主窗口、菜单栏、工具栏和状态栏。主界面通过消息映射机制处理用户交互,并与设备管理、项目管理和数据管理器等模块进行数据交互。
主界面架构采用分层设计,包括:
- **主框架层**`CMainFrame`负责整体布局和核心功能调度
- **子框架层**`CChildFrame`用于管理多文档界面中的子窗口
- **视图层**`CChildView`提供客户端区域的显示功能
- **辅助组件层**:如启动画面`CSplashWnd`等提供辅助功能
该架构支持模块化扩展,通过消息驱动机制实现各组件间的松耦合通信。
**Section sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L56-L94)
- [ChildFrm.cpp](file://cpp/Views/ChildFrm.cpp#L18-L27)
- [ChildView.cpp](file://cpp/Views/ChildView.cpp#L26-L30)
## 主窗口初始化流程
主窗口的初始化流程始于`CGeoMativeApp::InitInstance()`方法,在`GeoMative.cpp`中创建`CMainFrame`实例并加载框架。初始化过程包含以下关键步骤:
1. **主框架创建**:通过`new CMainFrame`实例化主窗口对象
2. **框架加载**:调用`LoadFrame(IDR_MAINFRAME)`加载资源定义的框架结构
3. **窗口显示**:设置为最大化显示并通过`ShowWindow``UpdateWindow`呈现
4. **数据库连接**:初始化ADO连接,打开GeoMativeDB.accdb数据库
5. **系统初始化**:创建系统时间获取线程,初始化诊断信息等
`CMainFrame::OnCreate`方法中,进一步完成工具栏、状态栏的创建和初始化,并显示启动画面。整个初始化流程确保了应用程序在启动时能够正确配置所有必要的UI组件和系统资源。
```mermaid
sequenceDiagram
participant App as CGeoMativeApp
participant MainFrame as CMainFrame
participant Splash as CSplashWnd
App->>MainFrame : new CMainFrame()
App->>MainFrame : LoadFrame(IDR_MAINFRAME)
App->>MainFrame : ShowWindow(SW_SHOWMAXIMIZED)
App->>MainFrame : UpdateWindow()
MainFrame->>MainFrame : OnCreate()
MainFrame->>Splash : CSplashWnd : : ShowSplashScreen()
MainFrame->>MainFrame : 创建工具栏和状态栏
MainFrame->>MainFrame : 初始化设备检测
```
**Diagram sources**
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L208-L227)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L164-L223)
- [Splash.cpp](file://cpp/Views/Splash.cpp#L45-L55)
**Section sources**
- [GeoMative.cpp](file://cpp/Main/GeoMative.cpp#L208-L399)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L111-L135)
- [Splash.cpp](file://cpp/Views/Splash.cpp#L19-L55)
## 菜单栏、工具栏与状态栏构建
主界面的菜单栏、工具栏和状态栏通过MFC的标准机制构建。在`MainFrm.cpp`中,`BEGIN_MESSAGE_MAP`宏定义了这些控件的创建和管理。
**工具栏**通过`CToolBar::CreateEx`方法创建,使用`TBSTYLE_FLAT|TBSTYLE_TOOLTIPS`样式实现扁平化外观和工具提示功能。工具栏加载`IDR_MAINFRAME`资源中的工具栏定义,并通过`EnableDocking(CBRS_ALIGN_ANY)`启用任意方向停靠。
**状态栏**通过`CStatusBar::Create`方法创建,使用预定义的指示器数组`indicators`来显示状态信息。该数组包含分隔符、大写锁定、数字锁定和滚动锁定等标准状态指示器。
```mermaid
classDiagram
class CMainFrame {
+CStatusBar m_wndStatusBar
+CToolBar m_wndToolBar
+LoadFrame()
+OnCreate()
+PreCreateWindow()
}
class CToolBar {
+CreateEx()
+LoadToolBar()
+EnableDocking()
+DockControlBar()
}
class CStatusBar {
+Create()
+SetIndicators()
}
CMainFrame --> CToolBar : 包含
CMainFrame --> CStatusBar : 包含
```
**Diagram sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L169-L189)
- [MainFrm.h](file://h/MainFrm.h#L56-L57)
**Section sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L164-L190)
- [MainFrm.h](file://h/MainFrm.h#L56-L57)
## 多文档界面(MDI)组织方式
Geomative Studio采用标准的MFC多文档界面(MDI)架构,通过`CMDIFrameWnd``CMDIChildWnd`类实现。主框架`CMainFrame`继承自`CMDIFrameWnd`,负责管理多个子窗口。
MDI架构的核心组件包括:
- **主框架窗口**`CMainFrame`,作为所有子窗口的容器
- **子框架窗口**`CChildFrame`,继承自`CMDIChildWnd`,每个子窗口的容器
- **视图窗口**`CChildView`,继承自`CWnd`,提供实际内容显示区域
子窗口的创建通过`CreateNewChild`方法实现,该方法使用运行时类信息创建指定类型的子框架。例如,在`OnMngDataWin`方法中,通过`CreateNewChild(RUNTIME_CLASS(CDataMngFrame), IDR_MAINFRAME)`创建数据管理框架。
```mermaid
graph TD
A[CMainFrame] --> B[CChildFrame]
A --> C[CChildFrame]
A --> D[CChildFrame]
B --> E[CChildView]
C --> F[CChildView]
D --> G[CChildView]
style A fill:#f9f,stroke:#333
style B fill:#bbf,stroke:#333
style C fill:#bbf,stroke:#333
style D fill:#bbf,stroke:#333
```
**Diagram sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L624-L667)
- [ChildFrm.cpp](file://cpp/Views/ChildFrm.cpp#L17-L27)
**Section sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L624-L667)
- [ChildFrm.cpp](file://cpp/Views/ChildFrm.cpp#L17-L118)
- [ChildFrm.h](file://h/ChildFrm.h#L14-L54)
## 子窗口创建与管理逻辑
子窗口的创建与管理由`CChildFrame``CChildView`类共同实现。`CChildFrame`作为子框架窗口,负责管理子窗口的生命周期和布局,而`CChildView`则负责客户端区域的内容显示。
`CChildFrame::OnCreate`方法中,通过`m_wndView.Create()`创建`CChildView`实例,并将其作为子窗口的视图组件。`OnCmdMsg`方法实现了命令消息的传递机制,确保视图能够优先处理命令消息。
子窗口的关闭通过`OnFileClose`方法实现,该方法发送`WM_CLOSE`消息来关闭窗口。`OnSetFocus`方法确保当子窗口获得焦点时,其内部的视图组件也能获得焦点。
```mermaid
flowchart TD
Start([子窗口创建]) --> PreCreateWindow["CChildFrame::PreCreateWindow"]
PreCreateWindow --> OnCreate["CChildFrame::OnCreate"]
OnCreate --> CreateView["创建CChildView"]
CreateView --> SetStyle["设置窗口样式"]
SetStyle --> Complete([子窗口创建完成])
CloseStart([子窗口关闭]) --> OnFileClose["CChildFrame::OnFileClose"]
OnFileClose --> SendClose["发送WM_CLOSE消息"]
SendClose --> CompleteClose([窗口关闭])
```
**Diagram sources**
- [ChildFrm.cpp](file://cpp/Views/ChildFrm.cpp#L85-L98)
- [ChildView.cpp](file://cpp/Views/ChildView.cpp#L36-L47)
**Section sources**
- [ChildFrm.cpp](file://cpp/Views/ChildFrm.cpp#L33-L118)
- [ChildView.cpp](file://cpp/Views/ChildView.cpp#L17-L58)
- [ChildView.h](file://h/ChildView.h#L15-L52)
## 启动画面显示控制
启动画面由`CSplashWnd`类实现,遵循MFC向导添加的典型启动画面模式。该类继承自`CWnd`,通过静态方法`ShowSplashScreen`控制启动画面的显示。
启动画面的显示控制流程如下:
1. 调用`CSplashWnd::ShowSplashScreen(this)`显示启动画面
2. `Create`方法加载`IDB_SPLASH`位图资源并创建弹出式窗口
3. `OnCreate`方法调用`CenterWindow`居中显示,并设置2秒定时器
4. `OnPaint`方法使用`BitBlt`绘制启动画面位图
5. `OnTimer`方法触发`HideSplashScreen`隐藏并销毁窗口
启动画面具有用户交互感知能力,通过`PreTranslateAppMessage`方法检测键盘或鼠标消息,一旦用户交互即立即隐藏启动画面,提升用户体验。
```mermaid
stateDiagram-v2
[*] --> Hidden
Hidden --> Creating : ShowSplashScreen()
Creating --> Displayed : Create()
Displayed --> Hiding : OnTimer() or 用户交互
Hiding --> Hidden : DestroyWindow()
note right of Displayed
定时器设置为2秒
或等待用户交互
end note
```
**Diagram sources**
- [Splash.cpp](file://cpp/Views/Splash.cpp#L45-L55)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L193-L194)
**Section sources**
- [Splash.cpp](file://cpp/Views/Splash.cpp#L1-L142)
- [Splash.h](file://h/Splash.h#L12-L56)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L193-L194)
## UI元素资源定义与消息映射
UI元素的资源定义主要通过`.rc`资源文件实现,尽管`GeoMative.rc2`文件当前为空,但系统使用`IDR_MAINFRAME`等资源ID引用主框架资源。菜单、工具栏和对话框等UI元素在资源编辑器中定义,并通过资源ID在代码中引用。
消息映射机制是MFC的核心特性,通过`BEGIN_MESSAGE_MAP``END_MESSAGE_MAP`宏定义消息处理函数。在`MainFrm.cpp`中,消息映射表将WM_CREATE、菜单命令ID和自定义消息映射到相应的处理方法。
例如,菜单命令`IDM_MNG_DATA_WIN`映射到`OnMngDataWin`方法,自定义消息`WM_SCHEDULE`映射到`OnSchedule`方法。这种声明式的消息映射机制使得UI事件处理清晰且易于维护。
```mermaid
erDiagram
RESOURCE : "资源定义" {
string 资源类型
string 资源ID
string 资源数据
}
MESSAGE_MAP : "消息映射" {
string 消息ID
string 处理函数
string 消息类型
}
HANDLER : "处理函数" {
string 函数名
string 参数
string 返回值
}
RESOURCE ||--o{ MESSAGE_MAP : "通过ID关联"
MESSAGE_MAP }o--|| HANDLER : "映射到"
```
**Diagram sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L58-L94)
- [GeoMative.rc2](file://res/GeoMative.rc2#L1-L14)
**Section sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L58-L94)
- [GeoMative.rc2](file://res/GeoMative.rc2#L1-L14)
## 用户操作路由机制
用户操作路由机制基于MFC的消息映射系统实现。`ON_COMMAND`宏将菜单项和工具栏按钮的命令ID映射到特定的处理函数。当用户点击菜单项或工具栏按钮时,MFC框架自动调用相应的处理方法。
例如,`ON_COMMAND(IDM_MNG_DATA_WIN, OnMngDataWin)`将数据管理窗口命令映射到`OnMngDataWin`方法。该方法检查`m_pDataMngFrm`是否已创建,若未创建则通过`CreateNewChild`创建新的子框架,否则激活现有窗口。
自定义消息通过`ON_MESSAGE`宏处理,如`ON_MESSAGE(WM_SCHEDULE, OnSchedule)`处理调度消息。这种机制支持应用程序内部组件间的通信,实现了松耦合的设计。
```mermaid
sequenceDiagram
participant User as 用户
participant Frame as CMainFrame
participant Handler as 处理函数
User->>Frame : 点击菜单项IDM_MNG_DATA_WIN
Frame->>Frame : 查找消息映射表
Frame->>Handler : 调用OnMngDataWin()
Handler->>Handler : 检查m_pDataMngFrm
alt 窗口未创建
Handler->>Handler : CreateNewChild()
Handler->>Handler : ShowWindow(SW_SHOWMAXIMIZED)
else 窗口已存在
Handler->>Handler : ActivateFrame()
end
Handler-->>Frame : 返回
```
**Diagram sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L60-L63)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L624-L636)
**Section sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L60-L63)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L624-L667)
## 主界面与其他管理模块的数据交互
主界面通过成员变量和消息机制与设备管理、项目管理和数据管理器等模块进行数据交互。`CMainFrame`类定义了指向这些管理框架的指针,如`m_pDevMngFrm``m_pDataMngFrm``m_pSptMngFrm`
数据交互主要通过以下方式实现:
- **直接方法调用**:通过管理框架指针调用其公开方法
- **消息传递**:使用`SendMessage`发送`WM_REFRESH`等自定义消息
- **共享数据对象**:通过应用程序对象`theApp`访问全局管理器
例如,在设备连接时,主框架通过`m_pDevMngFrm->SendMessage(WM_REFRESH_NAV_DEVICE)`通知设备管理框架刷新设备列表。文件导入导出操作通过`theApp.m_pIOManager`执行,并在完成后发送刷新消息。
```mermaid
classDiagram
class CMainFrame {
+CDevMngFrame* m_pDevMngFrm
+CDataMngFrame* m_pDataMngFrm
+CSptMngFrame* m_pSptMngFrm
+OnRefresh()
+OnFileExp()
+OnFileImp()
}
class CDevMngFrame {
+OnRefreshNavDevice()
}
class CDataMngFrame {
+OnRefresh()
}
class CIOManager {
+Export()
+Import()
}
CMainFrame --> CDevMngFrame : 持有引用
CMainFrame --> CDataMngFrame : 持有引用
CMainFrame --> CIOManager : 通过theApp访问
CMainFrame ..> CDevMngFrame : 发送WM_REFRESH_NAV_DEVICE
CMainFrame ..> CDataMngFrame : 发送WM_REFRESH
```
**Diagram sources**
- [MainFrm.h](file://h/MainFrm.h#L40-L42)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L554-L555)
**Section sources**
- [MainFrm.h](file://h/MainFrm.h#L40-L42)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L554-L555)
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L69-L72)
## MFC框架下的窗口生命周期管理
MFC框架通过一系列虚拟方法和消息处理机制管理窗口生命周期。窗口的创建、销毁和消息处理遵循特定的顺序和模式。
**创建过程**
1. 构造函数:`CMainFrame()`进行成员变量初始化
2. `PreCreateWindow`:修改窗口样式和类属性
3. `OnCreate`:创建子控件(工具栏、状态栏)
4. `LoadFrame`:加载框架资源并显示窗口
**销毁过程**
1. `WM_CLOSE`消息:触发窗口关闭
2. 析构函数:`~CMainFrame()`清理资源
3. `PostNcDestroy`:删除C++对象(在`CSplashWnd`中实现)
子窗口通过`OnCmdMsg`方法实现命令消息的传递,确保视图能够优先处理命令。这种分层的消息处理机制是MFC框架的核心特性之一。
```mermaid
flowchart TB
subgraph 创建流程
A[构造函数] --> B[PreCreateWindow]
B --> C[OnCreate]
C --> D[LoadFrame]
D --> E[ShowWindow]
end
subgraph 销毁流程
F[WM_CLOSE] --> G[析构函数]
G --> H[PostNcDestroy]
H --> I[对象删除]
end
```
**Diagram sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L111-L127)
- [ChildFrm.cpp](file://cpp/Views/ChildFrm.cpp#L33-L43)
- [Splash.cpp](file://cpp/Views/Splash.cpp#L100-L104)
**Section sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp#L111-L127)
- [ChildFrm.cpp](file://cpp/Views/ChildFrm.cpp#L33-L43)
- [Splash.cpp](file://cpp/Views/Splash.cpp#L100-L104)
## 性能优化建议
针对Geomative Studio主界面的性能优化,建议从以下几个方面着手:
**减少重绘开销**
- 使用双缓冲技术减少闪烁
- 仅重绘无效区域而非整个窗口
- 延迟更新,批量处理UI变更
**减少消息处理延迟**
- 避免在消息处理函数中执行耗时操作
- 将长时间运行的任务移至工作线程
- 使用定时器分批处理大量数据更新
**内存管理优化**
- 及时释放不再使用的子窗口
- 使用智能指针管理动态创建的对象
- 缓存频繁访问的资源
**启动性能优化**
- 延迟加载非关键模块
- 优化数据库连接和初始化流程
- 减少启动时的同步操作
通过实施这些优化措施,可以显著提升主界面的响应速度和用户体验。
**Section sources**
- [MainFrm.cpp](file://cpp/Views/MainFrm.cpp)
- [ChildFrm.cpp](file://cpp/Views/ChildFrm.cpp)
- [Splash.cpp](file://cpp/Views/Splash.cpp)
@@ -0,0 +1,269 @@
# 数据管理界面
<cite>
**本文档引用的文件**
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp)
- [DialListMeasuData.cpp](file://cpp/Views/DialListMeasuData.cpp)
- [DialListMeasuGR.cpp](file://cpp/Views/DialListMeasuGR.cpp)
- [DialListRealTimeMeasuData.cpp](file://cpp/Views/DialListRealTimeMeasuData.cpp)
- [DialListRealTimeMeasuGR.cpp](file://cpp/Views/DialListRealTimeMeasuGR.cpp)
- [DialMeasureData.cpp](file://cpp/Views/DialMeasureData.cpp)
- [DialMeasureDetailInfo.cpp](file://cpp/Views/DialMeasureDetailInfo.cpp)
- [DialRealTimeMeasureData.cpp](file://cpp/Views/DialRealTimeMeasureData.cpp)
- [TdManager.h](file://h/TdManager.h)
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp)
- [DataOperator.h](file://h/DataOperator.h)
- [TaskDataOper.h](file://h/TaskDataOper.h)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp)
</cite>
## 目录
1. [数据管理框架](#数据管理框架)
2. [测量数据列表展示](#测量数据列表展示)
3. [实时数据刷新机制](#实时数据刷新机制)
4. [测量详情查看功能](#测量详情查看功能)
5. [实时监控界面行为](#实时监控界面行为)
6. [数据查询、过滤与导出](#数据查询过滤与导出)
7. [大数据量列表优化](#大数据量列表优化)
8. [操作指南](#操作指南)
9. [高级开发者指南](#高级开发者指南)
## 数据管理框架
数据管理框架的核心是`CDataMngFrame`类,它负责组织和管理数据管理界面的整体结构。该框架采用MDI(多文档界面)设计,通过分割窗口(Splitter Window)将界面分为左右两个视图:左侧为导航数据视图(`CNavDataView`),右侧为应用数据视图(`CAppDataView`)。
框架通过消息映射(`BEGIN_MESSAGE_MAP`)处理各种数据管理操作,如创建、删除、导出和刷新数据。当用户在导航树中选择一个数据项时,框架会根据数据类型(如2D电阻率、3D激电等)动态创建相应的应用视图,并加载和显示数据。
```mermaid
classDiagram
class CDataMngFrame {
+m_pNavDataView : CView*
+m_pAppDataView : CView*
+m_pDataOperator : CDataOperator*
+OnCreateClient() bool
+OnSchedule() LRESULT
+ShowAppView() bool
+ShowContentListByPageView() bool
}
class CDataOperator {
+ShowRsp2DTdInfo() void
+ShowIps2DpTdInfo() void
+ShowSP2DTdInfo() void
+LoadRsp2dRecordbyPage() void
+LoadIpsp2dRecordbyPage() void
+LoadSP2dRecordbyPage() void
}
CDataMngFrame --> CDataOperator : "使用"
CDataMngFrame --> CView : "包含 m_pNavDataView"
CDataMngFrame --> CView : "包含 m_pAppDataView"
```
**Diagram sources**
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp#L49-L602)
**Section sources**
- [datamngframe.cpp](file://cpp/Views/datamngframe.cpp#L1-L800)
## 测量数据列表展示
测量数据列表的展示逻辑主要由`CDialListMeasuData``CDialListMeasuGR`两个类实现。`CDialListMeasuData`负责显示测量数据,而`CDialListMeasuGR`负责显示接地电阻信息。
`CDialListMeasuData``OnInitDialog`方法中初始化列表控件,设置列标题(如ID、A、B、M、N、Stack、K、V(mV)、I(mA)、R0(Ohm*m)等),并从数据库查询数据填充列表。它支持分页显示,通过“上一页”和“下一页”按钮进行导航。
```mermaid
flowchart TD
A[初始化对话框] --> B[设置列表控件样式]
B --> C[插入列标题]
C --> D[查询数据库获取数据]
D --> E{数据是否为空?}
E --> |否| F[调用OnShowTdData显示数据]
E --> |是| G[返回]
F --> H[遍历数据向量]
H --> I[格式化并插入列表项]
I --> J[设置列表项文本]
J --> K{是否遍历完成?}
K --> |否| H
K --> |是| L[结束]
```
**Diagram sources**
- [DialListMeasuData.cpp](file://cpp/Views/DialListMeasuData.cpp#L52-L120)
**Section sources**
- [DialListMeasuData.cpp](file://cpp/Views/DialListMeasuData.cpp#L1-L333)
- [DialListMeasuGR.cpp](file://cpp/Views/DialListMeasuGR.cpp#L1-L113)
## 实时数据刷新机制
实时数据的刷新机制由`CDialListRealTimeMeasureData``CDialListRealTimeMeasuGR`类实现。与静态数据列表不同,实时数据需要在测量过程中动态更新。
`CDialListRealTimeMeasureData`提供了三种数据更新方法:
1. `OnShowTdData`: 一次性清空并重新填充整个列表。
2. `OnShowTdDataAppend`: 在列表末尾追加新数据。
3. `OnShowTdDataUpdate`: 智能更新,先查找是否存在该数据,存在则更新,不存在则追加。
这种设计确保了在高频率数据更新场景下的流畅性和准确性。
```mermaid
sequenceDiagram
participant Device as "测量设备"
participant App as "应用程序"
participant List as "实时数据列表"
Device->>App : 发送测量数据包
App->>App : 解析数据包
App->>List : 调用OnShowTdDataUpdate
List->>List : 查找ID匹配的列表项
alt 找到匹配项
List->>List : 更新现有项的数据
else 未找到匹配项
List->>List : 在末尾追加新项
end
List->>List : 确保新项可见(EnsureVisible)
List->>List : 更新界面
```
**Diagram sources**
- [DialListRealTimeMeasuData.cpp](file://cpp/Views/DialListRealTimeMeasuData.cpp#L171-L332)
- [DialListRealTimeMeasuData.cpp](file://cpp/Views/DialListRealTimeMeasuData.cpp#L251-L332)
**Section sources**
- [DialListRealTimeMeasuData.cpp](file://cpp/Views/DialListRealTimeMeasuData.cpp#L1-L486)
- [DialListRealTimeMeasuGR.cpp](file://cpp/Views/DialListRealTimeMeasuGR.cpp#L1-L244)
## 测量详情查看功能
测量详情的查看功能由`CDialMeasureDetailInfo`类实现。该类提供了一个包含“数据”和“接地电阻”两个标签页的对话框,允许用户在一个界面中查看任务的详细信息。
其核心逻辑在`OnInitDialog`方法中:
1. 根据传入的任务参数(`STRemTaskArg`),创建并初始化`CDialListMeasuTask``CDialListMeasuGR`两个子控件。
2. 分别调用`ShowPage(1)``GetGRRequest(m_stTaskArg)`从云端获取任务数据和接地电阻信息。
3. 通过标签页的切换事件(`OnSelchangeTabChg`)来显示或隐藏相应的子控件。
```mermaid
classDiagram
class CDialMeasureDetailInfo {
+m_dialListMeasuTask : CDialListMeasuTask
+m_dialListMeasuGR : CDialListMeasuGR
+OnInitDialog() bool
+OnSelchangeTabChg() void
}
class CDialListMeasuTask {
+ShowPage() void
}
class CDialListMeasuGR {
+GetGRRequest() void
}
CDialMeasureDetailInfo --> CDialListMeasuTask
CDialMeasureDetailInfo --> CDialListMeasuGR
```
**Diagram sources**
- [DialMeasureDetailInfo.cpp](file://cpp/Views/DialMeasureDetailInfo.cpp#L56-L104)
**Section sources**
- [DialMeasureData.cpp](file://cpp/Views/DialMeasureData.cpp#L1-L2262)
- [DialMeasureDetailInfo.cpp](file://cpp/Views/DialMeasureDetailInfo.cpp#L1-L186)
## 实时监控界面行为
实时监控界面由`CDialRealTimeMeasureData`类控制。该类不仅管理数据列表,还处理用户与测量过程的交互,如开始测量、暂停测量、单点测量等。
其行为逻辑如下:
- **按钮状态管理**: 通过`SetBtnStatus`方法根据当前测量状态(如`EN_MEASU_BTN_MEASU_ALL`)启用或禁用按钮,防止用户进行无效操作。
- **测量命令发送**: 当用户点击“开始测量”时,`OnMeasureAll`方法会构造一个`STTrusteeTaskTable`结构体,并通过`PostNetRequest`发送到设备,启动测量任务。
- **数据接收与处理**: 重写`ProcRcvMeasuData`等方法来处理从设备接收的实时数据,并更新UI。
**Section sources**
- [DialRealTimeMeasureData.cpp](file://cpp/Views/DialRealTimeMeasureData.cpp#L1-L1879)
## 数据查询、过滤与导出
数据查询、过滤和导出功能主要由`CTdManager``CDataOperator`两个核心类实现。
`CTdManager`作为数据管理器,提供了与数据库交互的底层接口:
- **查询**: `ShowTdListByTz``ShowTdListByProject`等方法用于从数据库查询任务列表。
- **删除**: `DeleteRsp2DTd``DeleteIpsp2DTd`等方法用于删除不同类型的数据。
- **导入/导出**: `Import2DTdConToDB``ExportRsp2DTdToDAT`等方法用于数据的导入和导出。
`CDataOperator`则作为`CTdManager`的上层封装,为UI提供更便捷的调用接口。例如,`ExportRsp2DTdToExcel`方法会调用`CTdManager`的底层功能,将2D电阻率数据导出为Excel文件。
```mermaid
classDiagram
class CDataOperator {
+ExportRsp2DTdToExcel() UINT
+ExportRsp2DTdToDAT() UINT
+ExportRsp2DTdToCSV() UINT
+ShowRsp2DTdInfo() void
+LoadRsp2dRecordbyPage() void
}
class CTdManager {
+ShowTdListByTz() bool
+DeleteRsp2DTd() void
+Import2DTdConToDB() bool
+ExportRsp2DTdToDAT() UINT
}
CDataOperator --> CTdManager : "使用"
```
**Diagram sources**
- [DataOperator.h](file://h/DataOperator.h#L29-L87)
- [TdManager.h](file://h/TdManager.h#L33-L87)
**Section sources**
- [TdManager.h](file://h/TdManager.h#L1-L109)
- [TdManager.cpp](file://cpp/Managers/TdManager.cpp#L1-L6839)
- [DataOperator.h](file://h/DataOperator.h#L1-L174)
## 大数据量列表优化
在处理大数据量时,直接加载所有数据会导致界面卡顿。项目通过以下两种技术进行优化:
1. **分页加载**: `CDataOperator`类中的`LoadRsp2dRecordbyPage`等方法实现了分页查询。它接收一个起始ID和页大小,只从数据库加载指定范围的数据,显著减少了内存占用和加载时间。
2. **虚拟列表**: 虽然代码中未直接体现,但`CListCtrl`控件支持虚拟列表(Virtual List)模式。在这种模式下,控件不会存储所有数据,而是通过`LVN_GETDISPINFO`消息在需要显示某一行时,由程序动态提供该行的数据。这是一种处理海量数据的高效方式。
**Section sources**
- [DataOperator.h](file://h/DataOperator.h#L76-L83)
- [TaskDataOper.h](file://h/TaskDataOper.h#L378-L382)
- [TaskDataOper.cpp](file://cpp/Operator/TaskDataOper.cpp#L418-L513)
## 操作指南
### 初学者:数据查看与导出
1. **查看数据**:
* 打开“数据管理”界面。
* 在左侧导航树中选择一个任务。
* 右侧会自动显示该任务的测量数据列表。
* 使用“上一页”和“下一页”按钮浏览不同页面的数据。
2. **导出数据**:
* 在导航树中右键点击要导出的任务。
* 选择“导出”菜单下的格式,如“导出为Excel”或“导出为DAT文件”。
* 在弹出的对话框中选择保存路径,点击“保存”即可。
## 高级开发者指南
### 高频率数据更新场景下的UI线程安全处理
在实时监控等高频率数据更新场景下,数据接收通常在后台线程中进行,而UI更新必须在主线程(UI线程)中完成。为确保线程安全,项目采用了以下方案:
1. **消息传递机制**: 后台线程不直接操作UI控件,而是通过`PostMessage``PostNetRequest`向UI线程发送自定义消息(如`WM_MSG_UPDATE_TASK_LIST`)。
2. **UI线程处理**: UI线程的消息循环接收到消息后,调用相应的消息处理函数(如`OnShowTdDataUpdate`)来安全地更新列表控件。
这种“生产者-消费者”模式有效地隔离了数据处理和UI更新,避免了多线程访问共享资源导致的竞态条件和崩溃。
```mermaid
sequenceDiagram
participant WorkerThread as "工作线程"
participant UIThread as "UI线程"
participant ListCtrl as "列表控件"
WorkerThread->>WorkerThread : 接收测量数据
WorkerThread->>UIThread : PostMessage(WM_SHOW_TD_DATA_UPDATE, 数据指针)
UIThread->>UIThread : 消息循环接收到消息
UIThread->>UIThread : 调用OnShowTdDataUpdate
UIThread->>ListCtrl : 安全地更新列表项
ListCtrl->>UIThread : 更新完成
```
**Section sources**
- [DialListRealTimeMeasuData.cpp](file://cpp/Views/DialListRealTimeMeasuData.cpp#L344-L343)
- [DialRealTimeMeasureData.cpp](file://cpp/Views/DialRealTimeMeasureData.cpp#L593-L594)
@@ -0,0 +1,266 @@
# 设备管理界面
<cite>
**本文档引用的文件**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
- [DailLogin.cpp](file://cpp/Views/DailLogin.cpp)
- [DialFindComShow.cpp](file://cpp/Views/DialFindComShow.cpp)
- [DialShowDevParam.cpp](file://cpp/Views/DialShowDevParam.cpp)
- [DialPlcStatusShow.cpp](file://cpp/Views/DialPlcStatusShow.cpp)
- [DialDevStatusTimerShow.cpp](file://cpp/Views/DialDevStatusTimerShow.cpp)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp)
- [NetRequestDialog.cpp](file://cpp/socket/NetRequestDialog.cpp)
</cite>
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构概述](#架构概述)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考虑](#性能考虑)
8. [故障排除指南](#故障排除指南)
9. [结论](#结论)
## 简介
本文档深入分析GeomativeStudio项目中设备管理相关的UI组件实现。重点介绍devmngframe.cpp中设备管理框架的布局结构与消息响应机制,DailLogin.cpp中的登录验证流程,DialFindComShow.cpp中的串口检测对话框逻辑,DialShowDevParam.cpp中的设备参数展示机制。解释DialPlcStatusShow.cpp和DialDevStatusTimerShow.cpp中PLC状态与定时状态的实时更新策略。结合MFC消息映射机制,说明用户操作如何触发CDevManager的接口调用。为初学者提供UI与设备通信协同工作的概念性解释,为高级开发者提供多线程环境下UI刷新的最佳实践。
## 项目结构
项目采用典型的MFC应用程序结构,设备管理相关的UI组件主要位于cpp/Views目录下。核心的设备管理框架由devmngframe.cpp实现,负责整体布局和消息分发。各个功能模块如登录、串口检测、设备参数展示等通过独立的对话框类实现。业务逻辑与数据管理由cpp/Managers和cpp/Operator目录下的类负责,形成清晰的分层架构。
**Section sources**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
- [DailLogin.cpp](file://cpp/Views/DailLogin.cpp)
## 核心组件
设备管理界面的核心组件包括设备管理框架、登录验证、串口检测、设备参数展示和状态监控等模块。这些组件通过MFC的消息映射机制协同工作,实现用户与设备的交互。CDevManager类作为设备管理的核心,负责设备的生命周期管理和状态维护。
**Section sources**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp)
## 架构概述
系统采用MFC文档/视图架构,设备管理功能通过CMDIChildWnd派生的CDevMngFrame类实现。该框架使用CSplitterWnd进行界面分割,左侧为导航树视图,右侧为内容显示区域。通过消息映射机制处理用户操作,调用CDevOperator和CDevManager类完成具体业务逻辑。
```mermaid
graph TB
subgraph "UI层"
A[CDevMngFrame] --> B[CNavDevView]
A --> C[CAppDevView]
A --> D[CAppDevOLView]
end
subgraph "业务逻辑层"
E[CDevOperator] --> F[CDevManager]
E --> G[CDevice]
end
subgraph "数据层"
F --> H[数据库]
G --> I[串口通信]
end
A --> E
B --> E
C --> E
D --> E
```
**Diagram sources**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp)
## 详细组件分析
### 设备管理框架分析
CDevMngFrame类实现了设备管理的主框架,负责界面布局和消息处理。通过CSplitterWnd将界面分为导航区域和内容显示区域,支持动态切换视图以显示不同状态的设备信息。
#### 布局结构
```mermaid
classDiagram
class CDevMngFrame {
+CSplitterWnd m_splitter
+CView* m_pAppDevView
+CView* m_pNavDevView
+OnCreateClient()
+ShowAppView()
}
class CNavDevView {
+CTreeCtrl m_devTree
}
class CAppDevView {
+CListCtrl m_devDetailList
}
class CAppDevOLView {
+CListCtrl m_devOLDetailList
+CListCtrl m_devOLGRList
+CListCtrl m_devOLACList
}
CDevMngFrame --> CNavDevView : "包含"
CDevMngFrame --> CAppDevView : "包含"
CDevMngFrame --> CAppDevOLView : "包含"
```
**Diagram sources**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
- [navdevview.h](file://h/navdevview.h)
- [appdevview.h](file://h/appdevview.h)
#### 消息响应机制
```mermaid
sequenceDiagram
participant 用户
participant CDevMngFrame
participant CDevOperator
participant CDevManager
用户->>CDevMngFrame : 点击"修改设备参数"
CDevMngFrame->>CDevMngFrame : OnModifyDeviceParameter()
CDevMngFrame->>CDevOperator : ModifyDeviceParameter()
CDevOperator->>CDevManager : GetDeviceByID()
CDevManager-->>CDevOperator : 返回CDevice对象
CDevOperator->>CDevice : ModifyParameter()
CDevice-->>CDevOperator : 显示参数对话框
CDevOperator->>CDevice : ShowOLDetailInfo()
CDevice-->>CDevOperator : 更新UI
CDevOperator-->>CDevMngFrame : 返回结果
CDevMngFrame-->>用户 : 显示更新后的界面
```
**Diagram sources**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp)
### 登录验证流程分析
DailLogin.cpp实现了系统的登录验证功能,包括用户身份验证、密码保存和自动登录等特性。
#### 登录验证流程
```mermaid
flowchart TD
Start([开始]) --> ValidateInput["验证输入参数"]
ValidateInput --> InputValid{"输入有效?"}
InputValid --> |否| ReturnError["显示错误信息"]
InputValid --> |是| CheckUserID["验证用户ID"]
CheckUserID --> UserIDValid{"ID正确?"}
UserIDValid --> |否| ReturnError
UserIDValid --> |是| CheckPassword["验证密码"]
CheckPassword --> PasswordValid{"密码正确?"}
PasswordValid --> |否| ReturnError
PasswordValid --> |是| SaveSettings["保存设置"]
SaveSettings --> CheckSave["是否保存密码?"]
CheckSave --> |是| SavePassword["写入config.ini"]
CheckSave --> |否| SkipSave
SkipSave --> CheckAutoLogin["是否自动登录?"]
CheckAutoLogin --> |是| SaveAutoLogin["写入config.ini"]
CheckAutoLogin --> |否| SkipAutoLogin
SkipAutoLogin --> Complete["登录成功"]
ReturnError --> End([结束])
Complete --> End
```
**Diagram sources**
- [DailLogin.cpp](file://cpp/Views/DailLogin.cpp)
### 串口检测对话框逻辑
DialFindComShow.cpp实现了串口检测结果的显示功能,用于向用户展示串口连接状态。
#### 串口检测逻辑
```mermaid
classDiagram
class CDialFindComShow {
+CString m_strShowCom
+OnInitDialog()
}
CDialFindComShow --> CDialog : "继承"
```
**Diagram sources**
- [DialFindComShow.cpp](file://cpp/Views/DialFindComShow.cpp)
### 设备参数展示机制
DialShowDevParam.cpp实现了设备参数的展示和修改功能,支持参数的本地编辑和云端同步。
#### 参数展示与同步
```mermaid
sequenceDiagram
participant CDevMngFrame
participant CDialShowDevParam
participant Network
CDevMngFrame->>CDialShowDevParam : OnShowDevParam()
CDialShowDevParam->>CDialShowDevParam : 显示参数对话框
CDialShowDevParam->>CDialShowDevParam : 用户修改参数
CDialShowDevParam->>CDialShowDevParam : 验证输入
CDialShowDevParam->>Network : 发送修改请求
Network-->>CDialShowDevParam : 接收响应
CDialShowDevParam-->>CDevMngFrame : 返回结果
```
**Diagram sources**
- [DialShowDevParam.cpp](file://cpp/Views/DialShowDevParam.cpp)
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
### PLC状态与定时状态实时更新
DialPlcStatusShow.cpp和DialDevStatusTimerShow.cpp实现了PLC状态和定时状态的实时监控功能。
#### 状态更新策略
```mermaid
classDiagram
class CDialPlcStatusShow {
+STRemPlcData* m_pRemPlcData
+OnInitDialog()
}
class CDialDevStatusTimerShow {
+CListCtrl m_listData
+ShowPlcStatusData()
}
class CTaskDataOper {
+QueryPlcStatusData()
}
CDialDevStatusTimerShow --> CTaskDataOper : "使用"
CDialPlcStatusShow --> CDialDevStatusTimerShow : "关联"
```
**Diagram sources**
- [DialPlcStatusShow.cpp](file://cpp/Views/DialPlcStatusShow.cpp)
- [DialDevStatusTimerShow.cpp](file://cpp/Views/DialDevStatusTimerShow.cpp)
- [TaskDataOper.h](file://h/TaskDataOper.h)
**Section sources**
- [DialPlcStatusShow.cpp](file://cpp/Views/DialPlcStatusShow.cpp)
- [DialDevStatusTimerShow.cpp](file://cpp/Views/DialDevStatusTimerShow.cpp)
## 依赖关系分析
系统各组件之间存在清晰的依赖关系,UI组件依赖于业务逻辑组件,业务逻辑组件又依赖于数据访问组件。这种分层架构有助于代码的维护和扩展。
```mermaid
graph TD
A[devmngframe.cpp] --> B[DevOperator.cpp]
B --> C[DevManager.cpp]
C --> D[Device.cpp]
D --> E[SComPort.cpp]
A --> F[DialShowDevParam.cpp]
F --> G[NetRequestDialog.cpp]
A --> H[DialPlcStatusShow.cpp]
H --> I[DialDevStatusTimerShow.cpp]
I --> J[TaskDataOper.cpp]
```
**Diagram sources**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
- [DevOperator.cpp](file://cpp/Operator/DevOperator.cpp)
- [DevManager.cpp](file://cpp/Managers/DevManager.cpp)
## 性能考虑
在多线程环境下进行UI刷新时,应避免在主线程中执行耗时操作。建议使用工作线程处理设备通信,通过PostMessage或SendMessage将结果发送回UI线程进行界面更新。对于频繁的状态更新,可以采用定时器机制,避免过度刷新导致的性能问题。
## 故障排除指南
常见问题包括设备连接失败、参数同步异常和界面刷新延迟等。检查网络连接状态、验证设备ID和类型、确认串口配置正确性是解决问题的关键步骤。使用日志文件可以帮助定位具体的问题根源。
**Section sources**
- [devmngframe.cpp](file://cpp/Views/devmngframe.cpp)
- [Device.cpp](file://cpp/ProblemZone/Device.cpp)
## 结论
本文档详细分析了GeomativeStudio项目中设备管理相关的UI组件实现。通过MFC框架实现了功能完整的设备管理界面,各组件之间通过清晰的消息传递机制协同工作。系统架构合理,代码组织规范,为类似应用的开发提供了有价值的参考。
@@ -0,0 +1,358 @@
# 项目管理界面
<cite>
**本文档引用的文件**
- [taskmngframe.cpp](file://cpp/Views/taskmngframe.cpp)
- [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp)
- [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp)
- [DialNew3DTask.cpp](file://cpp/Views/DialNew3DTask.cpp)
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp)
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp)
- [DialTaskTree.cpp](file://cpp/Views/DialTaskTree.cpp)
- [DialTaskManager.cpp](file://cpp/Views/DialTaskManager.cpp)
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp)
</cite>
## 目录
1. [任务管理框架与导航逻辑](#任务管理框架与导航逻辑)
2. [测量任务创建流程](#测量任务创建流程)
3. [任务包配置机制](#任务包配置机制)
4. [地形参数设置逻辑](#地形参数设置逻辑)
5. [任务树形视图构建与交互](#任务树形视图构建与交互)
6. [项目数据持久化与加载](#项目数据持久化与加载)
7. [任务参数验证与数据传递](#任务参数验证与数据传递)
8. [任务配置工作流](#任务配置工作流)
9. [UI响应性能优化建议](#ui响应性能优化建议)
## 任务管理框架与导航逻辑
任务管理框架由`taskmngframe.cpp`实现,作为MDI子窗口继承自`CMDIChildWnd`。该框架负责组织和管理所有与任务相关的UI组件,提供统一的导航界面。框架通过消息映射处理窗口激活、关闭等事件,确保在用户切换不同任务管理视图时能够正确更新状态和界面元素。
**Section sources**
- [taskmngframe.cpp](file://cpp/Views/taskmngframe.cpp#L1-L36)
## 测量任务创建流程
### 1D测量任务创建
`DialNew1DTask.cpp`实现了1D测量任务的创建对话框。该对话框初始化时会根据当前UI语言设置控件文本,并从`CTaskDataOper`操作类查询可用的介质类型和脚本信息。用户选择测试类型(电阻率、激电、自电)后,系统会动态更新发射波形和发射周期的选项。在用户点击"创建"按钮后,系统会执行完整的参数验证,包括任务名、测试方式、装置类型、脚本、迭代次数等,确保所有必填项都已正确填写且符合取值范围。
```mermaid
flowchart TD
Start([开始创建1D任务]) --> Init["初始化对话框\n设置语言、加载介质和脚本"]
Init --> SelectType["用户选择测试类型\n(电阻率/激电/自电)"]
SelectType --> UpdateOptions["更新发射波形和周期选项"]
UpdateOptions --> UserInput["用户输入任务参数\n任务名、位置、脚本等"]
UserInput --> Validate["点击创建时验证参数"]
Validate --> CheckName{"任务名为空?"}
CheckName --> |是| ShowError1["显示错误提示"]
CheckName --> |否| CheckType{"测试方式未选?"}
CheckType --> |是| ShowError2["显示错误提示"]
CheckType --> |否| CheckArray{"装置类型未选?"}
CheckArray --> |是| ShowError3["显示错误提示"]
CheckArray --> |否| CheckScript{"脚本未选?"}
CheckScript --> |是| ShowError4["显示错误提示"]
CheckScript --> |否| CheckStacking{"迭代次数有效?"}
CheckStacking --> |否| ShowError5["显示错误提示"]
CheckStacking --> |是| CreateTask["调用CTaskDataOper::Create1DTask\n创建任务"]
CreateTask --> Success{"创建成功?"}
Success --> |是| CloseDialog["关闭对话框"]
Success --> |否| Return["返回等待用户修正"]
ShowError1 --> Return
ShowError2 --> Return
ShowError3 --> Return
ShowError4 --> Return
ShowError5 --> Return
```
**Diagram sources**
- [DialNew1DTask.cpp](file://cpp/Views/DialNew1DTask.cpp#L1-L381)
### 2D测量任务创建
`DialNew2DTask.cpp`实现了2D测量任务的创建对话框。与1D任务相比,2D任务需要更多的参数配置,包括电缆布线方式、起始/结束电极、电极间距、孔间距(对于交叉孔装置)等。对话框在初始化时会根据装置类型动态显示或隐藏相关控件,例如交叉孔装置会显示孔间距输入框。当用户选择不同的测试类型时,系统会过滤可用的电缆布线方式,确保选择的配置是有效的。
```mermaid
flowchart TD
Start([开始创建2D任务]) --> Init["初始化对话框\n加载介质、脚本、电缆布局"]
Init --> SelectType["用户选择测试类型"]
SelectType --> FilterLayout["根据测试类型过滤\n电缆布线方式"]
FilterLayout --> UserInput["用户输入任务参数\n包括电极间距、起始/结束电极等"]
UserInput --> Validate["点击创建时验证参数"]
Validate --> CheckCommon["验证通用参数\n(任务名、测试方式等)"]
CheckCommon --> CheckSpace{"电极间距为零?"}
CheckSpace --> |是| ShowError1["显示错误提示"]
CheckSpace --> |否| CheckHole{"交叉孔装置且孔间距为零?"}
CheckHole --> |是| ShowError2["显示错误提示"]
CheckHole --> |否| CheckRange{"起始/结束电极越界?"}
CheckRange --> |是| ShowError3["显示错误提示"]
CheckRange --> |否| CreateTask["调用CTaskDataOper::Create2DTask\n创建任务"]
CreateTask --> Success{"创建成功?"}
Success --> |是| CloseDialog["关闭对话框"]
Success --> |否| Return["返回等待用户修正"]
ShowError1 --> Return
ShowError2 --> Return
ShowError3 --> Return
```
**Diagram sources**
- [DialNew2DTask.cpp](file://cpp/Views/DialNew2DTask.cpp#L1-L665)
### 3D测量任务创建
`DialNew3DTask.cpp`实现了3D测量任务的创建对话框。3D任务的配置最为复杂,需要设置网格大小、X/Y方向电极步长和距离等参数。当用户选择脚本时,系统会自动查询并显示网格信息(X和Y方向的点数),帮助用户理解测量范围。对话框还提供了发射周期的"自动"选项,为用户提供更灵活的配置选择。
```mermaid
flowchart TD
Start([开始创建3D任务]) --> Init["初始化对话框\n加载介质、脚本、电缆布局"]
Init --> SelectScript["用户选择脚本"]
SelectScript --> QueryGrid["查询并显示网格信息\n(X方向点数, Y方向点数)"]
QueryGrid --> UserInput["用户输入任务参数\n包括步长、距离等"]
UserInput --> Validate["点击创建时验证参数"]
Validate --> CheckCommon["验证通用参数\n(任务名、测试方式等)"]
CheckCommon --> CheckStep{"步长为空?"}
CheckStep --> |是| ShowError["显示错误提示"]
CheckStep --> |否| CreateTask["调用CTaskDataOper::Create3DTask\n创建任务"]
CreateTask --> Success{"创建成功?"}
Success --> |是| CloseDialog["关闭对话框"]
Success --> |否| Return["返回等待用户修正"]
ShowError --> Return
```
**Diagram sources**
- [DialNew3DTask.cpp](file://cpp/Views/DialNew3DTask.cpp#L1-L570)
## 任务包配置机制
`DialCfgTaskPacket.cpp`实现了任务包的配置对话框,允许用户将多个任务组织成一个任务包进行循环执行。对话框包含一个任务选择下拉框和一个任务列表,用户可以将选中的任务添加到列表中,也可以从列表中删除任务。系统会检查重复添加的任务,避免同一个任务被多次执行。
在用户点击"保存"时,系统会对输入的参数进行严格验证:
- 循环次数必须在1-60000之间
- 时间间隔必须在1-60000之间
- PLC ID不能为空
验证通过后,系统会将任务列表和属性信息保存到数据库中,供后续执行使用。
```mermaid
classDiagram
class CDialCfgTaskPacket {
+m_cmbTaskName : CComboBox
+m_listTaskPacket : CListCtrl
+m_cmbTaskName : CComboBox
+OnButtonAdd() void
+OnButtonDel() void
+OnOK() void
+IsRepeatTask(int) bool
+InitialTaskList() void
}
class CTaskDataOper {
+QueryTdBrowseInfo() void
+QueryTaskPacketAttr() bool
+InsertTaskPacketInfo() bool
}
CDialCfgTaskPacket --> CTaskDataOper : "使用"
```
**Diagram sources**
- [DialCfgTaskPacket.cpp](file://cpp/Views/DialCfgTaskPacket.cpp#L1-L301)
## 地形参数设置逻辑
`DialCfgTerrain.cpp`实现了地形参数的配置对话框,允许用户导入DAT文件并编辑地形数据点。对话框提供了添加、修改、删除地形数据点的功能,并支持从文件导入地形数据。用户可以设置地形数据标志(水平距离或垂直距离)和第一个电极对应的地形数据点编号。
在保存地形数据时,系统会执行严格的验证:
- 必须已导入DAT文件
- 必须选择地形数据标志
- 必须输入至少一个地形数据点
- 第一个电极对应的地形数据点编号必须在有效范围内
验证通过后,系统会将地形数据写入原DAT文件的末尾,遵循特定的文件格式要求。
```mermaid
flowchart TD
Start([开始配置地形]) --> ImportFile["用户导入DAT文件"]
ImportFile --> EditData["编辑地形数据点\n添加、修改、删除"]
EditData --> SetParams["设置地形参数\n标志、第一个电极编号"]
SetParams --> Save["点击保存"]
Save --> Validate["验证参数"]
Validate --> CheckFile{"已导入文件?"}
CheckFile --> |否| ShowError1["显示错误提示"]
CheckFile --> |是| CheckFlag{"选择数据标志?"}
CheckFlag --> |否| ShowError2["显示错误提示"]
CheckFlag --> |是| CheckData{"输入地形数据?"}
CheckData --> |否| ShowError3["显示错误提示"]
CheckData --> |是| CheckIndex{"第一个电极编号有效?"}
CheckIndex --> |否| ShowError4["显示错误提示"]
CheckIndex --> |是| WriteFile["将地形数据写入DAT文件"]
WriteFile --> Success{"写入成功?"}
Success --> |是| ShowSuccess["显示成功提示"]
Success --> |否| ShowFail["显示失败提示"]
ShowError1 --> Return["返回等待用户修正"]
ShowError2 --> Return
ShowError3 --> Return
ShowError4 --> Return
```
**Diagram sources**
- [DialCfgTerrain.cpp](file://cpp/Views/DialCfgTerrain.cpp#L1-L843)
## 任务树形视图构建与交互
### 任务树形视图构建
`DialTaskTree.cpp`实现了任务树形视图,使用`CTreeCtrl`控件显示任务列表。视图支持复选框功能,允许用户选择多个任务进行批量操作。视图初始化时会根据任务类型(2D或3D)从服务器获取任务数据,并构建树形结构。
```mermaid
classDiagram
class CDialTaskTree {
+m_treeTask : CTreeCtrl
+m_iSptType : int
+m_pParentWnd : CWnd*
+ShowTaskTree(int, time_t, time_t) void
+OnClickTreeTaskList() void
+OnNMRClickTreeTaskList() void
+OnAddNewItemToTaskList() bool
+OnClearTaskList() void
}
class CTaskDataOper {
+InitOnLineTaskTreeCtrl() void
+SetCurrentTimeRange() void
}
CDialTaskTree --> CTaskDataOper : "使用"
```
**Diagram sources**
- [DialTaskTree.cpp](file://cpp/Views/DialTaskTree.cpp#L1-L686)
### 任务树形视图交互
任务树形视图支持丰富的交互功能:
- 点击复选框:选择或取消选择任务,同时更新父节点的选中计数
- 右键点击:显示上下文菜单,提供创建任务、删除任务、取消测试、刷新列表等操作
- 点击任务节点:通知父窗口当前选中的任务
上下文菜单的选项会根据当前UI语言动态调整文本内容,确保用户界面的国际化支持。
```mermaid
sequenceDiagram
participant User as "用户"
participant Tree as "任务树"
participant Parent as "父窗口"
User->>Tree : 右键点击任务节点
Tree->>Tree : 显示上下文菜单
User->>Tree : 选择"删除任务"
Tree->>Parent : 发送WM_MSG_DELETE_TASK消息
Parent->>Parent : 处理删除任务逻辑
Parent->>Tree : 刷新任务列表
Tree->>User : 显示操作结果
```
**Diagram sources**
- [DialTaskTree.cpp](file://cpp/Views/DialTaskTree.cpp#L1-L686)
## 项目数据持久化与加载
`ProManager.cpp`实现了项目管理器,负责项目数据的持久化与加载。项目管理器通过`CProManager`类与数据库交互,实现项目和测区的创建、查询和同步功能。
项目创建流程包括:
1. 在数据库中创建项目记录
2. 在设备上创建项目文件夹和配置文件
3. 同步项目数据到设备
```mermaid
sequenceDiagram
participant UI as "用户界面"
participant ProMgr as "CProManager"
participant DB as "数据库"
participant Dev as "设备"
UI->>ProMgr : 创建项目
ProMgr->>ProMgr : 显示创建对话框
ProMgr->>ProMgr : 验证项目名称唯一性
ProMgr->>DB : 插入项目记录
DB-->>ProMgr : 返回项目ID
ProMgr->>Dev : 在设备上创建项目文件夹
Dev-->>ProMgr : 文件夹创建成功
ProMgr->>Dev : 发送项目配置文件
Dev-->>ProMgr : 文件发送成功
ProMgr->>DB : 记录同步状态
DB-->>ProMgr : 同步记录创建成功
ProMgr-->>UI : 显示创建成功
```
**Diagram sources**
- [ProManager.cpp](file://cpp/Managers/ProManager.cpp#L1-L2054)
## 任务参数验证与数据传递
### 任务参数验证
系统在创建任务时执行严格的参数验证,确保所有输入都符合业务规则:
- **必填项验证**:任务名、测试方式、装置类型、脚本等必须填写
- **取值范围验证**:迭代次数(1-255)、采样间隔(0-30000)、电极间距(>0)等
- **逻辑关系验证**:交叉孔装置的孔间距必须大于电极间距
- **唯一性验证**:任务包中不能包含重复任务
### 跨对话框数据传递
系统通过多种机制实现跨对话框的数据传递:
- **构造函数传递**:在创建对话框时通过构造函数传递必要的操作对象(如`CTaskDataOper`
- **成员变量共享**:父窗口与子窗口通过成员变量共享数据
- **消息机制**:使用Windows消息在不同窗口间传递数据和状态
例如,在`DialTaskManager.cpp`中,创建任务时会根据任务类型显示相应的创建对话框,并将创建好的任务参数传递给上传逻辑:
```cpp
// 伪代码示例
if (0 == m_iSelTaskType) {
iRet = m_dialNew2DTask.DoModal();
if (IDOK == iRet) {
// 从对话框获取创建好的任务参数
strTaskCN = m_dialNew2DTask.m_strTaskCN;
// 构造任务参数结构体
strcpy(m_TaskArg.ucTaskID, strTmp);
strcpy(m_TaskArg.ucTDName, m_dialNew2DTask.m_strTaskName);
// ... 其他参数
// 上传任务数据
CDownloadDataProgressDlg uploadDlg(&m_TaskArg, &m_taskOper,this);
uploadDlg.DoModal();
}
}
```
**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)
- [DialTaskManager.cpp](file://cpp/Views/DialTaskManager.cpp#L1-L2242)
## 任务配置工作流
对于初学者,任务配置的工作流可以概括为以下步骤:
1. **创建项目**:通过项目管理器创建新的项目,填写项目基本信息
2. **创建测区**:在项目中创建测区,定义测量区域
3. **创建任务**
- 选择任务类型(1D、2D或3D
- 选择测试方式(电阻率、激电或自电)
- 选择装置类型和测量脚本
- 设置任务参数(迭代次数、发射周期等)
- 点击"创建"完成任务创建
4. **配置地形**(可选):为任务配置地形数据,导入或手动输入地形点
5. **组织任务包**(可选):将多个任务组织成任务包,设置循环执行参数
6. **执行任务**:在任务管理器中选择任务并开始测量
每个步骤都有相应的对话框引导用户完成配置,系统会在关键操作前进行参数验证,确保配置的正确性。
## UI响应性能优化建议
针对大型项目下的UI响应性能,建议采取以下优化措施:
1. **分页加载任务数据**:避免一次性加载所有任务,采用分页或按时间范围加载的方式,减少内存占用和UI阻塞
2. **异步数据加载**:将耗时的数据查询操作放在后台线程执行,避免阻塞UI线程
3. **虚拟化列表控件**:对于包含大量任务的列表,使用虚拟化技术,只渲染可见区域的项目
4. **缓存常用数据**:将频繁访问的数据(如介质类型、脚本列表)缓存到内存中,减少数据库查询次数
5. **优化数据库查询**:为常用查询字段建立索引,优化SQL查询语句,减少查询时间
6. **延迟加载**:对于非关键信息,在用户需要时才进行加载,提高初始加载速度
7. **批量操作优化**:对于批量删除等操作,使用事务处理,减少数据库交互次数
这些优化措施可以显著提升大型项目下的UI响应速度,改善用户体验。