夜雨聆风学习资料网

ARTICLE · 984594

【源码】批量属性文字内容同步,属性块批量修改属性,批量修改块属性

【源码】批量属性文字内容同步,属性块批量修改属性,批量修改块属性
多个属性块具有相同的块定义,如何根据已处理好的模板,批量属性文字内容同步呢?比如PT 01的只同步修改相应的属性文字内容,PT 03只同步修改相应的属性文字内容呢?
手动修改非常浪费时间,也很枯燥,不如写一个程序来实现。
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(属性名, 属性值)
    刷新显示

相关学习资料