树状控件与列表控件交互以及XML的解析

  自查笔记。       

方法记录

MSXML相关

创建对象

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
MSXML2::IXMLDOMDocumentPtr pDoc;

HRESULT hr = pDoc.CreateInstance(_uuidof(MSXML2::DOMDocument60));
if(!pDoc)
{
	ASSERT(FALSE);
	return;
}
_variant_t varOut((bool)TRUE);
varOut = pDoc->load(xmlPath);
if ((bool)varOut == FALSE)
{
	::MessageBox(NULL, "Wrong!", "提示", MB_ICONERROR);
}

获取根节点

1
2
MSXML2::IXMLDOMElementPtr pNode;
pNode = pDoc->GetdocumentElement();

获取属性(法一)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
MSXML2::IXMLDOMNamedNodeMapPtr pAttrMap;
MSXML2::IXMLDOMNodePtr pAttrItem;
MSXML2::IXMLDOMNodeListPtr pNodeList = pNode->GetchildNodes();
long Len = pNodeList->Getlength();
for (int i = 0; i < Len; ++i)
{
	MSXML2::IXMLDOMElementPtr pChildNode = (MSXML2::IXMLDOMElementPtr)pNodeList->Getitem(i);
	pChildNode->get_attributes(&pAttrMap);
	long count;
	pAttrMap->get_length(&count);
	if (count)
	{
		pAttrMap->get_item(0, &pAttrItem);
		_variant_t variantItemName;
		pAttrItem->get_nodeTypedValue(&variantItemName);
	}
}

获取属性(法二)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
MSXML2::IXMLDOMNodeListPtr pList = pRoot->GetchildNodes();
int iCount = pList->Getlength();
for (int i = 0; i < iCount; ++i)
{
	MSXML2::IXMLDOMElementPtr pItem = (MSXML2::IXMLDOMElementPtr)pList->item[i];
	MSXML2::IXMLDOMNamedNodeMapPtr pAttrMap = pItem->Getattributes();
	MSXML2::IXMLDOMNodePtr pAttrItem;
	for (int att = 0; att < pAttrMap->length; ++att)
	{
		pAttrItem = pAttrMap->Getitem(att);
		strTemp = (LPCTSTR)pAttrItem->GetnodeName();
		_variant_t value;
		value = pAttrItem->GetnodeValue();
		if (strTemp == "某属性名1")
		{
			//需要进行的操作
		}
		if (strTemp == "某属性名2")
		{
			//需要进行的操作
		}
	}
}

删除节点

连同子节点一起删 pChildNode->GetParentNode()->removeChild(pChildNode);

树控件相关

插入

HTREEITEM ht = m_tree.InsertItem((_bstr_t)variantValue, 1, 1, ht, TVI_LAST); 依次是:插入的数据,树前图标点击前,树前图标点击后,父节点,插在最后。

存入数据

m_tree.SetItemData(ht,(DWORD_PTR)数据);

获得根节点

HTREEITEM hRoot=m_tree.GetRootItem();

展开树

m_tree.Expand(ht,TVE_EXPAND);

获取选中树

HTREEITEM ChooseItem = m_tree.GetSelectedItem(); 获取数据 数据类型animal pStructure = (数据类型animal)m_tree.GetitemData(ChooseItem);

列表控件相关

插入

m_list.InsertItem(i,(LPCTSTR)数据,i);

存入数据

m_list.SetItemData(i,(DWORD_PTR)数据);

删除全部项

m_list.DeleteAllItems();

在列表最后插入

int iRow = m_list.GetItemCount(); m_list.InsertItem(iRow, text, 0); text 插入的文本 0表示imagelist中的第一个图片 imagelist是由一幅幅image拼起来的长图列表

其它C++相关

MessageBox

MessageBox分为win API 和 MFC封装两种。 win API: ::MessageBox(1, 2, 3, 4); 1为父窗口句柄,常用NULL 2为显示的字符串 3为标题栏显示的字符串 4为图标icon 有四种:MB_ICONERROR,MB_ICONINFORMATION,MB_ICONWARNING,MB_ICONQUESTION

父对话框给子对话框传值

如果子对话框是模态对话框,那么子对话框是无法在弹出后调用父对话框的控件变量的。只能在DoModal之前,通过一个子对话框的自定义成员变量传递过去。 eg. CxxDlg dlg; UpdateData(TRUE); dlg.m_str=m_edit; dlg.DoModal();

一种不良的方式: 父对话框 BookDlg 子对话框TitleDlg 在父对话框中 TitleDlg dlg(this); 在子对话框中 CBookDlg parent = (CBookDlg)GetParent(); 然后就可以使用了: CString text=pParent->m_sentence; m_sentence是父对话框类的成员变量

