MFC开发xml编辑器整理
xml格式如下所示:
<CalibrationData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<CalConfig name="TEST">
<CalPath number="1" name="ANT0" data="2022-10-11 20:05:51" dayLimit="999">
<CalPoint key="822.500" value="1100"/>
<CalPoint key="1745.00" value="0.72"/>
<CalPoint key="1747.50" value="0.71"/>
</CalPath>
<CalPath number="2" name="ANT1" data="2022-10-11 20:05:51" dayLimit="999">
<CalPoint key="195000" value="1500"/>
<CalPoint key="1784.90" value="0.78"/>
<CalPoint key="1785.00" value="0.78"/>
<CalPoint key="1805.00" value="0.80"/>
<CalPoint key="1840.00" value="0.68"/>
</CalPath>
<CalPath number="3" name="ANT2" data="2022-10-11 20:05:51" dayLimit="999">
<CalPoint key="192500" value="4100"/>
</CalPath>
<CalPath number="4" name="ANT3" data="2022-10-11 20:05:51" dayLimit="999">
<CalPoint key="192500" value="2900"/>
</CalPath>
<CalPath number="5" name="ANT4" data="2022-10-11 20:05:51" dayLimit="999">
<CalPoint key="35000" value="3200"/>
</CalPath>
</CalConfig>
</CalibrationData>
设计步骤:
1.拖入treeControl控件,创建变量m_tree,用于显示TEST节点下的子节点CalPath
向tree插入节点
CString strName(_T(""));
HTREEITEM hCalConfig = m_tree.InsertItem(strName);
m_tree.InsertItem(strName, hCalConfig);
2.拖入listControl控件,创建变量m_list,用于显示子节点CalPoint 的属性值
表格中插入表头信息,并设置格式
m_list.ModifyStyle( 0, LVS_REPORT ); // 报表模式
m_list.SetExtendedStyle(m_list.GetExtendedStyle() | LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT /*| LVS_EX_CHECKBOXES*/);
CRect rect;
m_list.GetClientRect(rect);
m_list.InsertColumn(0, L"", LVCFMT_CENTER);
m_list.InsertColumn(1, L"freq", LVCFMT_CENTER, rect.Width() / 2);
m_list.InsertColumn(2, L"loss", LVCFMT_CENTER, rect.Width() / 2);
CImageList image;
image.Create(1, 25, TRUE | ILC_COLOR16, 1, 0); //设置表格的高度
m_list.SetImageList(&image, LVSIL_SMALL);
m_list.DeleteColumn(0);//第一列无法居中显示,删除第一列
双击表格实现内容可编辑,需要往界面上拖入Edit Control控件
OnDblclkList(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
m_hitRow = pNMListView->iItem;//获得选中的行
m_hitCol = pNMListView->iSubItem;//获得选中列
if (m_hitRow != -1 && m_hitCol != -1 )
{
/*if (pNMListView->iSubItem == 0)
{
return;//设置第一列不可编辑
}*/
CRect rect;
m_list.GetSubItemRect(m_hitRow, m_hitCol, LVIR_LABEL, rect);
m_editListCtrl.SetWindowText(m_list.GetItemText(m_hitRow, m_hitCol));
m_editListCtrl.SetParent(&m_list);
m_editListCtrl.MoveWindow(&rect, TRUE);
m_editListCtrl.ShowWindow(TRUE);
m_editListCtrl.SetFocus();
m_editListCtrl.ShowCaret();//显示光标
m_editListCtrl.SetSel(-1);
}
*pResult = 0;
}
编辑框中的光标消失后,将数据保存到表格中
OnKillfocusEdit()
{
// TODO: 在此添加控件通知处理程序代码
CString str;
m_editListCtrl.GetWindowText(str); //得到用户输入的新的内容
m_list.SetItemText(m_hitRow, m_hitCol, str); //设置编辑框的新内容
m_editListCtrl.ShowWindow(SW_HIDE); //应用编辑框
//同步节点中保存的信息
if (!m_hEditItem)
{
return;
}
CString text = m_tree.GetItemText(m_hEditItem);
//CalPoint节点,将界面上修改的参数保存到m_mapDataMT
map<CString, CalPath>::iterator ite = m_mapDataMT.find(text);
if (ite == m_mapDataMT.end())
{
return;
}
vector<map<CString, CString>>& vecCalPoint = ite->second.CalPathList;
//修改数据的行数要小于vecCalPoint容器大小
if (m_hitRow < (int)vecCalPoint.size())
{
map<CString, CString>& mapCalPoint = vecCalPoint[m_hitRow];
if (0 == m_hitCol)
{
mapCalPoint[L"freq"] = str;
}
else if (1 == m_hitCol)
{
mapCalPoint[L"loss"] = str;
}
}
}
3.本文借用MSXML读取和修改xml属性值,需要在头文件 #import <msxml4.dll> 这是微软库
ReadXml(CString strXmlPath, bool bModify)
{
if (strXmlPath.IsEmpty())
{
MessageBox(_T("xml文件名为空"), _T("错误"), MB_ICONERROR);
}
MSXML2::IXMLDOMDocumentPtr pDoc;
::CoInitialize(NULL);
HRESULT hr = pDoc.CreateInstance(__uuidof(MSXML2::DOMDocument40));
if (!SUCCEEDED(hr))
{
MessageBox(_T("创建DOMDocument对象失败。\n请检查运行环境"), _T("错误"), MB_ICONERROR);
return;
}
// 读取xml
pDoc->put_async(VARIANT_FALSE);
VARIANT_BOOL bhr = pDoc->load((_variant_t)strXmlPath);
if (bhr != VARIANT_TRUE) {
MessageBox(_T("无法正确读取xml文件"), _T("错误"), MB_ICONERROR);
return;
}
// 根节点取得
MSXML2::IXMLDOMElementPtr root = pDoc->documentElement;
// 取得根节点的名字
_variant_t strRootName = root->nodeName;
_bstr_t wstrRootName(strRootName.bstrVal);
MSXML2::IXMLDOMNodeListPtr nodeList = root->GetchildNodes();
// 解析CalibrationData的子节点
ReadCalConfig(nodeList, bModify);
if (bModify)
{
pDoc->save((_variant_t)strXmlPath);
}
}
ReadCalConfig(MSXML2::IXMLDOMNodeListPtr nodeList, bool bModify )
{
int ilength = nodeList->Getlength();
for (int nodeCount = 0; nodeCount < ilength; nodeCount++) {
MSXML2::IXMLDOMNodePtr nodePtr = nodeList->nextNode();
_variant_t strNodeName = nodePtr->GetnodeName();
_variant_t strNodeValue = nodePtr->GetnodeValue();
// 取得节点的属性值
MSXML2::IXMLDOMNamedNodeMapPtr pDOMAttrList= nodePtr->Getattributes();
MSXML2::IXMLDOMNodePtr pDOMAttr= pDOMAttrList->Getitem(0);
CString cstrValue = (CString)(char*)pDOMAttr->GetnodeName();
if (0 == CString(L"name").CompareNoCase(cstrValue))
{
CString strName =pDOMAttr->GetnodeTypedValue();
//向combox插入CalConfig节点列表
m_comNodeList.AddString(strName);
int nSel = m_comNodeList.GetCurSel();
CString cstrEditNode = _T("");
if (nSel > -1)
{
m_comNodeList.GetLBText(nSel, cstrEditNode);
}
//判断combox控件中,当前名字是否跟xml的节点名字一样
if (cstrEditNode == strName && bModify)
{
ReadCalPath(nodePtr->GetchildNodes(), true);
}
else if (cstrEditNode == strName && !bModify)
{
m_hCalConfig = m_tree.InsertItem(strName);
// 读取指定节点的 CalConfig节点下的子节点
ReadCalPath(nodePtr->GetchildNodes());
}
}
}
}
ReadCalPath(MSXML2::IXMLDOMNodeListPtr nodeList, bool bModify)
{
CString strNo;
CString strNumber; // number
CString strName; // name
for (int nodeCount = 0; nodeCount < nodeList->Getlength(); nodeCount++)
{
MSXML2::IXMLDOMNodePtr nodePtr = nodeList->nextNode();
_variant_t strCaseNodeName = nodePtr->GetnodeName();//获取节点的名字
_variant_t strCaseNodeValue = nodePtr->Gettext();//获取节点内的值
BSTR bStrTemp = strCaseNodeName.bstrVal;
CString strTemp = CString(bStrTemp);
SysFreeString(bStrTemp);
CString strNodeName = strTemp;
// 节点有属性值
if (0 == strNodeName.CompareNoCase(_T("CalPath")))
{
strNumber.Empty();
strName.Empty();
// 取得节点的属性值
MSXML2::IXMLDOMNamedNodeMapPtr pDOMAttrList= nodePtr->Getattributes();
for (int j = 0; j < pDOMAttrList->Getlength(); j++)
{
MSXML2::IXMLDOMNodePtr pDOMAttr= pDOMAttrList->Getitem(j);
CString cstrValue = (CString)(char*)pDOMAttr->GetnodeName();
if (0 == CString(L"number").CompareNoCase(cstrValue))
{
strNumber = pDOMAttr->GetnodeTypedValue();
}
else if (0 == CString(L"name").CompareNoCase(cstrValue))
{
strName =pDOMAttr->GetnodeTypedValue();
//向树控件插入节点
if (!bModify)
{
m_tree.InsertItem(strName, m_hCalConfig);
}
}
}
}
if (bModify)
{
//修改xml节点的值
ModifyCalPoint(nodePtr->GetchildNodes(), strName);
}
else
{
//只读xml节点的值
ReadCalPoint(nodePtr->GetchildNodes(), strName);
}
}
}
ReadCalPoint(MSXML2::IXMLDOMNodeListPtr nodeList, CString cstr)
{
CString strNo;
CString strKey; // key
CString strValue; // value
vector<map<CString, CString>> vecCalPath;
for (int nodeCount = 0; nodeCount < nodeList->Getlength(); nodeCount++)
{
MSXML2::IXMLDOMNodePtr nodePtr = nodeList->nextNode();
_variant_t strCaseNodeName = nodePtr->GetnodeName();
_variant_t strCaseNodeValue = nodePtr->Gettext();
BSTR bStrTemp = strCaseNodeName.bstrVal;
CString strTemp = CString(bStrTemp);
SysFreeString(bStrTemp);
CString strNodeName = strTemp;
// 节点没有属性值
if (0 != strNodeName.CompareNoCase(_T("CalPoint")))
{
continue;
}
strKey.Empty();
strValue.Empty();
map<CString, CString> mapCalPoint;
// 取得节点的属性值
MSXML2::IXMLDOMNamedNodeMapPtr pDOMAttrList= nodePtr->Getattributes();
for (int j = 0; j < pDOMAttrList->Getlength(); j++)
{
MSXML2::IXMLDOMNodePtr pDOMAttr= pDOMAttrList->Getitem(j);
CString cstrValue = (CString)(char*)pDOMAttr->GetnodeName();
if (0 == CString(L"key").CompareNoCase(cstrValue))
{
strKey= pDOMAttr->GetnodeTypedValue();
mapCalPoint.insert(make_pair(L"key", strFreq));
}
else if (0 == CString(L"value").CompareNoCase(cstrValue))
{
strValue=pDOMAttr->GetnodeTypedValue();
mapCalPoint.insert(make_pair(L"value", strLoss));
}
}
vecCalPath.push_back(mapCalPoint);
}
CalPath calPoint;
calPoint.CalPathList = vecCalPath;
m_mapDataMT.insert(make_pair(cstr, calPoint));
}
ModifyCalPoint(MSXML2::IXMLDOMNodeListPtr nodeList, CString cstr)
{
CString strNo;
vector<map<CString, CString>> vecCalPath = m_mapDataMT[cstr].CalPathList;
for (int nodeCount = 0; nodeCount < nodeList->Getlength(); nodeCount++)
{
MSXML2::IXMLDOMNodePtr nodePtr = nodeList->nextNode();
_variant_t strCaseNodeName = nodePtr->GetnodeName();
_variant_t strCaseNodeValue = nodePtr->Gettext();
BSTR bStrTemp = strCaseNodeName.bstrVal;
CString strTemp = CString(bStrTemp);
SysFreeString(bStrTemp);
CString strNodeName = strTemp;
// 节点没有属性值
if (0 != strNodeName.CompareNoCase(_T("CalPoint")) || MSXML2::DOMNodeType::NODE_COMMENT == nodePtr->GetnodeType())
{
continue;
}
map<CString, CString> mapCalPoint = vecCalPath[nodeCount];
// 取得节点的属性值
MSXML2::IXMLDOMNamedNodeMapPtr pDOMAttrList= nodePtr->Getattributes();
for (int j = 0; j < pDOMAttrList->Getlength(); j++)
{
MSXML2::IXMLDOMNodePtr pDOMAttr= pDOMAttrList->Getitem(j);
CString cstrValue = (CString)(char*)pDOMAttr->GetnodeName();
if (0 == CString(L"key").CompareNoCase(cstrValue))
{
variant_t var = (LPCTSTR)(mapCalPoint[L"key"]);
pDOMAttr->PutnodeTypedValue(var);
}
else if (0 == CString(L"value").CompareNoCase(cstrValue))
{
variant_t var = (LPCTSTR)(mapCalPoint[L"value"]);
pDOMAttr->PutnodeTypedValue(var);
}
}
}
}