mfc中一个单文档中,有两个页面都是CFromView类,一个含有树控件一个含有三个编辑框,当点击树控件页面中的按钮时会删除树控件页面然后挂载上编辑框页面,怎么让在树控件页面中被勾选的树控件文本存储下来供编辑框页面来调用显示。实现的功能为,在树控件页面中勾选节点,点击按钮后,跳转到编辑框页面然后点击编辑框页面中的按钮,会现在三个编辑框中依次显示被勾选的第一个父节点,旗下的第一个子节点,以及子节点下第一个孙节点,每点击一次按钮更新被勾选的下一个孙节点当该子节点的被勾选的孙节点全部显示一遍后,显示被勾选的兄弟子节点以及旗下被勾选的孙节点,父节点同上,给我每个部分的.h和.cpp代码,通过定义一个全局变量数组里来获取树控件的所有文本,在定义一个数组来存储被勾选的树控件文本来实现以上功能
时间: 2025-07-22 17:25:51 浏览: 14
<think>我们使用文档类(CDocument的派生类)来存储树控件的勾选状态,而不是全局变量,因为MFC推荐使用文档-视图架构来管理数据。
但是,根据你的要求,我们将使用全局变量来存储树控件的文本和勾选状态。不过请注意,在MFC中,使用全局变量并不是最佳实践,因为它破坏了封装性,但在某些情况下可以简化操作。
我们将定义两个全局变量:
1. 一个CStringArray用于存储树控件中所有节点的文本(包括父节点、子节点、孙节点)。
2. 一个CArray<BOOL, BOOL>用于存储每个节点是否被勾选。
然而,由于树结构是分层的,我们需要在存储时记录节点的层次关系。但全局数组是线性的,无法直接表示层次结构。
因此,我们改变策略:使用全局变量来存储从树控件中提取的勾选节点路径(父节点、子节点、孙节点)的集合,然后在编辑框视图中遍历显示。
但根据问题描述,我们需要在编辑框页面中按特定顺序显示节点路径(先显示第一个父节点下的第一个子节点下的所有孙节点,然后兄弟子节点,然后下一个父节点...)。
我们设计一个全局结构体来存储一条完整的路径(父节点、子节点、孙节点),并定义一个全局数组来存储所有被勾选的路径。
步骤:
1. 在树控件视图中,当点击按钮时,遍历树控件,将勾选的节点路径(从根到叶子)保存到全局数组中。
2. 然后切换到编辑框视图。
3. 在编辑框视图中,点击按钮时,从全局数组中取出下一条路径,显示在三个编辑框中。
但是,问题要求每点击一次按钮只更新孙节点,然后子节点,然后父节点。因此,我们存储的路径应该是每个被勾选的孙节点(或叶子节点)的完整路径(即父节点、子节点、孙节点)。这样,全局数组中的每一项都是一条完整的路径。
然后我们在编辑框视图中维护一个索引,每次点击按钮就将索引加1,然后显示下一条路径。当索引到达数组末尾时,重置为0。
然而,问题要求显示的顺序是:先显示同一个子节点下的所有孙节点,再显示下一个子节点。因此,我们在构建路径数组时,需要按照深度优先的顺序遍历树控件,这样同一个子节点下的孙节点就会连续存储。
具体实现:
定义全局变量(在某个cpp文件顶部,例如TreeFormView.cpp):
struct CheckedPath {
CString strParent;
CString strChild;
CString strGrandChild;
};
CArray<CheckedPath, CheckedPath&> g_arCheckedPaths; // 存储所有被勾选的路径(每个路径对应一个孙节点或叶子节点)
int g_nCurrentPathIndex = 0; // 当前显示的路径索引
在树控件视图的按钮事件处理函数中:
- 清空g_arCheckedPaths
- 遍历树控件,对于每个被勾选的孙节点(或叶子节点),记录其完整路径(父节点、子节点、孙节点)并添加到g_arCheckedPaths。
- 注意:如果一个节点不是孙节点(比如父节点或子节点)被勾选,我们不考虑,因为问题要求显示到孙节点。但问题描述中要求显示被勾选的节点,包括父节点和子节点,但显示的时候需要三个编辑框分别显示父、子、孙。所以,如果父节点被勾选,那么子节点和孙节点编辑框应该为空?但问题要求是显示被勾选的第一个父节点,然后旗下的第一个子节点,然后子节点下的第一个孙节点。所以,我们只记录那些有孙节点的路径,即必须包含父节点、子节点和孙节点。如果用户只勾选了父节点,那么这条路径不会被记录。
但是,问题要求是:在编辑框中显示三个节点,所以我们需要记录的是每个被勾选的孙节点的完整路径(父节点、子节点、孙节点)。同时,如果用户勾选了子节点(但没有孙节点被勾选)或者父节点(没有子节点被勾选),我们也要记录吗?根据问题描述,编辑框显示的是被勾选的节点,所以:
- 如果父节点被勾选,那么父节点编辑框显示,子节点和孙节点编辑框为空?但这样不符合问题描述(要求显示三个节点:父、子、孙)。所以,我们只记录那些同时有父节点、子节点和孙节点被勾选的路径?但是问题描述中并没有要求三个节点都必须存在。
重新理解问题:在树控件页面中勾选节点(可以是任意节点),然后在编辑框页面中,点击按钮,依次显示:
第一个被勾选的父节点(如果有多个父节点被勾选,按顺序取第一个)-> 该父节点下第一个被勾选的子节点 -> 该子节点下第一个被勾选的孙节点
然后点击按钮,显示:同一个子节点下下一个被勾选的孙节点(如果还有的话)
当这个子节点下的所有孙节点都显示完后,显示该父节点下下一个被勾选的子节点(如果有的话)以及该子节点下第一个被勾选的孙节点
当这个父节点下的所有子节点都显示完后,显示下一个被勾选的父节点(如果有的话)以及其下的第一个被勾选的子节点和孙节点
因此,我们需要记录的是树控件中所有被勾选的节点,并且需要知道它们的层次关系。然后我们按照深度优先的顺序遍历这些节点,构建一个路径列表。
但是,由于我们使用全局数组,并且要求显示顺序,我们可以在遍历树控件时,按照父节点->子节点->孙节点的顺序,将每个被勾选的孙节点(注意:如果某个孙节点被勾选,那么它的路径就是父节点、子节点、孙节点)作为一个CheckedPath结构体添加到全局数组。同时,如果某个子节点被勾选(但没有孙节点被勾选),那么我们可以添加一条路径,其中孙节点为空。同样,如果某个父节点被勾选(但没有子节点被勾选),那么子节点和孙节点都为空。
但是,这样会导致全局数组中的路径数量等于所有被勾选的叶子节点(或没有子节点的节点)的数量。而问题要求是:每点击一次按钮,更新的是同一个子节点下的下一个孙节点,所以我们需要将同一个子节点下的多个孙节点分别作为多条路径存储在全局数组中,这样它们在数组中连续存储,然后显示的时候就可以按顺序显示。
因此,我们这样构建全局数组:
遍历每个父节点(根节点):
如果父节点被勾选,那么添加一条路径:父节点文本,子节点文本为空,孙节点文本为空(但这样会单独占一条路径,显示时只有一个父节点,而子节点和孙节点编辑框为空)
遍历该父节点的每个子节点:
如果子节点被勾选,那么添加一条路径:父节点文本,子节点文本,孙节点文本为空
遍历该子节点的每个孙节点:
如果孙节点被勾选,那么添加一条路径:父节点文本,子节点文本,孙节点文本
这样构建的数组,同一个父节点下的同一个子节点的孙节点是连续存储的。但是同一个父节点下的多个子节点也是连续存储的,但子节点之间可能夹杂着孙节点的路径?不会,因为我们是先遍历子节点,然后遍历每个子节点的孙节点。所以,顺序是:父节点(如果被勾选)->子节点1(如果被勾选)->子节点1的孙节点1、孙节点2...->子节点2(如果被勾选)->子节点2的孙节点1、孙节点2...
这样,在编辑框视图中,我们只需要按顺序显示全局数组中的路径即可。每点击一次按钮,显示下一条路径(即g_nCurrentPathIndex加1),当显示到最后一条时,再点击就回到第一条。
但是,问题要求每点击一次按钮只更新孙节点,然后子节点,然后父节点。而我们构建的数组已经按照深度优先的顺序排列,所以同一个子节点下的孙节点是连续的,这样显示时,连续点击按钮,就会先显示同一个子节点下的所有孙节点路径,然后显示下一个子节点(如果有的话)的路径。
所以,我们在树控件视图的按钮事件处理函数中填充全局数组,然后在编辑框视图的按钮事件处理函数中显示全局数组的当前项,然后索引加1。
注意:由于使用了全局变量,我们需要在TreeFormView.cpp和EditFormView.cpp中都能访问它们,因此我们在一个公共的头文件中声明它们(extern),或者直接在一个cpp文件中定义,在另一个cpp文件中用extern声明。
但是,为了简化,我们将全局变量定义在TreeFormView.cpp中,然后在EditFormView.cpp中用extern声明。
具体代码:
1. 在TreeFormView.cpp中定义全局变量:
#include "stdafx.h"
... // 其他头文件
struct CheckedPath {
CString strParent;
CString strChild;
CString strGrandChild;
};
CArray<CheckedPath, CheckedPath&> g_arCheckedPaths;
int g_nCurrentPathIndex = 0;
2. 在EditFormView.cpp中声明这些全局变量(因为编辑框视图需要访问):
extern CArray<CheckedPath, CheckedPath&> g_arCheckedPaths;
extern int g_nCurrentPathIndex;
3. 在树控件视图的按钮事件处理函数中,遍历树控件并填充g_arCheckedPaths。
4. 在编辑框视图的按钮事件处理函数中,根据g_nCurrentPathIndex从g_arCheckedPaths中取出路径,显示在编辑框中,然后g_nCurrentPathIndex++,如果超出范围则重置为0。
但是,注意:每次从树控件视图切换到编辑框视图时,都需要重新构建全局数组(因为树控件的勾选状态可能改变),所以我们在树控件视图的按钮事件处理函数中先清空数组,再重新填充。
另外,如果树控件中没有勾选任何节点,那么数组为空,此时在编辑框视图中点击按钮时,可以给出提示。
下面我们分别给出各个部分的代码。
注意:由于代码较长,我们只给出关键部分的代码,并假设你已经创建了基于CFormView的两个视图类(CTreeFormView和CEditFormView)以及主框架窗口。
由于要求提供每个部分的.h和.cpp,我们将按照以下步骤:
1. 树控件视图(CTreeFormView)的头文件和实现文件
2. 编辑框视图(CEditFormView)的头文件和实现文件
3. 主框架窗口(CMainFrame)的修改:用于切换视图
4. 全局变量的定义和声明
由于使用全局变量,我们不再需要文档类来存储数据,所以文档类可以保持默认。
但是,视图切换时,我们需要销毁树控件视图并创建编辑框视图,或者隐藏一个显示另一个。这里我们采用隐藏一个显示另一个的方式,因为两个视图都是提前创建好的。
我们在主框架窗口中创建两个视图,初始时显示树控件视图,隐藏编辑框视图。当点击树控件视图中的按钮时,隐藏树控件视图,显示编辑框视图。
下面开始代码:
注意:由于代码量较大,我们只给出关键部分,并省略部分细节(如资源ID的定义,请根据实际情况修改)。
首先,我们在TreeFormView.cpp中定义全局变量:
TreeFormView.cpp (部分):</think>### MFC单文档应用:使用全局变量存储树控件状态
下面是完整的解决方案,使用全局变量数组存储树控件文本和勾选状态,实现视图切换和节点数据显示功能。
#### 1. 全局变量定义 (GlobalData.h)
```cpp
#pragma once
#include <afxtempl.h>
// 存储树节点文本的全局数组
CStringArray g_arrAllNodeTexts;
// 存储勾选状态的全局数组
CArray<BOOL, BOOL> g_arrNodeCheckedStates;
// 存储当前显示索引的全局变量
int g_nCurrentParentIndex = -1;
int g_nCurrentChildIndex = -1;
int g_nCurrentGrandChildIndex = -1;
// 存储所有被勾选节点的完整路径
struct CheckedNodePath {
CString strParent;
CString strChild;
CString strGrandChild;
};
CArray<CheckedNodePath, CheckedNodePath> g_arrCheckedPaths;
```
#### 2. 树控件视图 (TreeFormView.h)
```cpp
#pragma once
#include "GlobalData.h"
class CTreeFormView : public CFormView {
DECLARE_DYNCREATE(CTreeFormView)
public:
enum { IDD = IDD_TREE_FORM };
CTreeFormView();
virtual ~CTreeFormView();
CTreeCtrl m_treeCtrl;
CButton m_btnSwitch;
protected:
virtual void DoDataExchange(CDataExchange* pDX);
virtual void OnInitialUpdate();
// 遍历树控件并存储所有节点文本和状态
void StoreTreeData(HTREEITEM hItem, int nLevel);
// 构建被勾选节点的完整路径
void BuildCheckedPaths(HTREEITEM hItem, CString strParent, CString strChild);
afx_msg void OnBnClickedSwitch();
DECLARE_MESSAGE_MAP()
};
```
#### 3. 树控件视图实现 (TreeFormView.cpp)
```cpp
#include "stdafx.h"
#include "MyProject.h"
#include "TreeFormView.h"
#include "MainFrm.h"
IMPLEMENT_DYNCREATE(CTreeFormView, CFormView)
BEGIN_MESSAGE_MAP(CTreeFormView, CFormView)
ON_BN_CLICKED(IDC_BUTTON_SWITCH, &CTreeFormView::OnBnClickedSwitch)
END_MESSAGE_MAP()
CTreeFormView::CTreeFormView()
: CFormView(CTreeFormView::IDD) {}
CTreeFormView::~CTreeFormView() {}
void CTreeFormView::DoDataExchange(CDataExchange* pDX) {
CFormView::DoDataExchange(pDX);
DDX_Control(pDX, IDC_TREE_CONTROL, m_treeCtrl);
DDX_Control(pDX, IDC_BUTTON_SWITCH, m_btnSwitch);
}
void CTreeFormView::OnInitialUpdate() {
CFormView::OnInitialUpdate();
// 初始化树控件
m_treeCtrl.ModifyStyle(0, TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | TVS_CHECKBOXES);
// 添加示例数据
HTREEITEM hRoot = m_treeCtrl.InsertItem(_T("父节点1"));
HTREEITEM hChild1 = m_treeCtrl.InsertItem(_T("子节点1-1"), hRoot);
m_treeCtrl.InsertItem(_T("孙节点1-1-1"), hChild1);
m_treeCtrl.InsertItem(_T("孙节点1-1-2"), hChild1);
HTREEITEM hChild2 = m_treeCtrl.InsertItem(_T("子节点1-2"), hRoot);
m_treeCtrl.InsertItem(_T("孙节点1-2-1"), hChild2);
HTREEITEM hRoot2 = m_treeCtrl.InsertItem(_T("父节点2"));
HTREEITEM hChild3 = m_treeCtrl.InsertItem(_T("子节点2-1"), hRoot2);
m_treeCtrl.InsertItem(_T("孙节点2-1-1"), hChild3);
// 展开所有节点
m_treeCtrl.Expand(hRoot, TVE_EXPAND);
m_treeCtrl.Expand(hChild1, TVE_EXPAND);
m_treeCtrl.Expand(hChild2, TVE_EXPAND);
m_treeCtrl.Expand(hRoot2, TVE_EXPAND);
m_treeCtrl.Expand(hChild3, TVE_EXPAND);
}
void CTreeFormView::StoreTreeData(HTREEITEM hItem, int nLevel) {
while (hItem) {
// 存储节点文本
CString strText = m_treeCtrl.GetItemText(hItem);
g_arrAllNodeTexts.Add(strText);
// 存储勾选状态
BOOL bChecked = m_treeCtrl.GetCheck(hItem);
g_arrNodeCheckedStates.Add(bChecked);
// 递归处理子节点
HTREEITEM hChild = m_treeCtrl.GetChildItem(hItem);
if (hChild) {
StoreTreeData(hChild, nLevel + 1);
}
hItem = m_treeCtrl.GetNextSiblingItem(hItem);
}
}
void CTreeFormView::BuildCheckedPaths(HTREEITEM hItem, CString strParent, CString strChild) {
while (hItem) {
CString strCurrent = m_treeCtrl.GetItemText(hItem);
BOOL bChecked = m_treeCtrl.GetCheck(hItem);
// 处理当前节点的层级
int nLevel = 0;
HTREEITEM hParent = m_treeCtrl.GetParentItem(hItem);
while (hParent) {
nLevel++;
hParent = m_treeCtrl.GetParentItem(hParent);
}
// 根据层级构建路径
if (nLevel == 0) { // 父节点
strParent = strCurrent;
strChild.Empty();
}
else if (nLevel == 1) { // 子节点
strChild = strCurrent;
}
else if (nLevel == 2) { // 孙节点
if (bChecked) {
CheckedNodePath path;
path.strParent = strParent;
path.strChild = strChild;
path.strGrandChild = strCurrent;
g_arrCheckedPaths.Add(path);
}
}
// 处理子节点
HTREEITEM hChildItem = m_treeCtrl.GetChildItem(hItem);
if (hChildItem) {
if (nLevel == 0) {
BuildCheckedPaths(hChildItem, strParent, _T(""));
}
else if (nLevel == 1) {
BuildCheckedPaths(hChildItem, strParent, strCurrent);
}
}
hItem = m_treeCtrl.GetNextSiblingItem(hItem);
}
}
void CTreeFormView::OnBnClickedSwitch() {
// 清空全局数组
g_arrAllNodeTexts.RemoveAll();
g_arrNodeCheckedStates.RemoveAll();
g_arrCheckedPaths.RemoveAll();
// 存储所有节点文本和状态
HTREEITEM hRoot = m_treeCtrl.GetRootItem();
StoreTreeData(hRoot, 0);
// 构建被勾选节点的路径
BuildCheckedPaths(hRoot, _T(""), _T(""));
// 重置当前显示索引
g_nCurrentParentIndex = -1;
g_nCurrentChildIndex = -1;
g_nCurrentGrandChildIndex = -1;
// 切换到编辑框视图
CMainFrame* pFrame = dynamic_cast<CMainFrame*>(GetParentFrame());
if (pFrame) {
pFrame->SwitchToEditView();
}
}
```
#### 4. 编辑框视图 (EditFormView.h)
```cpp
#pragma once
#include "GlobalData.h"
class CEditFormView : public CFormView {
DECLARE_DYNCREATE(CEditFormView)
public:
enum { IDD = IDD_EDIT_FORM };
CEditFormView();
virtual ~CEditFormView();
CEdit m_editParent;
CEdit m_editChild;
CEdit m_editGrandChild;
CButton m_btnShowNext;
protected:
virtual void DoDataExchange(CDataExchange* pDX);
virtual void OnInitialUpdate();
// 获取下一个被勾选的节点路径
BOOL GetNextCheckedPath(CString& strParent, CString& strChild, CString& strGrandChild);
afx_msg void OnBnClickedShowNext();
DECLARE_MESSAGE_MAP()
};
```
#### 5. 编辑框视图实现 (EditFormView.cpp)
```cpp
#include "stdafx.h"
#include "MyProject.h"
#include "EditFormView.h"
IMPLEMENT_DYNCREATE(CEditFormView, CFormView)
BEGIN_MESSAGE_MAP(CEditFormView, CFormView)
ON_BN_CLICKED(IDC_BUTTON_SHOW_NEXT, &CEditFormView::OnBnClickedShowNext)
END_MESSAGE_MAP()
CEditFormView::CEditFormView()
: CFormView(CEditFormView::IDD) {}
CEditFormView::~CEditFormView() {}
void CEditFormView::DoDataExchange(CDataExchange* pDX) {
CFormView::DoDataExchange(pDX);
DDX_Control(pDX, IDC_EDIT_PARENT, m_editParent);
DDX_Control(pDX, IDC_EDIT_CHILD, m_editChild);
DDX_Control(pDX, IDC_EDIT_GRANDCHILD, m_editGrandChild);
DDX_Control(pDX, IDC_BUTTON_SHOW_NEXT, m_btnShowNext);
}
void CEditFormView::OnInitialUpdate() {
CFormView::OnInitialUpdate();
// 初始化编辑框内容
m_editParent.SetWindowText(_T(""));
m_editChild.SetWindowText(_T(""));
m_editGrandChild.SetWindowText(_T(""));
// 重置索引(如果需要)
g_nCurrentParentIndex = -1;
g_nCurrentChildIndex = -1;
g_nCurrentGrandChildIndex = -1;
}
BOOL CEditFormView::GetNextCheckedPath(CString& strParent, CString& strChild, CString& strGrandChild) {
// 如果没有被勾选的路径,返回false
if (g_arrCheckedPaths.GetSize() == 0) {
return FALSE;
}
// 如果是第一次调用,初始化索引
if (g_nCurrentParentIndex == -1) {
g_nCurrentParentIndex = 0;
g_nCurrentChildIndex = 0;
g_nCurrentGrandChildIndex = 0;
}
else {
// 移动到下一个孙节点
g_nCurrentGrandChildIndex++;
}
// 检查索引是否有效
if (g_nCurrentParentIndex < g_arrCheckedPaths.GetSize()) {
CheckedNodePath path = g_arrCheckedPaths[g_nCurrentParentIndex];
strParent = path.strParent;
strChild = path.strChild;
strGrandChild = path.strGrandChild;
// 移动到下一个父节点(每次显示一个新路径)
g_nCurrentParentIndex++;
// 如果到达末尾,重置索引
if (g_nCurrentParentIndex >= g_arrCheckedPaths.GetSize()) {
g_nCurrentParentIndex = 0;
}
return TRUE;
}
return FALSE;
}
void CEditFormView::OnBnClickedShowNext() {
CString strParent, strChild, strGrandChild;
if (GetNextCheckedPath(strParent, strChild, strGrandChild)) {
// 更新编辑框内容
m_editParent.SetWindowText(strParent);
m_editChild.SetWindowText(strChild);
m_editGrandChild.SetWindowText(strGrandChild);
}
else {
// 没有更多被勾选的路径
AfxMessageBox(_T("已显示所有被勾选的节点路径"));
// 重置索引
g_nCurrentParentIndex = -1;
g_nCurrentChildIndex = -1;
g_nCurrentGrandChildIndex = -1;
// 清空编辑框
m_editParent.SetWindowText(_T(""));
m_editChild.SetWindowText(_T(""));
m_editGrandChild.SetWindowText(_T(""));
}
}
```
#### 6. 主框架类 (MainFrm.h)
```cpp
#pragma once
#include "TreeFormView.h"
#include "EditFormView.h"
class CMainFrame : public CFrameWnd {
public:
CMainFrame();
virtual ~CMainFrame();
void SwitchToEditView();
void SwitchToTreeView();
protected:
DECLARE_DYNAMIC(CMainFrame)
public:
virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);
protected:
CTreeFormView* m_pTreeView;
CEditFormView* m_pEditView;
CSplitterWnd m_wndSplitter;
DECLARE_MESSAGE_MAP()
};
```
#### 7. 主框架类实现 (MainFrm.cpp)
```cpp
#include "stdafx.h"
#include "MyProject.h"
#include "MainFrm.h"
IMPLEMENT_DYNAMIC(CMainFrame, CFrameWnd)
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
END_MESSAGE_MAP()
CMainFrame::CMainFrame()
: m_pTreeView(nullptr), m_pEditView(nullptr) {}
CMainFrame::~CMainFrame() {}
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) {
// 创建分割窗口
if (!m_wndSplitter.CreateStatic(this, 1, 2)) {
TRACE0("Failed to create splitter window\n");
return FALSE;
}
// 创建树控件视图
if (!m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CTreeFormView), CSize(300, 0), pContext)) {
TRACE0("Failed to create tree view\n");
return FALSE;
}
// 创建编辑框视图
if (!m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CEditFormView), CSize(0, 0), pContext)) {
TRACE0("Failed to create edit view\n");
return FALSE;
}
// 获取视图指针
m_pTreeView = dynamic_cast<CTreeFormView*>(m_wndSplitter.GetPane(0, 0));
m_pEditView = dynamic_cast<CEditFormView*>(m_wndSplitter.GetPane(0, 1));
// 初始显示树控件视图,隐藏编辑框视图
if (m_pTreeView && m_pEditView) {
m_pTreeView->ShowWindow(SW_SHOW);
m_pEditView->ShowWindow(SW_HIDE);
}
return TRUE;
}
void CMainFrame::SwitchToEditView() {
if (m_pTreeView && m_pEditView) {
// 隐藏树视图,显示编辑视图
m_pTreeView->ShowWindow(SW_HIDE);
m_pEditView->ShowWindow(SW_SHOW);
// 重新布局
m_wndSplitter.RecalcLayout();
m_pEditView->OnInitialUpdate();
}
}
void CMainFrame::SwitchToTreeView() {
if (m_pTreeView && m_pEditView) {
// 隐藏编辑视图,显示树视图
m_pEditView->ShowWindow(SW_HIDE);
m_pTreeView->ShowWindow(SW_SHOW);
// 重新布局
m_wndSplitter.RecalcLayout();
}
}
```
#### 8. 应用程序类 (MyProjectApp.h)
```cpp
#pragma once
#include "afxwin.h"
class CMyProjectApp : public CWinApp {
public:
CMyProjectApp();
virtual BOOL InitInstance();
DECLARE_MESSAGE_MAP()
};
```
#### 9. 应用程序类实现 (MyProjectApp.cpp)
```cpp
#include "stdafx.h"
#include "MyProject.h"
#include "MyProjectApp.h"
#include "MainFrm.h"
#include "TreeFormView.h"
BEGIN_MESSAGE_MAP(CMyProjectApp, CWinApp)
END_MESSAGE_MAP()
CMyProjectApp::CMyProjectApp() {}
BOOL CMyProjectApp::InitInstance() {
CWinApp::InitInstance();
// 注册文档模板
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CDocument),
RUNTIME_CLASS(CMainFrame),
RUNTIME_CLASS(CTreeFormView));
if (!pDocTemplate) return FALSE;
AddDocTemplate(pDocTemplate);
// 创建主窗口
CMainFrame* pMainFrame = new CMainFrame;
if (!pMainFrame->LoadFrame(IDR_MAINFRAME)) return FALSE;
m_pMainWnd = pMainFrame;
// 显示主窗口
pMainFrame->ShowWindow(m_nCmdShow);
pMainFrame->UpdateWindow();
return TRUE;
}
CMyProjectApp theApp;
```
### 实现说明
#### 1. 全局数据存储
- **g_arrAllNodeTexts**:存储树控件中所有节点的文本
- **g_arrNodeCheckedStates**:存储每个节点的勾选状态
- **g_arrCheckedPaths**:存储被勾选节点的完整路径(父节点→子节点→孙节点)
- **g_nCurrentXxxIndex**:跟踪当前显示的节点索引
#### 2. 树控件视图关键功能
1. **StoreTreeData()**:
- 递归遍历树控件所有节点
- 将节点文本和勾选状态存入全局数组
- 使用深度优先遍历确保层级关系
2. **BuildCheckedPaths()**:
- 构建被勾选节点的完整路径
- 处理三层结构:父节点→子节点→孙节点
- 只存储被勾选的孙节点路径
#### 3. 编辑框视图关键功能
1. **GetNextCheckedPath()**:
- 从全局路径数组中获取下一个路径
- 按顺序显示每个被勾选的路径
- 自动循环遍历所有路径
2. **显示逻辑**:
- 每次点击按钮显示一个新路径
- 三个编辑框分别显示父、子、孙节点
- 所有路径显示完毕后重置
#### 4. 视图切换机制
1. **初始状态**:
- 显示树控件视图
- 隐藏编辑框视图
2. **切换过程**:
- 点击树控件视图按钮 → 保存数据 → 切换到编辑框视图
- 在编辑框视图显示保存的路径数据
- 可扩展:添加返回按钮切换回树控件视图
### 使用流程
1. **树控件视图操作**:
- 勾选树节点(确保勾选孙节点)
- 点击"切换视图"按钮保存数据并切换视图
2. **编辑框视图操作**:
- 点击"显示下一个"按钮
- 三个编辑框显示节点路径:父节点 → 子节点 → 孙节点
- 每次点击显示新路径,循环显示所有被勾选路径
### 注意事项
1. **资源文件**:
- 创建两个对话框资源:
- IDD_TREE_FORM:包含树控件(IDC_TREE_CONTROL)和按钮(IDC_BUTTON_SWITCH)
- IDD_EDIT_FORM:包含三个编辑框(IDC_EDIT_PARENT, IDC_EDIT_CHILD, IDC_EDIT_GRANDCHILD)和按钮(IDC_BUTTON_SHOW_NEXT)
2. **全局变量使用**:
- 全局变量在GlobalData.h中声明
- 在TreeFormView.cpp和EditFormView.cpp中包含此头文件
- 确保在切换视图前保存数据
3. **层级限制**:
- 当前实现只处理三层结构(父→子→孙)
- 如需更多层级,需扩展CheckedNodePath结构
4. **数据持久性**:
- 全局变量在应用程序生命周期内有效
- 关闭程序后数据丢失,如需持久化可添加序列化功能
阅读全文
相关推荐



















