a
This commit is contained in:
@@ -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)
|
||||
Reference in New Issue
Block a user