LOGO
帮助文档
旧版文档
在edit中的演示修改后的演示通用的函数控件中的通用链表对于链表的操作提供的接口
在edit中的演示

下载地址:


http://www.mxcad.net:2080/cpp/Tech-XData.zip


在...MxDraw52\Src\MxDraw5.2\samples\Edit的实例中,我们有以下的扩展数据演示功能:



blob.png

修改后的演示

此实例将进一步演示如何获取实体上的扩展数据并修改,演示程序运行如下图:



blob.png

通用的函数

打开CAD图纸:


在“打开图纸”按钮的单击事件中,我们添加如下函数:


void CTechXDataDlg::OnBnClickedOpenMap()
{
	acDocManager->sendStringToExecute(Mx::mcdbCurDwg()->GetDocument(), L"OpenDwg");
}


事件中的代码大意为调用我们之前准备的命令,接口如下:


	// Summary:
	// 		向控件发送一个命令,并执行该命令
	// Parameters:
	// 		pAcTargetDocument	-	执行命令的对象
	//		pszExecute			-	执行命令的对象
	//		bActivate			-	暂没有使用
	//		bWrapUpInactiveDoc	-	暂没有使用
	//		bEchoString			-	暂没有使用
	//		pParam				-   执行命令时,可以带参数执行,用户不需要负责它的内存释放,将由sendStringToExecute函数自动释放
	// Returns:
	// 		如果成功返回Mcad::eOk,如果传递的数据非法则返回Mcad::eInvalidInput
	virtual Mcad::ErrorStatus sendStringToExecute(McApDocument* pAcTargetDocument,
		LPCTSTR pszExecute,
		bool bActivate = true,
		bool bWrapUpInactiveDoc = false,
		bool bEchoString = true,
		struct resbuf* pParam = NULL,
		bool bFunCall = false
		) = 0;


而调用的命令,我们需要做出如下的准备,如“选择实体”按钮单击事件中的代码段:


void CTechXDataDlg::OnBnClickedChooseButton()
{
	Mx::mcDocManager()->sendStringToExecute(MxDraw::GetDatabase(m_hDrawOcx)->GetDocument()
		, _T("CET"));

	InitToPanle();
}


我们调用的“CET”命令,该命令为我们的自定义命令,我们做出了如下的声明及实现:



blob.png



命令代码声明如下:


static void ChooseEnt();


命令代码实现如下:


void CTechXDataDlg::ChooseEnt()
{
	MrxDbgUiPrEntity mChooseEnt(L"选择一个实体");
	if (MrxDbgUiPrBase::kOk == mChooseEnt.go())
	{
		m_mId = mChooseEnt.objectId();
	}
	else
	{
		m_mId.setNull();
	}
}


在完成命令的具体功能之后,我们将其注册到系统,以供调用,注册命命令声明如下:


static void RegisterCommand();


实现如下:


void CTechXDataDlg::RegisterCommand()
{
	acedRegCmds->addCommand(_T("SysCmd"), _T("CET"), _T("CET"),
		MCRX_CMD_MODAL, ChooseEnt);
}


我们在面板的初始化函数中调用它:



blob.png



至此我们即完成了自定义命令的所有步骤,需要说明的是,与用户交互的操作,比如我们的自定义命令“ChooseEnt”即是提示用户选择一个实体,必须放在自定义命令中执行。

控件中的通用链表

在 ...\MxDraw52\Src\MxDraw5.2\ArxInc\Mdsdef.h中,我们看到了链表的如下定义:


#ifndef _mdsdef_h
#define _mdsdef_h 1
 
 
#define TRUE    1
#define FALSE   0
#define EOS     '\0'
 
#pragma pack(push, 8)
 
typedef double   mds_real;
typedef mds_real mds_point[3];
typedef long     mds_name[2];
typedef mds_real mds_matrix[4][4];
 
 
typedef mds_real *mds_pointp;
typedef long     *mds_namep;
 
 
 
#ifdef X
#undef X
#endif
#ifdef Y
#undef Y
#endif
#ifdef Z
#undef Z
#endif
#ifdef T
#undef T
#endif
 
#ifndef _XYZT_DEFINED
#define _XYZT_DEFINED
enum { X = 0, Y = 1, Z = 2 }; 
enum { T = 3 };              
#endif 
 
 
#define PAUSE "\\"
 
 
enum {
    RSG_NONULL      = 0x01,  
    RSG_NOZERO      = 0x02,  
    RSG_NONEG       = 0x04,  
    RSG_NOLIM       = 0x08,  
    RSG_GETZ        = 0x10,  
    RSG_DASH        = 0x20,  
                             
    RSG_2D          = 0x40,  
                             
    RSG_OTHER       = 0x80,  
    RSG_DDISTFIRST  = 0x100,
 
RSG_NOXORDRAG   = 0x200,
 
 
RSG_DYNXYCOORDINPUT = 0x400,
REG_DYNANGELINPUT   = 0x800,
REG_DISTANCEINPUT = 0x1000,
RET_AUTOINPUT       = 0x2000
};
 
 
enum {
    INP_NNULL   = RSG_NONULL,
    INP_NZERO   = RSG_NOZERO,
    INP_NNEG    = RSG_NONEG,
    INP_NLIM    = RSG_NOLIM,
    INP_DASH    = RSG_DASH,
    INP_NZCOORD = RSG_2D
};
 
 
struct mds_binary {    
    short clen;        
    char *buf;        
};
 
 
union mds_u_val {
   mds_real rreal;
   mds_real rpoint[3];
   short rint;
   LPTSTR rstring;
   long rlname[2];
   long rlong;   
   struct mds_binary rbinary;
   unsigned char ihandle[8];
/*#ifdef _WIN64*/
__int64 objId;
// #else
//    long objId;
// #endif
   void*  pObj;
}; 
 
 
struct resbuf {                                                  
        struct resbuf *rbnext; 
        short restype;
        union mds_u_val resval;
resbuf()
{
restype = 5003 ; // RTSHORT
rbnext  = 0;
resval.rint = 0;
}
};
 
