自查笔记。
  
   

方法记录

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);


MSDN参考

MSXML

MSXML API 历史记录 https://msdn.microsoft.com/zh-cn/library/ms762314(v=vs.85).aspx

MSXML SDK 概述 https://msdn.microsoft.com/zh-cn/library/ms760399(v=vs.85).aspx

TreeControl控件

使用 CTreeCtrl https://msdn.microsoft.com/zh-cn/library/8ws6dh1y(v=vs.120).aspx

ListControl控件

使用 CListCtrl https://msdn.microsoft.com/zh-cn/library/cc468276(v=vs.71).aspx
创建列表控件 (List Control) https://msdn.microsoft.com/zh-cn/library/cc451545(v=vs.71).aspx


现有一个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)

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