自查笔记。
方法记录
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
父子循环
父子循环遍历时避免使用相同的变量名。
几个函数
检查路径合法性 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); 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); 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);//更新界面到值
数据类型转换
- 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)
发现六层结构办不到时,仿佛多米诺骨牌立到最后几块,突然看到最开始的一段里有一块距离放远了……
但换成双结构体其实改动也没太多,又好像把那块出差错的给换了块适合长度的,整个链条还是能补完整的。
思维过山车 跌宕起伏