typedef struct resbuf *pResbuf;
typedef const struct resbuf *kpResbuf;
 
#pragma pack(pop)
 
#endif
对于链表的操作

可以看到的是,链表支持如,整形、句柄、指针、字符串的存储,而在存储中,对于每一个节点的类型设置“restype”必须与存储的数据类型(mds_u_val联合下的数据类型)对应,如此实例中的设置扩展数据代码段:


	 resbuf* pExDataRb = nullptr;
	 std::vector <resbuf*> vBuf;
	 resbuf* pLastNode = nullptr;
	 auto CreateNewXData = [&]() {

		 pLastNode = pExDataRb = acutBuildList(AcDb::kDxfRegAppName, sTemp, 0);

		 m_mRealNum.GetWindowTextW(sTemp);
		 if (sTemp.GetLength())
		 {
			 auto pBuf = acutBuildList(AcDb::kDxfXdReal, _wtof(sTemp), 0);
			 pLastNode->rbnext = pBuf;
			 pLastNode = pLastNode->rbnext;
			 vBuf.push_back(pBuf);
		 }
		 m_mShortNum.GetWindowTextW(sTemp);
		 if (sTemp.GetLength())
		 {
			 auto pBuf = acutBuildList(AcDb::kDxfXdInteger16, _wtoi(sTemp), 0);
			 pLastNode->rbnext = pBuf;
			 pLastNode = pLastNode->rbnext;
			 vBuf.push_back(pBuf);
		 }
		 m_mLongNum.GetWindowTextW(sTemp);
		 if (sTemp.GetLength())
		 {
			 auto pBuf = acutBuildList(AcDb::kDxfXdInteger32, _wtoi(sTemp), 0);
			 pLastNode->rbnext = pBuf;
			 pLastNode = pLastNode->rbnext;
			 vBuf.push_back(pBuf);
		 }
		 m_mString.GetWindowTextW(sTemp);
		 if (sTemp.GetLength())
		 {
			 auto pBuf = acutBuildList(AcDb::kDxfXdAsciiString, sTemp, 0);
			 pLastNode->rbnext = pBuf;
			 pLastNode = pLastNode->rbnext;
			 vBuf.push_back(pBuf);
		 }

		 CString sTempY, sTempZ;
		 {
			 m_m3dVectorX.GetWindowTextW(sTemp);
			 if (!sTemp.GetLength())
				 return;
			 m_m3dVectorY.GetWindowTextW(sTempY);
			 if (!sTempY.GetLength())
				 return;
			 m_m3dVectorZ.GetWindowTextW(sTempZ);
			 if (!sTempZ.GetLength())
				 return;
			 mds_real vVec[] = { _wtof(sTemp),_wtof(sTempY),_wtof(sTempZ) };
			 auto pBuf = acutBuildList(AcDb::kDxfXdXCoord, vVec, 0);
			 pLastNode->rbnext = pBuf;
			 pLastNode = pLastNode->rbnext;
			 vBuf.push_back(pBuf);
		 }
	 };


上述代码段中,我们再次使用到了acutBuildList宏,在构造选择集的介绍文章中我们已对该宏进行了介绍,再次不再赘述。而在构造扩展数据时,大致的结构如下:


blob.png

提供的接口

可以看到的是,数据都是以程序名(即  kDxfRegAppName     = 1001)开始,而在后挂在相关的信息。


获取、修改、删除扩展数据


获取扩展数据的接口如下:


virtual struct resbuf*    xData   (
    LPCTSTR pszRegappName = NULL - 扩展数据应用名,如果为空返回所有扩展数据
) const;


设置扩展数据的接口如下:


virtual Mcad::ErrorStatus setXData(
    const struct resbuf* xdata - 扩展数据链表指针,在不使用时调用Mx::mcutRelRb释放链表
);


需要注意的是:如果我们创建了已有的应用程序名并设置到扩展数据,将会覆盖之前该应用名下的数据,在本实例中,我们通过提示用户的方式,选择覆盖、加入尾部(合并)的方式来添加,代码如下:


		 McDbObjectPointer<AcDbEntity> spEnt(m_mId, AcDb::kForWrite);
		 if (spEnt.openStatus() == Acad::eOk)
		 {
			 auto pData = spEnt->xData(sTemp);

			 if (pData)
			 {
				 auto iResult = MxDraw::MxMessageBox(L"已有该程序名的扩展数据,YES[覆盖] NO[合并] CANCLE[取消]", MB_YESNOCANCEL);
				 if (IDYES == iResult) {
					 CreateNewXData();
				 }
				 else if (IDNO == iResult) {
					 CreateNewXData();
					 pLastNode->rbnext = pData->rbnext;
					 pData->rbnext = pExDataRb;
				 }
				 else {
					 return;
				 }
			 }
			 else
			 {
				 CreateNewXData();
			 }
			 spEnt->setXData(pExDataRb);
			 acutRelRb(pData);
		 }


仅需将已有扩展数据的最后一个数据的rbnext指针指向我们新添加的节点即可


删除扩展数据的接口如下:


virtual Mcad::ErrorStatus delXData(
    LPCTSTR pzsAppName = NULL - 删除的扩展数据名称,如果为空,删除所有扩展数据。
);