父窗口引用子窗口变量 在父窗口中 xxxDlg dlg; if(dlg.DoModal() == IDOK) { //操作 }

在子对话框显示图片

给自对话框添加OnInitDlg() 添加OnPaint() (记得加WM_ONPAINT消息) 在OnInitDlg中加载图片,在OnPanint()中重绘图片。(在初始化里重绘是不行的)

vector

添加头文件#include vector容器,std::vector<类型*> name; push_back添加元素。 遍历元素使用迭代器iterator,for循环 vector<数据类型>::iterator it; for(it=数据.begin();it!=数据.end();it++) { //操作 Break; }

map

添加头文件#include std::map<CString, std::vector<信息» 一个CString对应一个vector。查询时也是先遍历(迭代器)再比较,it->first指代返回关键字,it->second指代数据。

父子循环

父子循环遍历时避免使用相同的变量名。

几个函数

检查路径合法性 PathFileExists(path),使用它需要加上头文件#include “shlwapi.h” 字符连接 CString str; str.Format(("%s%s\%s\"),path,“第三层”,“第四层”)); 复制文件CopyFile(原完整带后缀路径,复制后的带后缀完整目的路径,TRUE); 该函数有返回值 比较

1
2
3
4
if(strTemp.Compare("相比较的字符串")==0)
{
//操作
}

创建临时文件夹

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
TCHAR Temp[512];
GetTempPath(512, Temp);
CString strTempPath;
strTempPath.Format("%s\\Mydata", Temp);
if (!PathFileExists(strTempPath))
{
	if (!CreateDirectory(strTempPath, NULL))
	{
		ASSERT(FALSE);
		return;
	}
}

复制文件夹及子文件

写一个函数CopyDiretory(CString source, CString target)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
	CFileFind finder;
bool bWorking = finder.FindFile(source);
while (bWorking)
{
	bWorking = finder.FindNextFile();
	if (finder.IsDirectory() && !finder.IsDots())
	{
		copyDiretory(finder.GetFilePath(), target + "\\" + finder.GetFileName();
	}
	else
	{
		Bool temp = CopyFile(finder.GetFilePath(), target + "\\" + finder.GetFileName(), FALSE);
		if (temp == 0)
		{
			MessageBox("复制失败!");
			return;
		}
	}
}
	
}

删除文件目录及子文件夹

写一个DeleteDirectory函数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
CFileFind finder;
CString path;
path.Format("%s\\*.*", directorypath);
BOOL bWorking = finder.FindFile(path);
while (bWorking)
{
	bWorking = finder.FindNextFile();
	if (finder.IsDirectory() && !finder.IsDots())
	{
		DeleteDirectory(finder.GetFilePath());
		RemoveDirectory(finder.GetFilePath();)
	}
	else
	{
		DeleteFile(finder.GetFilePath());
	}
	finder.Close();
	RemoveDirectory(directoryPath);
	return 0;
}

文件遍历

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
CFileFind finder;
CString strName;
BOOL bWorking = finder.FindFile(path);
std::vector<CString>a;
while (bWorking)
{
	bWorking = finder.FindNextFile();
	strName = finder.GetFileName();
	a.push_back(strName);//获取全部文件名
	vector<CString>::iterator it;
	for (it = a.begin(); it != a.end(); it++)
	{
		if ((*it) == strFileName)
		{
			//需要的处理代码
			break;
		}
	}

}

截取字符串

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
char* temp = new char[260];
::GetCurrentDirectory(260, temp);//得到的是DWord型
CString strTempDir = temp;
char* str = strTempDir.GetBuffer(strTempDir.GetLength() + 1);
char* delim = "\\";
char* buf;
char* p1 = strtok_s(str, delim, &buf);
char*p2 = strtok_s(NULL, delim, &buf);
CString strp1 = (_bstr_t)p1;
CString strp2 = (_bstr_t)p2;

循环截取

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
char* str = strName.GetBuffer(strName.GetLength() + 1);
char* delim = "\\";
char* buf;
int count = 0;
for (int i = 0; str[i]; i++)
{
	if (str[i] == *delim)
	{
		count++;
	}
	char* p = strtok_s(str, delim, *buf);
	for (int j = 0; j < count; j++)
	{
		p = strtok_s(NULL, delim, &buf);
	}
	CString strp = (_bstr_t)p;

}

禁用

GetDlgItem(IDC_Text)->EnableWindow(FALSE);

调用exe

法一: UINT temp=WinExec(strPath,SW_SHOWNORMAL); 法二:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15

STARTUPINFO si;
memset(&si, 0, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOW;
PROCESS_INFORMATION pi;
BOOL bDemoPro = CreateProcess(path, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
if (!bDemoPro)
{
	ASSERT(FALSE);
}
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);

窗口缩放

.h文件中: protected: afx_msg void OnSize(UINT nType,int cx, int cy); POINT old; CRect m_rect;

.cpp文件中: ON_WM_SIZE()

在OnInitDialog()中:

1
2
3
GetClientRect(&m_rect);//初始大小
old.x = m_rect.right - m_rect.left;
old.y = m_rect.bottom - m_rect.top;

在OnSize函数中:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
{
	CDialog::OnSize(nTpye, cx, cy);
	//TODO
	float fsp[2];
	POINT Newp;
	CRect rectNow;
	GetClientRect(&rectNow);
	Newp.x = rectNow.right - rectNow.left;
	Newp.y = rectNow.bottom - rectNow.top;
	fsp[0] = (float)Newp.x / old.x;
	fsp[1] = (float)Newp.y / old.y;
	CRect Rect;
	int woc;
	CPoint OldTLPoint, TLPoint;//左上
	CPoint OldBRPoint, BRPoint;//右下
	HWND hwndChild = ::GetWindow(m_hWnd, GW_CHILD);//列出所有控件
	while (hwndChild)
	{
		woc = ::GetDlgCtrlID(hwndChild);
		GetDlgItem(woc)->GetWindowRect(Rect);
		ScreenToClient(Rect);
		OldTLPoint = Rect.TopLeft();
		TLPoint.x = long(OldTLPoint.x*fsp[0]);
		TLPoint.y = long(OldTLPoint.y*fsp[1]);
		OldBRPoint = Rect.BottomRight();
		BRPoint.x = long(OldBRPoint.x*fsp[0]);
		BRPoint.y = long(OldBRPoint.y*fsp[1]);
		Rect.SetRect(TLPoint, BRPoint);
		GetDlgItem(woc)->MoveWindow(Rect, TRUE);
		hwndChild = ::GetWindow(hwndChild, GW_HWNDNEXT);
	}
	old = Newp;
}

更新数据

UpdateData(TRUE);//更新值到界面 UpdateData(FALSE);//更新界面到值

数据类型转换

  1. int转CString iRow是int型,number是CString型。 CString number; number.Format("%d", iRow);

2._variant_t转int _variant_t a; int b; b=_ttoi((LPCTSTR)(_bstr_t)a);


slug: FgrL9cJx aliases: [‘2017/07/20/树状控件与列表控件交互以及XML的解析/’] title: 树状控件与列表控件交互以及XML的解析 字数统计: WordCount date: 2017-07-20 23:04:43 updated: 2017-09-10 16:47:42 tags: [MFC, CPP, XML] categories: 编程语言

现有一个XML文档如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<root>
	<Node world = "生命">
		<Node animal = “动物">
			<Node aniname = "熊猫">
			</Node>
			<Node aniname = "兔子">
			</Node>
		</Node>
		<Node plant = "植物">
			<Node planame = "仙人掌">
			</Node>
			<Node planame = "玫瑰">
			</Node>
		</Node>
	</Node>
</root>

要求在树状控件上显示如下: –root —-动物 —-植物

在树状控件上点击“动物”,在列表控件上出现 1 熊猫 2 兔子

同理,点击“植物”,在列表控件上出现 1 仙人掌 2 玫瑰

思维碰撞

之前的思路:先SelectedSingleNode("/Node/Node"),定位到动物这一层。然后获得该结点的属性即aniname,插入树状控件。接着指向其兄弟结点,将兄弟结点(植物)的属性同样插入树状控件。如果新插入结点,可能需递归(但都是在动物同层面)。 因为并没有将“熊猫”“兔子”插入树状控件,因此无法使用m_tree.GetChildItem(ht)获取。所以我想通过“动物”植物“的aniname和planame来反过来查找对应xml里的结点pNode(这里存在问题how to find it?遍历xml找同样的名字?Item能和node存在对应关系么)。找到后,只需GetChildNode之类获取孩子结点,再插入到列表控件中(也就是和列表控件交互实际是列表控件在和xml直接交互,树控件只起到选择某个item,对应到xml中)。 简单说来:选择树结点->获得该xml对应结点->获得每一个孩子结点->获得孩子结点的文本和其他路径属性->通过列表插入

就算是为树状控件和列表控件设置一个类或者一个结构,先要把xml所需的信息全部放入。毕竟投射到树状控件的结点并非全部结点,最重要的是列表控件所需结点不在树状控件中。那么添加删除时,对应的类或结构也应相应操作,是否繁琐。但感觉之前用树控件用错了,只是获取了文本,数据并没传入。

又过了一天。思路变为:为不直接操作XML,应创建一个结构体,利用MSXML解析XML将信息放入结构体中,在后续树状控件和列表控件操作时都调用该结构体而非XML。

前面那么多废话,其实说白了就是要自己生成一棵树,数据来源是xml,通过MSXML获得每个结点信息,自己生成的树中只包含所需要的xml片段信息,之后树控件根据指针来获得选择结点的孩子结点。 xml解析的最关键之处,就是如何将xml文件内容解析成内存中的可用、易用的程序数据—DOM(Document Object Model)树。DOM其实就是多叉树,每个节点只需知道自己的第一个子节点(first child)和下一个兄弟节点(next sibling),即可实现元素数据的解析。

理一理六层结构: map->分类节点->vector->n个小节点->结构体->xml

如果要求分类节点就一层,是完全OK的。但如果要求分类下面还需要小分类,这就很不ok了。换为 两个结构体:1)小节点结构体->xml 2)分类节点结构体->vector->1)

发现六层结构办不到时,仿佛多米诺骨牌立到最后几块,突然看到最开始的一段里有一块距离放远了…… 但换成双结构体其实改动也没太多,又好像把那块出差错的给换了块适合长度的,整个链条还是能补完整的。 思维过山车 跌宕起伏

Licensed under CC BY-NC-SA 4.0
最后更新于 0001-01-01 00:00 UTC
使用 Hugo 构建
主题 StackJimmy 设计