引言 中车大同的旧图纸转换功能的定制开发告一段落,这段时间和周工学到了很多有用的知识,特此记录这个项目学到的编程技巧和项目开发经验。
容器越界问题 在这个项目中我有很多时候对数组越界问题并不敏感,导致在一些情况下程序直接崩溃了,下面举一些具体的例子:
bool parseDTTitleBar(const CString & filePath) { const auto titleBar = parseFile(filePath, titleBarSection[0]); const auto splitTitleBar = splitProfileString(titleBar); for (auto& item : splitTitleBar) { auto vec = item.second; + if (!vec.empty() && vec.size() == 10) titleBarDefItems_.emplace_back(item.first, vec[0], vec[1], _ttof(vec[5]), _ttof(vec[6]), _ttof(vec[7]), vec[4], _ttof(vec[2]), _ttof(vec[3]), vec[8], vec[9]); } if (titleBarDefItems_.empty()) return false; return true; }
本例中我去实例化一个对象,但使用的方式是直接选取 vec
元素没有增加数量判断。倘若 vec
只有 6 个元素但代码中却取到了 vec[9]
就会导致崩溃。
前向声明 前向声明是我编程时忽略掉的一个细节,在之前学校里写的代码只要编译能过去就不考虑这些问题了,但工作中需要注意效率。
#pragma once #include "jsoncpp/value.h" #include "EditableListCtrl.h" -#include "AbstractDetailsCreator.h" // DlgCvtMain 对话框 #include <vector> class DataRow; class AbstractPaperSelector; class PaperCreator; class PaperSizeDefinition; +class AbstractDetailsCreator;
#include
所做的就是将整个代码复制过来,而这里我们并不关心 AbstractDetailsCreator
具体如何是什么,只需要知道有这样一个类型存在即可,这时就可以用前置声明而非引入整个头文件。
从代码编写的优雅程度来讲这样也会让阅读代码更加容易,不会因为引入过多无关头文件而一头雾水。前置声明最大的好处在于避免编译膨胀,一个优秀的 CPP 代码应该只包含它的最小代码集合。
实体的 XData 读取 自己经常忘记如何读取实体的 XData,特此记录:
AcDbObjectPointer<AcDbText> text (textId) ;if (text.openStatus () != eOk) continue ;const auto xData = text->xDataPtr (TitleTextAppName);if (xData.isNull () || xData->next ().isNull () || xData->next ()->restype () != OdResBuf::kDxfXdAsciiString) continue ; CString itemName = xData->next ()->getString (); ...
获取链表后根据所需类型选择相应 get
函数即可。
以组为单位的图框定位点平移 大同希望把我们产品的图框插入点由内框左下点改为外框左下点,需要以组为单位做一下平移操作。思路上还是比较清晰的:
获取当前图纸中图框所在的组 以国标为例需要根据装订线有无确定平移所需的偏移量 遍历组进行平移操作 AcDbDictionaryPointer dict (acdbCurDwg()->groupDictionaryId(), kForRead) ;if (dict.openStatus () != eOk) return ;AcDbObjectPointer<AcDbGroup> paperGroup; if (dict->getAt (_T("PAPERGROUP" ), (AcDbGroup*&)paperGroup, kForRead) != Acad::eOk) return ;AcDbObjectPointer<AcDbGroup> group (paperGroup->objectId(), kForRead) ;if (group.openStatus () != eOk) return ;AcGeMatrix3d mat; double xOffset = 0.0 , yOffset = 0.0 ;if (g_paper.bZhuangding){ xOffset = g_paper.a; yOffset = g_paper.c; } else xOffset = yOffset = g_paper.e; AcGeVector3d transVec (xOffset, yOffset, 0 ) ;mat.setToTranslation (transVec); unique_ptr<AcDbGroupIterator> groupIter (group->newIterator()) ;if (groupIter == nullptr ) return ;for (; !groupIter->done (); groupIter->next ()){ AcDbObjectPointer<AcDbBlockReference> blkRef (groupIter->objectId(), kForWrite) ; if (blkRef.openStatus () != eOk) continue ; blkRef->transformBy (mat); }
附加栏缩放 附加栏缩放方式由变换矩阵改为修改实体的缩放因子:
AcDbObjectId idEnt; if (acdbGetObjectId(idEnt, entIns) == Acad::eOk) { AcDbObjectPointer<AcDbBlockReference> pEntity(idEnt, AcDb::kForWrite); if (pEntity.openStatus() == Acad::eOk) { - AcGeMatrix3d matrix; - matrix.setToScaling(scale); - pEntity->transformBy(matrix); + pEntity->setScaleFactors({ scale, scale, scale }); } }
重写读取 .ini
文件函数 业务场景 业务场景需要读取下面的 .def
配置文件:
[Info] bindingEditable =0 bindingDefault =1 bindingAreaWidth =20 bindingEtcAreaWidth =5 notBindingWidth =0 splitEditable =1 splitDefault =1 splitTextHeight =3.5 middleEditable =1 middleDefault =1 attachBarEditable =0 attachBarDefault =0 mainTitleBarHeight =63 bomHeaderHeight =9.993 bomTextBlockHeight =7 bomTextBlockExtHeight =10 [DTTitleBar] main = 主标题栏lb = 副标题栏签字lt = 副标题栏图样代码[DTTitleBarText] IRB001 = 图样代码IRB002 = 中文名称IRB003 = 中文材料IRB004_ZhiLiang = 质量IRB005_BiLi = 比例IRB006 = 共张IRB007 = 第张IRB008_TuFu = 图幅IRB009 = 俄文名称IRB010 = 俄文材料IRB011 = 订货号IRB012 = 识别符号1 IRB013 = 识别符号2 IRB014 = 识别符号3 IRB015 = 复印人员ILB001 = (左)国家标准登记号ILB002 = (左)签名和日期1 ILB003 = (左)替代正本号ILB004 = (左)副本登记号ILB005 = (左)签名和日期2 ILB006 = (左)替代文件代号ILB007 = (左)相应文件代号ILT001 = (上)专利编号ILT002 = (上)订货号标记ILT003 = (上)相应文件决议编号和批准年份ILT004 = (上)本文件决议编号和批准年份IRB101 = 更改区域1____ IRB102 = 变更序号1 IRB103 = 变更页码1 IRB104 = 通知单号1 IRB105 = 签名1 IRB106 = 日期1 IRB107 = 更改区域2____ IRB108 = 变更序号2 IRB109 = 变更页码2 IRB110 = 通知单号2 IRB111 = 签名2 IRB112 = 日期2 IRB113 = 更改区域3____ IRB114 = 变更序号3 IRB115 = 变更页码3 IRB116 = 通知单号3 IRB117 = 签名3 IRB118 = 日期3 IRB119 = 更改区域4____ IRB120 = 变更序号4 IRB121 = 变更页码4 IRB122 = 通知单号4 IRB123 = 签名4 IRB124 = 日期4 IRB125 =设计-文件数量IRB126 =审核-文件数量IRB127 =主任设计-文件数量IRB128 =工艺-文件数量IRB129 =标准化-文件数量IRB130 =批准-文件数量[DTTitleBarTextReference] tydmfz = 图样代码[DTBOM] bomHeader = 主明细栏bomTextBlock = 明细文字框bomTextBlockExt = 明细文字框扩展[DTBOMText] BOM001 = 序号BOM002 = 代码BOM003 = 代号BOM004 = 名称BOM005 = 数量BOM006 = 材料BOM007 = 单件BOM008 = 总计BOM009 = 附注EXT001 = 外文名称EXT002 = 外文材料[DTAttachBar] [DTAttachBarText]
.ini
文件结构我之前遇到的大部分配置文件的类型都是 .xml
或者 .josn
(现在网络端也是这两者使用比较多,属于通用的配置文件类型了),面对 .ini
文件还是比较陌生。 这里引用简书一位博主的 ini文件格式和读取 :
ini 就是英文 “initialization” 的头三个字母的缩写,当然 INI file 的后缀名也不一定是 .ini
,也可以是 .cfg
,.conf
或者是 .txt
。
ini 文件的格式很简单,最基本的三个要素是:parameters
,sections
和 comments
。
parameters ini 所包含的最基本的”元素”就是 parameter
,每一个 parameter
都有一个 name
和一个 value
,如下所示:
sections 所有的 parameters
都是以 sections
为单位结合在一起的。所有的 section
名称都是独占一行,并且 sections
名字都被方括号包围着([ section's name ]
)。
在 section
声明后的所有 parameters
都是属于该 section
。对于一个 section
没有明显的结束标志符,一个 section
的开始就是上一个 section
的结束,或者是 end of the file。 section
如下所示:
在 ini 文件中注释语句是以分号 ;
开始的。所有的所有的注释语句不管多长都是独占一行直到结束的。在分号和行结束符之间的所有内容都是被忽略的。
解决方案 项目的工具类中有之前写好的读取 .ini
配置文件函数:
...... CString IM_PUBLIC_FUNCTION_ IM_GetConfigFileValue ( CString szFileName , CString szSegName , CString szKeyName , CString szDefault = _T("" ) , int nMaxLength = 512 ) ;BOOL IM_PUBLIC_FUNCTION_ IM_SetConfigFileValue ( CString szFileName , CString szSegName , CString szKeyName , CString szValue ) ;#define WritePrivateProfileInt IM_WritePrivateProfileInt BOOL IM_PUBLIC_FUNCTION_ IM_WritePrivateProfileInt ( LPCTSTR lpAppName , LPCTSTR lpKeyName , int nValue , LPCTSTR lpFileName ) ;CString IM_PUBLIC_FUNCTION_ IM_GetPrivateProfileString ( LPCTSTR lpAppName, LPCTSTR lpKeyName, LPCTSTR lpDefault, LPCTSTR lpFileName , DWORD lMaxSize = 256 ) ;void IM_PUBLIC_FUNCTION_ IM_GetPrivateProfileSectionMap ( CString szAppName, CString szFilePath, map<CString,CString>& mapValue ) ;void IM_PUBLIC_FUNCTION_ IM_GetPrivateProfileAppNames (const CString &szFilePath, CStringArray &szAppNames) ;CString IM_PUBLIC_FUNCTION_ IM_GetSystemSettingProfile () ;......
这些函数的实现则是依赖于底层 Windows 提供的 API 接口 。
而在具体实践中,由于业务场景中 .ini
文件的 parameters
的 value
值过长,导致读取的时候出现遗漏的情况(下面以读取 [DTTitleBarText]
为例):
std::map<CString, CString> resultMap; IM_GetPrivateProfileSectionMap (L"DTTitleBarText" , filePath, resultMap);
得到的 resultMap
则是缺失了一部分:
[DTTitleBarText] IRB001 = 图样代码; 5; IRB; -60; 47.5; 0; MC; 120; STR; 0; 11; Standard; main; ; IRB002 = 中文名称; 5; IRB; -85; 33.75; 0; MC; 70; STR; 0; 11; Standard; main; ; IRB003 = 中文材料; 5; IRB; -85; 11.25; 0; MC; 70; STR; 0; 11; Standard; main; ; IRB004_ZhiLiang = 质量; 4; IRB; -26.5; 27.5; 0; MC; 17; STR; 0; 11; Standard; main; ; IRB005_BiLi = 比例; 4; IRB; -9; 27.5; 0; MC; 18; STR; 0; 11; Standard; main; ; IRB006 = 共张; 3.5; IRB; -15; 17.5; 0; MC; 30; STR; 0; 11; Standard; main; ; IRB007 = 第张; 3.5; IRB; -40; 17.5; 0; MC; 20; STR; 0; 11; Standard; main; ; IRB008_TuFu = 图幅; 4; IRB; -3.5; -2.5; 0; MC; 7; STR; 0; 11; Standard; main; ; IRB009 = 俄文名称; 5; IRB; -85; 21.25; 0; MC; 70; STR; 0; 11; Standard; main; ; IRB010 = 俄文材料; 5; IRB; -85; 3.75; 0; MC; 70; STR; 0; 11; Standard; main; ; IRB011 = 订货号; 4; IRB; -60; 59; 0; MC; 120; STR; 0; 11; Standard; main; ; IRB012 = 识别符号1; 4; IRB; -47.5; 27.5; 0; MC; 5; STR; 0; 11; Standard; main; ; IRB013 = 识别符号2; 4; IRB; -42.5; 27.5; 0; MC; 5; STR; 0; 11; Standard; main; ; IRB014 = 识别符号3; 4; IRB; -37.5; 27.5; 0; MC; 5; STR; 0; 11; Standard; main; ; IRB015 = 复印人员; 3.5; IRB; -70; -2.5; 0; ML; 30; STR; 0; 11; Standard; main; ; ILB001 = (左)国家标准登记号; 4; ILB; 8.5; 12.5; 90; MC; 25; STR; 0; 11; Standard; lb; ; ILB002 = (左)签名和日期1; 4; ILB; 8.5; 42.5; 90; MC; 35; STR; 0; 11; Standard; lb; ; ILB003 = (左)替代正本号; 4; ILB; 8.5; 72.5; 90; MC; 25; STR; 0; 11; Standard; lb; ; ILB004 = (左)副本登记号; 4; ILB; 8.5; 97.5; 90; MC; 25; STR; 0; 11; Standard; lb; ; ILB005 = (左)签名和日期2; 4; ILB; 8.5; 127.5; 90; MC; 35; STR; 0; 11; Standard; lb; ; ILB006 = (左)替代文件代号; 4; ILB; 8.5; 197; 90; MC; 60; STR; 0; 11; Standard; lb; ; ILB007 = (左)相应文件代号; 4; ILB; 8.5; 257; 90; MC; 60; STR; 0; 11; Standard; lb; ; ILT001 = (上)专利编号; 3; ILT; 35; -17.5; 0; MC; 70; STR; 0; 11; Standard; lt; ; -ILT002 = (上)订货号标记; 3; ILT; 77; -7; 0; MC; 14; STR; 0; 11; Standard; lt; ; -ILT003 = (上)相应文件决议编号和批准年份; 3; ILT; 110.5; -3.5; 0; MC; 53; STR; 0; 11; Standard; lt; ; -ILT004 = (上)本文件决议编号和批准年份; 3; ILT; 110.5; -10.5; 0; MC; 53; STR; 0; 11; Standard; lt; ; -IRB101 = 更改区域1____; 3; IRB; -195; 37.5; 0; MC; 20; STR; 0; 11; Standard; main; ; -IRB102 = 变更序号1; 3; IRB; -181.5; 37.5; 0; MC; 7; STR; 0; 11; Standard; main; ; -IRB103 = 变更页码1; 3; IRB; -173; 37.5; 0; MC; 10; STR; 0; 11; Standard; main; ; -IRB104 = 通知单号1; 3; IRB; -156.5; 37.5; 0; MC; 23; STR; 0; 11; Standard; main; ; -IRB105 = 签名1; 3; IRB; -137.5; 37.5; 0; MC; 15; STR; 0; 11; Standard; main; ; -IRB106 = 日期1; 3; IRB; -125; 37.5; 0; MC; 10; STR; 0; 11; Standard; main; ; -IRB107 = 更改区域2____; 3; IRB; -195; 42.5; 0; MC; 20; STR; 0; 11; Standard; main; ; -IRB108 = 变更序号2; 3; IRB; -181.5; 42.5; 0; MC; 7; STR; 0; 11; Standard; main; ; -IRB109 = 变更页码2; 3; IRB; -173; 42.5; 0; MC; 10; STR; 0; 11; Standard; main; ; -IRB110 = 通知单号2; 3; IRB; -156.5; 42.5; 0; MC; 23; STR; 0; 11; Standard; main; ; -IRB111 = 签名2; 3; IRB; -137.5; 42.5; 0; MC; 15; STR; 0; 11; Standard; main; ; -IRB112 = 日期2; 3; IRB; -125; 42.5; 0; MC; 10; STR; 0; 11; Standard; main; ; -IRB113 = 更改区域3____; 3; IRB; -195; 47.5; 0; MC; 20; STR; 0; 11; Standard; main; ; -IRB114 = 变更序号3; 3; IRB; -181.5; 47.5; 0; MC; 7; STR; 0; 11; Standard; main; ; -IRB115 = 变更页码3; 3; IRB; -173; 47.5; 0; MC; 10; STR; 0; 11; Standard; main; ; -IRB116 = 通知单号3; 3; IRB; -156.5; 47.5; 0; MC; 23; STR; 0; 11; Standard; main; ; -IRB117 = 签名3; 3; IRB; -137.5; 47.5; 0; MC; 15; STR; 0; 11; Standard; main; ; -IRB118 = 日期3; 3; IRB; -125; 47.5; 0; MC; 10; STR; 0; 11; Standard; main; ; -IRB119 = 更改区域4____; 3; IRB; -195; 52.5; 0; MC; 20; STR; 0; 11; Standard; main; ; -IRB120 = 变更序号4; 3; IRB; -181.5; 52.5; 0; MC; 7; STR; 0; 11; Standard; main; ; -IRB121 = 变更页码4; 3; IRB; -173; 52.5; 0; MC; 10; STR; 0; 11; Standard; main; ; -IRB122 = 通知单号4; 3; IRB; -156.5; 52.5; 0; MC; 23; STR; 0; 11; Standard; main; ; -IRB123 = 签名4; 3; IRB; -137.5; 52.5; 0; MC; 15; STR; 0; 11; Standard; main; ; -IRB124 = 日期4; 3; IRB; -125; 52.5; 0; MC; 10; STR; 0; 11; Standard; main; ; -IRB125=设计-文件数量; 3; IRB; -156.5; 27.5 ; 0; MC; 23; STR; 0; 11; Standard; main; ; -IRB126=审核-文件数量; 3; IRB; -156.5; 22.5 ; 0; MC; 23; STR; 0; 11; Standard; main; ; -IRB127=主任设计-文件数量; 3; IRB; -156.5; 17.5 ; 0; MC; 23; STR; 0; 11; Standard; main; ; -IRB128=工艺-文件数量; 3; IRB; -156.5; 12.5 ; 0; MC; 23; STR; 0; 11; Standard; main; ; -IRB129=标准化-文件数量; 3; IRB; -156.5; 7.5 ; 0; MC; 23; STR; 0; 11; Standard; main; ; -IRB130=批准-文件数量; 3; IRB; -156.5; 2.5 ; 0; MC; 23; STR; 0; 11; Standard; main; ;
直觉告诉我可能是缓冲区大小的问题,所以还是查一下微软官方文档 看一下实现比较好,可能需要自己去重新实现一下读取函数。
GetPrivateProfileSection function
DWORD GetPrivateProfileSection ( [in] LPCTSTR lpAppName, [out] LPTSTR lpReturnedString, [in] DWORD nSize, [in] LPCTSTR lpFileName ) ;
[in] lpAppName
The name of the section in the initialization file.
[out] lpReturnedString
A pointer to a buffer that receives the key name and value pairs associated with the named section. The buffer is filled with one or more null-terminated strings; the last string is followed by a second null character.
[in] nSize
The size of the buffer pointed to by the lpReturnedString parameter, in characters. The maximum profile section size is 32,767 characters.
[in] lpFileName
The name of the initialization file. If this parameter does not contain a full path to the file, the system searches for the file in the Windows directory.
这里比较关键的地方就是这个 nSize
,可以看到它是通过一个缓冲区大小的参数设定读取的缓冲区大小,最大可以设置为 32,767 字节。经过周工排查 IM_GetPrivateProfileSectionMap
的缓冲区为 2k 左右,所以需要我们重新编写函数读取。
那么首先我们先重新设定最大的缓冲区大小(也就是刚才的 32,767):
TCHAR buffer[32767 ] = { 0 }; auto profileSize = GetPrivateProfileSection (appName, buffer, std::size (buffer), filePath);
之后则需要用一个我之前几乎没有用过的 string_view
。C++17 中我们可以使用 std::string_view
来获取一个字符串的视图,字符串视图并不真正的创建或者拷贝字符串,而只是拥有一个字符串的查看功能。std::string_view
比 std::string
的性能要高很多,因为每个 std::string
都独自拥有一份字符串的拷贝,而 std::string_view
只是记录了自己对应的字符串的指针和偏移位置,当我们在只是查看字符串的函数中可以直接使用 std::string_view
来代替。
读取出来的 buffer
字符串则是以下面形式排列:
name1 = value1 \0 name2 = value2 \0 name3 = value3 \0 ... nameN = valueN \0\0
这里我的算法是用左右双指针寻找 =
和 \0
,以此类推直至读取到 profileSize
:
size_t left = 0 ;size_t right = sv.find (L'=' , left);if (right == std::wstring_view::npos) right = profileSize; std::wstring_view key = sv.substr (left, right - left);
左指针归零,右指针先找到 =
。此时观察可以发现左右指针已经可以把 name1
读取出来了:
name1 = value1 \0 name2 = value2 \0 name3 = value3 \0 ... ^ ^ l r
接着左指针移到右指针(也就是 =
所在位置)后面一位,右指针找到 \0
。此时观察可以发现左右指针又可以把 value1
读取出来了:
name1 = value1 \0 name2 = value2 \0 name3 = value3 \0 ... ^ ^ l r
依此类推,最终完整实现如下:
std::map<CString, CString> Utility::readPrivateProfile (CString appName, CString filePath) { TCHAR buffer[32767 ] = { 0 }; auto profileSize = GetPrivateProfileSection (appName, buffer, std::size (buffer), filePath); std::wstring_view sv{ buffer, profileSize }; size_t left = 0 ; std::map<CString, CString> ret; while (left < profileSize) { size_t right = sv.find (L'=' , left); if (right == std::wstring_view::npos) right = profileSize; std::wstring_view key = sv.substr (left, right - left); left = right + 1 ; right = sv.find (L'\0' , left); if (right == std::wstring_view::npos) right = profileSize; std::wstring_view value = sv.substr (left, right - left); left = right + 1 ; if (!key.empty ()) ret.emplace (CString (key.data (), key.length ()), CString (value.data (), value.length ())); } return ret; }
智能指针托管导致实体打开失败 在移植的过程中发现序号实体一直没办法添加进去,返回的 eWasOpenForWrite
找了好久,也尝试使用升降读写权限也失败了。后经周工点拨才发现问题所在:
-shared_ptr<XuHaoEntity> pMechXH(new XuHaoEntity(m_MechXHDInfo)); +XuHaoEntity* pMechXH = new XuHaoEntity(m_MechXHDInfo); ... AcDbBlockTableRecordPointer pModelSpace(IM_GetModalSpaceId(), AcDb::kForWrite); if (pModelSpace.openStatus() != eOk) return false; AcDbObjectId entId = AcDbObjectId::kNull; -if (pModelSpace->appendAcDbEntity(entId, pMechXH.get()) != Acad::eOk) +if (pModelSpace->appendAcDbEntity(entId, pMechXH) != Acad::eOk) return false; pMechXH->close();
由于智能指针的广泛使用,所以我对内存管理这一块并不够敏感。张帆的那本书曾经提到 ObjectARX 是如何管理内存的:
在操作图形数据库的各种对象时,必须遵守 AutoCAD 的打开和关闭对象的协议。该协议确保当对象被访问时在物理内存中,而未被访问时可以被分页存储在磁盘中。创建和打开数据库的对象之后,必须在不用的时候关闭它。
给初学 ObiectARX 的人两个建议。
不要忘记各种数据库对象的关闭 :在打开或创建数据库对象之后,必须尽可能早地关闭它。在初学者所犯的错误中,未及时关闭对象的错误至少占一半!不要使用 delete pLine
的语句 :对 C++ 比较熟悉的读者,习惯于配对使用 new
和 delete
运算符,这在 C++ 编程中是一个良好的编程习惯。但是在ObjectARX 的编程中,当编程者使用 appendAcDbEntity
函数将对象添加到图形数据库之后,就需要由图形数据库来操作该对象。这里的 shared_ptr<TH_XuHaoEntity>
就是问题关键。当我使用智能指针的时候将 XuHaoEntity
同时托管给 AutoCAD 和系统,这就导致在该段代码的作用域结束时会自动销毁该序号实体,而此时它已经被添加到数据库对象当中!内存泄漏的问题也就此诞生了,倘若此时用 Debug 工具测试会直接崩溃,因为该实体根本无法访问(毕竟已经在内存中被删除了)。
这个问题正好对应了建议二:不要使用 delete pLine
的语句。
文字样式表保持同步 天喻的旧图纸中转换时明细表部分需使用文字样式 Standard
的字体、大字体和宽度因子,但创建明细表时字体使用的是 HC_TEXTSTYLE
。虽然新建的图纸已经将两者调整为一致,但对于旧图纸而言仍不同步,需要将 Standard
的各项设置到 HC_TEXTSTYLE
:
AcDbTextStyleTablePointer pTextStyleTable (acdbHostApplicationServices()->workingDatabase(), AcDb::kForRead) ;if (pTextStyleTable.openStatus () != Acad::eOk) return ;AcDbObjectId standardTextStyleId, hcTextStyleId; if (pTextStyleTable->getAt (L"STANDARD" , standardTextStyleId) != Acad::eOk || pTextStyleTable->getAt (L"HC_TEXTSTYLE" , hcTextStyleId) != Acad::eOk) return ; pTextStyleTable->close (); AcDbTextStyleTableRecordPointer pStandardTextStyleTableRecord (standardTextStyleId, AcDb::kForRead) , pHCTextStyleTableRecord (hcTextStyleId, AcDb::kForWrite) ;if (pStandardTextStyleTableRecord.openStatus () != Acad::eOk || pHCTextStyleTableRecord.openStatus () != Acad::eOk) return ; GCHAR* fileName, *bigFontName; pStandardTextStyleTableRecord->fileName (fileName); pStandardTextStyleTableRecord->bigFontFileName (bigFontName); pHCTextStyleTableRecord->setFileName (fileName); pHCTextStyleTableRecord->setBigFontFileName (bigFontName); pHCTextStyleTableRecord->setXScale (pStandardTextStyleTableRecord->xScale ()); pHCTextStyleTableRecord->close (); pStandardTextStyleTableRecord->close ();
用的是笨办法挨个设置,暂时没找到类似整个拷贝的方式去处理文字样式表。
特殊字插入 大同方提供的 .shx
字体没办法正常显示 瞭
字,并且强烈要求增加该字的插入功能。
时间有限,讨论了一下决定先将 瞭
字做成 liao.dwg
文件,然后通过 LISP 代码交互并插入:
(defun liao() (initget 4 ) (if (= (setq height (getreal "\n请指定文字高度<2.5>: " )) nil ) (setq height 2.5 ) ) (setq echo (getvar "cmdecho" )) (setvar "cmdecho" 0 ) (command "insert" "瞭" "S" height "\\" 0 ) (setvar "cmdecho" echo) (princ ) )
代码交付中的文件批量删除操作 项目进度后期需要交付图纸转换的源码,但不会将我们所有项目的源码交付给大同方,所以需要将其余无关项目以头文件和库文件的形式交付。
先前我做交付时会一个一个去编译每个依赖项目,看缺少哪个头文件再加进去,效率很低。后面周工教了如何使用 find
命令去操作文件:
find <file_path> -type f ! -name "*.h" -delete
该命令会将所有非 .h
头文件删除,非常方便。