ARTICLE · 984594
【源码】批量属性文字内容同步,属性块批量修改属性,批量修改块属性
【源码】批量属性文字内容同步,属性块批量修改属性,批量修改块属性
多个属性块具有相同的块定义,如何根据已处理好的模板,批量属性文字内容同步呢?比如PT 01的只同步修改相应的属性文字内容,PT 03只同步修改相应的属性文字内容呢? 手动修改非常浪费时间,也很枯燥,不如写一个程序来实现。 处理后效果如下: 
阶段 3:构建源映射表

voidYJCMD::YJRefreshAttrText(){struct resbuf *rb;//结果缓冲表rb=acutBuildList(RTDXF0,TEXT("INSERT"),RTNONE);std::vector<AcDbObjectId> arrSrc = YJArxUtil::SelectUtil::SelectEnt(rb, _T("\n请选择源属性块"), _T("\n请选择源属性块"));std::vector<AcDbObjectId> arrDst = YJArxUtil::SelectUtil::SelectEnt(rb, _T("\n请选择目标属性块"), _T("\n请选择目标属性块"));acutRelRb(rb);if (arrSrc.size() < 1 || arrDst.size() < 1){acutPrintf(_T("\n源属性块或目标属性块的个数小于1!")); return;}std::vector<size_t> arrIndex;//用户输入的主键{YJArxUtil::YJBlockReferencePtr pBlkRef(arrSrc.at(0));if (!pBlkRef.IsOpenCorrectly())return;std::map<CString, CString> mapKeyVal;YJArxUtil::BlockUtil::GetBlockReferenceAttribute(pBlkRef, mapKeyVal);if (mapKeyVal.size() < 2){acutPrintf(_T("\n属性个数小于2,不需要使用本命令了!")); return;}int i = 1; std::vector<CString> arrKey;for (std::map<CString, CString>::iterator it = mapKeyVal.begin(); it != mapKeyVal.end(); ++it){acutPrintf(_T("\n属性%d的Key为%s"), i, it->first);arrKey.push_back(it->first); i++;}ACHAR sInput[128];if (RTNORM != acedGetString(0, _T("\n请选择用做主键Key的属性的序号,多个时需要使用;分割"), sInput)){acutPrintf(_T("\n未选择主键!")); return;}std::vector<CString> arrStr;YJArxUtil::TextUtil::SplitCString(CString(sInput), _T(";"), arrStr, false, true);for (size_t i = 0; i < arrStr.size(); ++i){int index = (int)_tstof(arrStr.at(i));index--;if (index > -1 && index < arrKey.size())arrIndex.push_back(index);}//std::sort(arrIndex.begin(), arrIndex.end());//排序}std::map<CString, std::map<CString, CString> > mapSrc;for(size_t m=0;m<arrSrc.size();++m){YJArxUtil::YJBlockReferencePtr pBlkRef(arrSrc.at(m));if (!pBlkRef.IsOpenCorrectly())return;std::map<CString, CString> mapKeyVal;YJArxUtil::BlockUtil::GetBlockReferenceAttribute(pBlkRef, mapKeyVal);if (mapKeyVal.size() < 2){acutPrintf(_T("\n属性个数小于2,不需要使用本命令了!")); continue;}CString sKey;for (size_t n = 0; n < arrIndex.size(); ++n){int i = 0;for (std::map<CString, CString>::iterator it = mapKeyVal.begin(); it != mapKeyVal.end(); ++it){if (i == arrIndex.at(n)){sKey += it->second; break;//注意这里使用的是second}i++;}}mapSrc[sKey] = mapKeyVal;}//开始匹配for (size_t m = 0; m < arrDst.size(); ++m){YJArxUtil::YJBlockReferencePtr pBlkRef(arrDst.at(m),AcDb::kForWrite);if (!pBlkRef.IsOpenCorrectly())return;std::map<CString, CString> mapKeyVal;YJArxUtil::BlockUtil::GetBlockReferenceAttribute(pBlkRef, mapKeyVal);if (mapKeyVal.size() < 2){acutPrintf(_T("\n属性个数小于2,不需要使用本命令了!")); continue;}CString sKey;for (size_t n = 0; n < arrIndex.size(); ++n){int i = 0;for (std::map<CString, CString>::iterator it = mapKeyVal.begin(); it != mapKeyVal.end(); ++it){if (i == arrIndex.at(n)){sKey += it->second; break;//注意这里使用的是second}i++;}}std::map<CString, std::map<CString, CString> >::iterator it = mapSrc.find(sKey);if (it == mapSrc.end())continue;mapKeyVal = it->second;size_t i = 0;for (std::map<CString, CString>::iterator it = mapKeyVal.begin(); it != mapKeyVal.end(); ++it){bool bFind = false;for (size_t n = 0; n < arrIndex.size(); ++n){if (i == arrIndex.at(n)){bFind = true; break;}}if (!bFind)//没有找到的才需要设置{YJArxUtil::BlockUtil::SetBlockRefAttribute(pBlkRef, it->first, it->second);}i++;}pBlkRef->recordGraphicsModified();pBlkRef->draw();//刷新界面显示actrTransactionManager->queueForGraphicsFlush();actrTransactionManager->flushGraphics();acedUpdateDisplay();}acutPrintf(_T("\n替换完毕!"));}

程序思路分析
一、功能概述
这是一个 ObjectARX 命令:属性块批量刷新——把一个"源属性块"的属性值,通过"主键匹配"同步到多个"目标属性块"上,且主键字段自身不被覆盖。
二、核心思路(4 个阶段)
阶段 1:选择实体
用 acutBuildList(RTDXF0, "INSERT", ...)构造过滤器,只选块参照(INSERT)用户交互选择源属性块集合(arrSrc)和目标属性块集合(arrDst) 校验两组都 ≥ 1 个
阶段 2:交互式选择主键
读取第一个源块的所有属性(Key=属性名, Value=属性值) 把所有 Key 打印出来让用户看(序号 1, 2, 3...) 用户输入"用做主键的属性序号",多个用 ;分隔(如1;3表示第 1 和第 3 个属性联合做主键)解析:字符串→数字→ index--(用户 1-based → 程序 0-based)→arrIndex
阶段 3:构建源映射表 mapSrc
遍历每个源块:
读属性 mapKeyVal
按 arrIndex 取出对应 Value,拼接成 sKey(主键字符串)
mapSrc[sKey] = mapKeyVal(整个属性的 Key-Value 映射)
潜在问题:若多个源块主键相同,map 会后者覆盖前者。
阶段 4:匹配并刷新目标块
遍历每个目标块 (kForWrite 打开):
读其属性 → 同样按 arrIndex 拼 sKey
mapSrc.find(sKey):
未找到 → continue(跳过)
找到 → 遍历源块的所有属性:
若是主键序号(arrIndex) → 跳过(不覆盖)
否则 → SetBlockRefAttribute(属性名, 属性值)
刷新显示