在本教程中,我们将使用自定义实体绘制一个五角星。
所需头文件及源文件已备好,如下所示:
教程 MyCustomEntity.h
教程 MyCustomEntity.cpp
该本教程中,使用CAD控件\MxDraw52\Src\MxDraw5.2\samples\Edit项目进行添加自定义实体进行演示。这里我们使用自定义实体绘制一个五角星,所需虚函数已被重写,在头文件中有对各个虚函数的参数说明,在此将不再赘述,接下来将着重介绍如何加载自定义实体以及需要注意的地方。
本教程旨在介绍控件提供的API及推荐操作方式演示,读者应根据自己需要参考实例使用程序设计语言撰写解决方案。
在 http://www.mxdraw.com/下载CAD控件安装包,该包是自解压包,默认路径是当前文件夹,不会更改你任何的电脑设置。
运行CopyReleaseFile.bat、CopyReleaseFileX64.bat文件后会出现ReleaseFile、ReleaseFileX64文件夹,里面包含了所需要的动态库和资源文件。
打开VS2010选择新建一个MFC应用程序,在应用程序类型中选择基于对话框,其他的默认。
配置开发环境输出目录到MxDraw52\Bin\vc100d。
包含目录修改成MxDraw52\Src\MxDraw5.2\MxInc,库目录修改成MxDraw52\Src\MxDraw5.2\libvc100。
首先在资源界面上加入一个Buttun(ID命名为IDC_DRAWFPS_BUTTON)按钮和一个Group Box(ID命名为IDC_RANGE_STATIC)按钮。
给Group Box按钮右键添加一个变量:
接下来为该项目创建一个C++类,这里创建的类名是CMcdbFivePointStar类:
在stdafx.h文件中添加代码:#include "mxdraw.h" 并在FivePointStar.cpp文件中进行CAD控件的注册和释放:
CWinApp::InitInstance(); /////////////////////////// MxDraw::InitMxDraw();//注册控件
MxDraw::UnInitMxDraw();//释放控件 /////////////////////////// return FALSE;
在FivePointStarDlg.cpp的OnInitDialog()函数中添加CAD控件额外的初始化代码如下:
CMcdbFivePointStar::rxInit();//注册自定义实体类信息到系统中 CRect rcPos; GetDlgItem(IDC_RANGE_STATIC)->GetWindowRect(rcPos); m_hDrawOcx = MxDraw::CreateMxDraw(this, rcPos, MxDraw::kShowCmdLineWindow); ASSERT(m_hDrawOcx != NULL);
写自定义实体类CMcdbFivePointStar继承自McDbEntity类
#define FPS_VERSION 1 //版本号 class CMcdbFivePointStar : public McDbEntity { public: ACRX_DECLARE_MEMBERS(CMcdbFivePointStar); CMcdbFivePointStar(int iLenth = 50, McGePoint3d vPos = McGePoint3d (0, 0, 0)); ~CMcdbFivePointStar(void); //重载该虚函数,绘制自定义实体的显示效果a Adesk::Boolean worldDraw( AcGiWorldDraw * wd//显示绘制的上下文对象 ); //重载该虚函数,返回自定义的编辑夹点 virtual Acad::ErrorStatus getGripPoints( AcGePoint3dArray& gripPoints,//返回夹点 AcGeIntArray& osnapModes,// 暂没有使用 AcGeIntArray& geomIds//暂没有使用 ) const; //重载该虚函数,处理夹点编辑结果。 virtual Acad::ErrorStatus moveGripPointsAt( const AcGeIntArray& indices,//indices [0]参数是传入被编辑的夹点索引, 其 它数组元素暂没有使用。 const AcGeVector3d& offset//夹点编辑的偏移量 ); //重载该虚函数,返回自定义实体的外包矩形框 virtual Acad::ErrorStatus getGeomExtents( AcDbExtents& extents//返回自定义实体外包矩形框。 ) const; //重载该虚函数,返回自定义实体的捕捉点 virtual Acad::ErrorStatus getOsnapPoints( AcDb::OsnapMode osnapMode,//捕捉点类型,通过该变量可以确 定需要返回什 么类型的捕捉点 int gsSelectionMark,//暂没有使用 const AcGePoint3d& pickPoint,//当前输入点 const AcGePoint3d& lastPoint,//上一次的输入点 const AcGeMatrix3d& viewXform,// 暂没有使用 AcGePoint3dArray& snapPoints,//返回捕捉点 AcDbIntArray& geomIds//暂没有使用 ) const; //重载该虚函数,返回自定义实体打碎后的实体,在控件中, //自定义实体保存在到dwg图中时,使用是块引用来保存, //控件使用该函数得到自定义实体在块引用中的实体数据。 virtual Acad::ErrorStatus explode( AcDbVoidPtrArray& entitySet//返回打碎后的基本实体。实体指针 内存控件释放。 ) const; //重载该虚函数,响应控件系统,读取自定义实体数据, //在从文件读取实体,复制实体等地方都会调用该函数。 virtual Acad::ErrorStatus dwgInFields( AcDbDwgFiler* pFiler//数据归档对象,在这个函数,使用该对象读 取数据。 ); //重载该虚函数,响应控件系统,写入自定义实体数据, //在把实体写入文件时,复制实体等地方都会调用该函数。 virtual Acad::ErrorStatus dwgOutFields( AcDbDwgFiler* pFiler//数据归档对象,在这个函数,使用该对象写 入数据。 ) const; void SetCenter(McGePoint3d vCenter); const McGePoint3d & GetCenter(); void SetLenth(int dLength); const int & GetLenth(); private: std::vector<McGePoint3d> GetFPS() const; int m_iLength;//五角星半径 McGePoint3d m_vPos; //五角星中心 /* int m_Rdius;*/ };
双击“画五角星产生事件”,添加代码如下:
CMcdbFivePointStar * pFPS = new CMcdbFivePointStar(100, McGePoint3d(100, 100, 0)); MrxDbgUtils::addToCurrentSpaceAndClose(pFPS);
1. 在自定义实体类函数中添加了读函数(assertReadEnabled)和写函数(assertWriteEnabled),函数说明:
断言对象当前状态一定被读方式打开,该函数多用于自定义实体的属性操作函数中。
void assertReadEnabled() const;
断言对象当前状态一定被写方式打开,该函数多用于自定义实体的属性操作函数中。
void assertWriteEnabled(Mdesk::Boolean autoUndo = true, Mdesk::Boolean recordModified = true, Mdesk::Boolean setSaveModifyed = true );
上述的函数主要为“退回”操作及“保存”的操作;如不加则会在上述操作中出现异常。
2. 在打碎虚函数(explode)中,我们进行了具体的添加实体的操作,在此处我们可以根据需要设置一些属性。
3. 在绘制函数中,我们调用打碎虚函数(explode),并对 绘图时使用的环境参数AcGiWorldDraw进行了如下设置: wd- >subEntityTraits().setLineWeight(pEnt->lineWeight())... 即为我们在explode中对实体设置的属性,在CAD控件中显示出来。
4. 在自定义实体类的头文件中,我们在类名下定义了如下声明:
//使用MCRX_DECLARE_MEMBERS宏定义类的类型信息函数,宏的第一个参数是类的类名 ACRX_DECLARE_MEMBERS(MyCustomEntity); 在源文件中进一步说明: ACRX_DXF_DEFINE_MEMBERS( MyCustomEntity, //自定义实体的类名 McDbEntity,//自定义实体的基类 AcDb::kDHL_CURRENT,//当前文件版本 AcDb::kMReleaseCurrent,//当前控件版本 AcDbProxyEntity::kAllAllowedBits,//代理实体处理标志 MyCustomEntity,//Dfx0组码对应值 MxDrawObj Test Custom Entity//类说明 );
此信息在实体信息中能够看到。
5. 在dwgInFields和dwgOutFields,我们进行了写档与归档的操作,使用了我们定义的宏:
#define MYCUSTOMENTITY_VERSION 1 //版本号
在自定义实体增加新的内容,如:新增一条线,我们则需要判断版本,根据获取到的版本号对是否使用线进行判断。
在读与写的操作中,我们使用了参数AcDbDwgFiler 进行具体的读写,此类可读写绝大多数用到的数据,但是读写必须保持同步,及此实例中在dwgOutFields先pFiler->writeInt(MYCUSTOMENTITY_VERSION),dwgOutFields需要先pFiler->readInt(&lVar),才能获取正确的数据。
6. 使用控件的移动函数move,或者点击自定义实体的夹点进行拖动,需要实现dwgInFields、dwgOutFields和moveGripPointsAt。
控件其他例程说明:
在控件安装目录下的samples\CustomEntity\ CustomEntity.sln例程,演示了自定义实体现。在例程实现连接块CLinkBlock自定义实体,CLinkLine自定义实体。
CLinkBlock类显示通过块引用显示,绘图捕捉点通过块记录中的块属性定义文本来确定,当该实体被编辑后,会自动移动与该实体连接的连接线,实现连动效果。
CLinkLine 类实现一个线段实体功能,并带有长度标注功能。
ACRX_DECLARE_MEMBERS 宏
作用:使用MCRX_DECLARE_MEMBERS宏定义类的类型信息函数,宏的第一个参数是类的类名。
参数:
名称 | 说明 |
---|---|
第一个参数 | 宏的第一个参数是类的类名 |
参考例程:
ACRX_DECLARE_MEMBERS(MyCustomEntity);
ACRX_DXF_DEFINE_MEMBERS宏
作用:定义类的类型信息。
定义:
#define ACRX_DXF_DEFINE_MEMBERS MCRX_DXF_DEFINE_MEMBERS_EX
#define MCRX_DXF_DEFINE_MEMBERS_EX(CLASS_NAME,PARENT_CLASS,DWG_VERSION, \
MAINTENANCE_VERSION,PROXY_FLAGS,DXF_NAME,APP) \
MCRX_DEFINE_MEMBERS(CLASS_NAME); \
参数:
名称 | 说明 |
---|---|
CLASS_NAME | 自定义实体的类名 |
PARENT_CLASS | 自定义实体的基类 |
DWG_VERSION | 当前文件版本 |
MAINTENANCE_VERSION | 当前控件版本 |
PROXY_FLAGS | 代理实体处理标志 |
DXF_NAME | Dfx0组码对应值 |
APP | 类说明 |
参考例程:
ACRX_DXF_DEFINE_MEMBERS( MyCustomEntity, //自定义实体的类名 McDbEntity,//自定义实体的基类 AcDb::kDHL_CURRENT,//当前文件版本 AcDb::kMReleaseCurrent,//当前控件版本 AcDbProxyEntity::kAllAllowedBits,//代理实体处理标志 MyCustomEntity,//Dfx0组码对应值 MxDrawObj Test Custom Entity//类说明 );
作用:绘制自定义实体的显示效果。
接口:Adesk::Boolean worldDraw(AcGiWorldDraw * wd);
参数:
名称 | 说明 |
---|---|
wd | 显示绘制的上下文对象 |
参考例程:
Adesk::Boolean MyCustomEntity::worldDraw(AcGiWorldDraw * wd) { assertReadEnabled(); AcDbVoidPtrArray entitySet; explode(entitySet); for (int i = 0; i < entitySet.length(); i++) { McDbEntity* pEnt = (McDbEntity*)entitySet[i]; wd->subEntityTraits().setLineWeight(pEnt->lineWeight()); wd->subEntityTraits().setColor(pEnt->colorIndex()); wd->subEntityTraits().setAlwaysShowLineWidth(TRUE); pEnt->worldDraw(wd); delete pEnt; } return Mdesk::kTrue; }
getGripPoints function
作用:返回自定义的编辑夹点。
接口:virtual Acad::ErrorStatus getGripPoints(
AcGePoint3dArray & gripPoints, AcGeIntArray & osnapModes, AcGeIntArray & geomIds
) const;
参数:
名称 | 说明 |
---|---|
gripPoints | 返回夹点 |
osnapModes | 暂没有使用 |
geomIds | 暂没有使用 |
参考例程:
Acad::ErrorStatus MyCustomEntity::getGripPoints(AcGePoint3dArray & gripPoints, AcGeIntArray & osnapModes, AcGeIntArray & geomIds) const { assertReadEnabled(); gripPoints.append(m_vCenterPt); return Acad::eOk; }
moveGripPointsAt function
作用:处理夹点编辑结果。
接口:virtual Acad::ErrorStatus moveGripPointsAt(
const AcGeIntArray & indices, const AcGeVector3d & offset
);
参数:
名称 | 说明 |
---|---|
indices | indices [0]参数是传入被编辑的夹点索引, 其它数组元素暂没有使用 |
Offset | 夹点编辑的偏移量 |
参考例程:
Acad::ErrorStatus MyCustomEntity::moveGripPointsAt(const AcGeIntArray & indices, const AcGeVector3d & offset) { assertWriteEnabled(); int iIndex = indices[0]; switch (iIndex) { case 0: m_vCenterPt += offset; break; } return Mcad::eOk; }
getGeomExtents function
作用:返回自定义实体的外包矩形框。
接口:virtual Acad::ErrorStatus getGeomExtents(
AcDbExtents & extents
) const;
参数:
名称 | 说明 |
---|---|
extents | 返回自定义实体外包矩形框 |
参考例程:
Acad::ErrorStatus MyCustomEntity::getGeomExtents(AcDbExtents & extents) const { assertReadEnabled(); auto vPos = GetFPS(); McGePoint3d vLeftBottom; McGePoint3d vRightTob; vLeftBottom = vPos[0]; vRightTob = vPos[0]; for (size_t i(1); i < vPos.size(); i++) { if (vLeftBottom.x > vPos[i].x) vLeftBottom.x = vPos[i].x; if (vLeftBottom.y > vPos[i].y) vLeftBottom.y = vPos[i].y; if (vRightTob.x < vPos[i].x) vRightTob.x = vPos[i].x; if (vRightTob.y < vPos[i].y) vRightTob.y = vPos[i].y; } extents.set(vLeftBottom, vRightTob); return Acad::eOk; }
getOsnapPoints function
作用:返回自定义实体的捕捉点。
接口:virtual Acad::ErrorStatus getOsnapPoints(
AcDb::OsnapMode osnapMode,
int gsSelectionMark,
const AcGePoint3d & pickPoint,
const AcGePoint3d & lastPoint,
const AcGeMatrix3d & viewXform,
AcGePoint3dArray & snapPoints,
AcDbIntArray & geomIds
) const;
参数:
名称 | 说明 |
---|---|
osnapMode | 捕捉点类型,通过该变量可以确定需要返回什么类型的捕捉点 |
GsSelectionMark | 暂没有使用 |
pickPoint | 当前输入点 |
LastPoint | 上一次的输入点 |
ViewXform | 暂没有使用 |
SnapPoints | 返回捕捉点 |
GeomIds | 暂没有使用 |
参考例程:
Acad::ErrorStatus MyCustomEntity::getOsnapPoints(AcDb::OsnapMode osnapMode, int gsSelectionMark, const AcGePoint3d & pickPoint, const AcGePoint3d & lastPoint, const AcGeMatrix3d & viewXform, AcGePoint3dArray & snapPoints, AcDbIntArray & geomIds) const { assertReadEnabled(); if (osnapMode == McDb::kOsModeEnd) { // 返回端点。 auto vPos = GetFPS(); for each (auto it in vPos) snapPoints.append(it); } else if (osnapMode == McDb::kOsModeMid) { // 返回的是中点。 snapPoints.append(m_vCenterPt); } return Mcad::eOk; }
Explode function
作用:重载该虚函数,返回自定义实体打碎后的实体,在控件中,自定义实体保存在到dwg图中时,使用是块引用来保存,控件使用该函数得到自定义实体在块引用中的实体数据。
接口:virtual Acad::ErrorStatus explode(
AcDbVoidPtrArray & entitySet
) const;
参数:
名称 | 说明 |
---|---|
entitySet | 返回打碎后的基本实体。实体指针内存控件释放 |
参考例程:
Acad::ErrorStatus MyCustomEntity::explode(AcDbVoidPtrArray & entitySet) const { assertReadEnabled(); auto vPos = GetFPS(); for (size_t i(0); i < vPos.size(); i++) { McDbLine* pLine = new McDbLine(vPos[i], vPos[(i + 2) % 5]); pLine->setLineWeight(McDb::kLnWt025); //设置一些属性 McCmColor mColor; mColor.setColor(RGB(0, 255, 0)); pLine->setColor(mColor); pLine->setAlwaysShowLineWeight(TRUE); entitySet.append(pLine); } return Acad::eOk; }
dwgInFields function
作用:重载该虚函数,响应控件系统,读取自定义实体数据,在从文件读取实体,复制实体等地方都会调用该函数。
接口:virtual Acad::ErrorStatus dwgInFields(
AcDbDwgFiler * pFiler
);
参数:
名称 | 说明 |
---|---|
pFiler | 数据归档对象,在这个函数,使用该对象写入数据 |
参考例程:
Acad::ErrorStatus MyCustomEntity::dwgInFields(AcDbDwgFiler * pFiler) { assertWriteEnabled(); int lVar = 1; pFiler->readInt(&lVar); pFiler->readDouble(&m_iLength); pFiler->readPoint3d(&m_vCenterPt); return Mcad::eOk; }
dwgOutFields function
作用:重载该虚函数,响应控件系统,读取自定义实体数据,在从文件读取实体,复制实体等地方都会调用该函数。
接口:virtual Acad::ErrorStatus dwgOutFields(
AcDbDwgFiler * pFiler
) const;
参数:
名称 | 说明 |
---|---|
pFiler | 数据归档对象,在这个函数,使用该对象读取数据 |
参考例程:
Acad::ErrorStatus MyCustomEntity::dwgOutFields(AcDbDwgFiler * pFiler) const { assertReadEnabled(); pFiler->writeInt(MYCUSTOMENTITY_VERSION); pFiler->writeDouble(m_iLength); pFiler->writePoint3d(m_vCenterPt); return Mcad::eOk; }