ObjectARX2016 OPM面板全攻略

显示多项扩展属性

    利用OPM技术实现动态属性的方法在网上并不是很多,对于初步接触这个内容的人来说,还是存在很多困惑,首先创建的项目在初次编译时就会出现很多问题,诸如:

  1. 1>TRACKER : 错误 TRK0005: 未能找到:“midl.exe”。系统找不到指定的文件;
  2. midl : command line error MIDL1012: argument illegal for switch / header
  3. 2>midl : command line error MIDL1024: Errors on command line—Aborting
  4. featuresOPM.rc(102): error RC2135: file not found: asdkfeaturesOPM.tlb

5>C:\ Program Files (x86)\Microsoft Visual Studio 11.0\VC\atlmfc\include\atlwinverapi.h(29): fatal error C1189: #error :  This file requires _WIN32_WINNT to be #defined at least to 0x0403. Value 0x0501 or higher is recommended.还有:如何把多个属性放置在同一个自定义的标签下面?如何在属性栏内显示一个值?而不是显示CAD内置的预定义的值。如何设置列表框中的多个选项?本文不再介绍ObjectARX2016环境安装及配置方法,这部分内容读者可参考win7下Visual Studio 2012 update4、AutoCAD 2016和二次开发插件ObjectARX2016环境安装及配置_Selenitic_G的博客-CSDN博客《win7下Visual Studio 2012 update4、AutoCAD 2016和二次开发插件ObjectARX2016环境安装及配置》。也不介绍动态属性(OPM)的实现方法与运行机制,这部分内容读者可参考Microsoft Word - Autocad 与动态属性.doc - 豆丁网《Microsoft Word - Autocad 与动态属性.doc 》。本文通过一个完整的实例,详细介绍在自定义的标签下显示CAD实体上的多项扩展属性。

1.项目需求

    在CAD图中有一个“地块”图层,这个图层中的所有实体均代表地籍宗地,实体类型包括AcDbPolyline、AcDbHatch两种,宗地上赋有扩展属性如下表:

DXF

值(例)

数据类型

控件类型

说明

1001

TDQSXX

注册程序名

1000

00159

String

文本框

宗地简码

1000

刘胜利

String

文本框

权利人

1000

320102196906182735

String

文本框

证件编号

1000

31/村民小组

String

列表框

权属性质

1000

063/教育用地

String

列表框

土地用途

1000

刘小兰

String

文本框

共有人

1000

186.27

String

文本框

宗地面积

1000

宗地备注

String

文本框

宗地备注

    在CAD特性面板中创建一个分类标签“土地权属信息”,在这个标签下添加宗地简码、权利人、证件编号、权属性质、土地用途、共有人、宗地面积、宗地备注等八项属性。其中123678六项为文本框,45二项为列表框。

    第4项权属性质的列表框有9个选项,分别是:10/国有土地所有权、30/集体土地所有权、31/村民小组、32/村集体经济组织、33/乡集体经济组织、34/其它农民集体经济组织、40/集体土地使用权、其他。

    第5项土地用途的列表框有15个选项,分别是: 071/城镇住宅用地、072/农村宅基地、081/机关团体用地、082/新闻出版用地、083/科教用地、061/工业用地、062/采矿用地、063/仓储用地、094/宗教用地、095/殡葬用地、101/铁路用地、102/公路用地、103/街巷用地、104/农村道路、其他。

2.创建项目及项目属性设轩

2.1 Visual Studio 2012设置

Visual Studio 2012设置见下图:

 

2.2创建项目myOPM

创建项目的流程如下:

 

 

3.3项目属性设置

 

右键点击解决方案中的myOPM项目,在弹出框中点击属性,如下图,打开属性设置对话框。

 

1常规:

 

2调试

 

3 C++目录>包含目录

选中包含目录,点击右边的小箭头,点击编辑

 

在弹出对话框中击文件夹按钮

    点击右边的···按钮

 

在弹出的文件对话框中选择ObjectARX按装目录下的inc文件夹,余类推。

4 C++目录>引用目录

 5 C++目录>库目录

 

6 C/C++>调试

 

7 MIDL>输出

 

9 "StdAfx.h"文件内容修改

 

现在,用菜单生成>生成解决方案便成功了。

1>------ 已启动生成: 项目: myOPM, 配置: Debug x64 ------

1>  general.cpp

1>     正在创建库 d:\Autodesk\ARX程序\myOPM\x64\/myOPM.lib 和对象 d:\Autodesk\ARX程序\myOPM\x64\/myOPM.exp

1>rxapi.lib(libinit.obj) : warning LNK4099: 未找到 PDB“rxapi_cl.pdb”(使用“rxapi.lib(libinit.obj)”或在“d:\Autodesk\ARX程序\myOPM\x64\rxapi_cl.pdb”中寻找);正在链接对象,如同没有调试信息一样

  1. myOPM.vcxproj -> d:\Autodesk\ARX程序\myOPM\x64\myOPM.ARX

========== 生成: 成功 1 个,失败 0 个,最新 0 个,跳过 0 个 ==========

3.添加属性项

3.1添加文本框属性项

右键点击项目>添加>类。(如下图)

 

在上图所示的窗口中,只需要填写第一个编辑框,指定一个名称,其余编辑框将自动完成,指定名称后,按下一步。

 

勾选Support for ICategorizeProperty(支持分类属性)

 DBX Classname,填写 AcDbEntiy,然后 Finish。

3.2关于OPM/Property Palette Interfaces Support选项

Support for ICategorizeProperty    支持分类属性

No addtional support     没有额外的支持(常规分类下的文本框)

Support for IDnamicEnumProperty    支持列表框属性

Support for IDynamicDialogProperty 支持对话框属性

 

  1. 要在常规分类里创建一个文本框属性项,如CAD特性面板中的<透明度>

选择No addtional support

  1. 要在常规分类里创建一个列表框属性项,如CAD特性面板中的<图层>

选择Support for IDnamicEnumProperty

  1. 要在常规分类里创建一个对话框属性项,如CAD特性面板中的<颜色>

选择Support for IDynamicDialogProperty

  1.  要在自定义分类里创建一个文本框属性项,如下图中的<宗地简码>

选择Support for ICategorizeProperty

No addtional support

  1. 要在自定义分类里创建一个列表框属性项,如下图中的<权属性质>

选择Support for ICategorizeProperty

Support for IDnamicEnumProperty

  1. 要在自定义分类里创建一个对话框属性项(本例未包含)

选择Support for ICategorizeProperty

Support for IDynamicDialogProperty

3.3关于DBX Classname的填写

如果要限定显示动态属性的实体类型,只里填写相应的实体类型名,如:AcDbLine、AcDbText、AcDbPolyline等,在本例中,表示地籍宗地的实体包括AcDbPolyline、AcDbHatch两种,所以填写实体的基类名称AcDbEntity。

3.4修改代码

自定义分类里创建的文本框属性项,.cpp文件中会自动生成14个函数,其中要修改6个函数:

//-----------------------------------------------------------------------------

//----- ZDXX1.cpp : Implementation of CZDXX1

//-----------------------------------------------------------------------------

#include "StdAfx.h"

#include "ZDXX1.h"

//修改项1.属性项的名称

STDMETHODIMP CZDXX1::GetDisplayName (BSTR *pBstrName) {

    if ( pBstrName == NULL )

        return (E_POINTER) ;

    *pBstrName =::SysAllocString (L"宗地简码") ;

    return (S_OK) ;

}

//修改项2.属性项的描述

STDMETHODIMP CZDXX1::GetDescription (BSTR *pBstrName) {

    if ( pBstrName == NULL )

        return (E_POINTER) ;

    *pBstrName =::SysAllocString (L"宗地的后5位编码") ;

    return (S_OK) ;

}

//修改项3.属性值的数据类型

STDMETHODIMP CZDXX1::GetCurrentValueType (VARTYPE *pVarType) {

    if ( pVarType == NULL )

        return (E_POINTER) ;

    //*pVarType =VT_I2 ;   //2字节整形 short

    //*pVarType =VT_I4 ;   //4字节整形 int

    //*pVarType =VT_R4 ;   //4字节浮点数 float

    //*pVarType =VT_R8 ;   //8字节浮点数 double

    *pVarType =VT_BSTR ;   //字符型 string   

    //*pVarType =VT_BOOL ; //逻辑值 bool

    //*pVarType =VT_USERDEFINED ;   //枚举类型

    return (S_OK) ;

    //个预定义属性取值:

    //*pVarType =VT_PREDEFINED;   return (E_NOTIMPL);

}

//修改项4.获取属性项的值

STDMETHODIMP CZDXX1::GetCurrentValueData (IUnknown *pUnk, VARIANT *pVarData) {

    if ( pUnk == NULL )

        return (E_INVALIDARG) ;

    if ( pVarData == NULL )

        return (E_POINTER) ;

    ::VariantInit (pVarData) ;

    V_VT(pVarData) =VT_BSTR ;    //定义控件的类型 string

    LONG_PTR oldID;

    ((IAcadObject *)pUnk)->get_ObjectID(&oldID);   //利用 pUnk 获取当前选中实体对象的 ID

    AcDbObjectId objID;

    objID.setFromOldId(oldID);

    //利用 ID 以读方式打开实体

    AcDbEntityPointer pEntPtr( objID, AcDb::kForRead );

    Acad::ErrorStatus es = pEntPtr.openStatus();

    if ( es != Acad::eOk)   {   return E_FAIL;  }    //打开实体失败,返回 非

    //从实体中获取XData

    vector<CString> OutDatas =GetDatas(appName,pEntPtr);

    pEntPtr->close();                //关闭实体

    if(实体图层名 ==TEXT("地块") && OutDatas.size()==9)  //如果实体的图层="地块"、扩展属性的项数=9

    {   //控件的值=扩展属性第二项(第一项的索引为0)

        pVarData->bstrVal = ::SysAllocString( OutDatas[1] );

        return (S_OK) ;

    }

    else {return E_FAIL;}

}

//修改项5.修改属性项的内容

STDMETHODIMP CZDXX1::SetCurrentValueData (IUnknown *pUnk, const VARIANT varData) {

    if ( pUnk == NULL )

        return (E_INVALIDARG) ;

    LONG_PTR oldID;

    ((IAcadObject *)pUnk)->get_ObjectID(&oldID);     //利用 pUnk 获取当前选中实体对象的 ID

    AcDbObjectId objID;

    objID.setFromOldId(oldID);  

    //根据Id来锁定文档

    AcAxDocLock docLock( objID, AcAxDocLock::kNormal );

    if ( docLock.lockStatus() != Acad::eOk ){return E_FAIL; }  //锁定文档失败,返回 非

    AcDbEntityPointer pEntPtr( objID, AcDb::kForWrite );       //利用 ID 以写方式打开对象

    Acad::ErrorStatus es = pEntPtr.openStatus();

    if ( es != Acad::eOk )  {   return E_FAIL;  }            //打开实体失败,返回 非

    vector<CString> OutDatas =GetDatas(appName,pEntPtr);    //从实体中获取XData

    if(实体图层名 ==TEXT("地块") && OutDatas.size()==9)      //如果实体的图层="地块"、扩展属性的项数=9

    {

        bstr_t newVal( varData.bstrVal );               //获取文本框的值

        OutDatas[1] = _tcsdup( (ACHAR*)newVal );        //利用文本框的值修改扩展属性的第2项

        ModifyXData(pEntPtr,OutDatas);                  //修改实体的扩展属性(关闭实体)

        return (S_OK) ;    

    }

    else

    {

        pEntPtr->close();                //关闭实体

        return E_FAIL;

    }  

}

//修改项6.设定分类属性的标签名

STDMETHODIMP CZDXX1::GetCategoryName (PROPCAT propcat, LCID lcid, BSTR *pBstrName) {

    if ( pBstrName == NULL )

        return (E_POINTER) ;

    if ( propcat != 0 )

        return (E_INVALIDARG) ;

    *pBstrName =::SysAllocString (L"土地权属信息") ;

    return (S_OK) ;

}

3.5配套代码

本例要自定义分类<土地权属信息>下创建8个属性项,每个属性项都要获取和修改实体的扩展属性,其中二个列表框属性还要多次用到列表框条目,为了简化程序代码,需要做一些准备工作:

1.在StdAfx.h文件中声明几个全局变量和函数:

//- Declare it as an extern here so that it becomes available in all modules

extern AcApDataManager<CDocData> DocVars ;

extern CString 实体图层名;     //实体图层名

extern CString appName;        //注册应用程序名

extern CString 权属性质[9];    //权属性质列表框项目

extern CString 土地用途[15];   //土地用途列表框项目

#pragma pack (pop)

using namespace std;

using std::string;

    // 提示用户选择某个类型的实体,注意:调用者必须关闭实体

bool PromptSelectEntity(const TCHAR* prompt, AcRxClass* classDesc, AcDbEntity *&pEnt, AcGePoint3d &pickPoint,

       bool bOpenForWrite = true);

bool PromptSelectEntity(const TCHAR* prompt, const std::vector<AcRxClass*> &classDescs, AcDbEntity *&pEnt,

       AcGePoint3d &pickPoint, bool bOpenForWrite = true);

vector<CString> GetDatas(CString appName,AcDbEntity *pEnt);     //获取实体的扩展属性

void ModifyXData(AcDbEntity *pEnt,vector<CString> infoDatas);   //修改实体的扩展属性

2.StdAfx.cpp文件中定义几个全局变量和函数:

#include "StdAfx.h"

using namespace std;

using std::string;

CString 实体图层名;     //实体图层名

CString appName;        //注册应用程序名

CString 权属性质[9];    //权属性质列表框项目

CString 土地用途[15];   //土地用途列表框项目

bool PromptSelectEntity(const TCHAR* prompt, AcRxClass* classDesc, AcDbEntity *&pEnt,

    AcGePoint3d &pickPoint, bool bOpenForWrite /*= true*/)

{

    std::vector<AcRxClass*> descs;

    descs.push_back(classDesc);

    return PromptSelectEntity(prompt, descs, pEnt, pickPoint, bOpenForWrite);

}

bool PromptSelectEntity(const TCHAR* prompt, const std::vector<AcRxClass*> &classDescs, AcDbEntity *&pEnt,

    AcGePoint3d &pickPoint, bool bOpenForWrite/*= true*/ )

{

    ads_name ename;

RETRY:

    if (acedEntSel(prompt, ename, asDblArray(pickPoint)) != RTNORM)

    {

        pEnt = NULL;

        return false;

    }

    AcDbObjectId entId;

    acdbGetObjectId(entId, ename);

    // 判断选择的实体是否是指定类型的实体

    Acad::ErrorStatus es;

    if (bOpenForWrite)

    {

        es = acdbOpenObject(pEnt, entId, AcDb::kForWrite);

    }

    else

    {

        es = acdbOpenObject(pEnt, entId, AcDb::kForRead);

    }

    assert(es == Acad::eOk);

    bool bRet = false;

    for (int i = 0; i < (int)classDescs.size(); i++)

    {

        if (pEnt->isKindOf(classDescs[i]))

        {

            bRet = true;

            break;

        }

    }

    if (bRet)

    {

        return true;

    }

    else

    {

        pEnt->close();

        acutPrintf(TEXT("\n选择的实体类型不合要求, 请再次选择..."));

        goto RETRY;

    }

}

//获取实体的扩展属性

vector<CString> GetDatas(CString appName,AcDbEntity *pEnt) {

        TCHAR *szLayerName=pEnt->layer();          

        实体图层名.Format(_T("%s"),szLayerName);   //给全局变量(实体图层名)赋值,用于判断是否显示属性

        vector<CString> outInfos;          //字符串数组

        struct resbuf *pRb = pEnt->xData(appName);  //获取实体的扩展属性

        struct resbuf *pTemp = pRb;   //使用临时的结果缓冲区指针进行遍历pRb

        for (int i = 0;pTemp != NULL;i++, pTemp = pTemp->rbnext)

        {

            CString str;

            switch(pTemp->restype)

            {

                case 1001:  //注册应用程译序名

                case 1000:  //字符串类型属性项的文本

                    outInfos.push_back(pTemp->resval.rstring);                    

                    break;

                case 1040:  //实数类型属性项的实数转为文本

                    str.Format(TEXT("%.2f"), pTemp->resval.rreal);

                    outInfos.push_back(str);  

                    break;

                default:break;

            }      

        }

        acutRelRb(pRb);   //释放pRb           

        return outInfos;

    }

//修改实体的扩展属性

void ModifyXData(AcDbEntity *pEnt,vector<CString> infoDatas) {

    // 提示用户选择所要添加扩展数据的图形对象  

    acdbRegApp(infoDatas[0]);    //注册应用程序名称

    double a=_ttof(infoDatas[7]);

    //创建结果缓冲区链表

    struct resbuf* rb = acutBuildList(AcDb::kDxfRegAppName, infoDatas[0],

            AcDb::kDxfXdAsciiString, infoDatas[1],  //宗地简码

            AcDb::kDxfXdAsciiString, infoDatas[2],  //权利人

            AcDb::kDxfXdAsciiString, infoDatas[3],  //证件编号

            AcDb::kDxfXdAsciiString, infoDatas[4],  //权属性质

            AcDb::kDxfXdAsciiString, infoDatas[5],  //土地用途

            AcDb::kDxfXdAsciiString, infoDatas[6],  //共有人

            AcDb::kDxfXdReal,a,                     //宗地面积

            AcDb::kDxfXdAsciiString, infoDatas[8],  //宗地备注        

            RTNONE);

    pEnt->setXData(rb);   //为选择的实体添加扩展数据

    acutRelRb(rb);        //释放 rb

    pEnt->close();        //关闭实体

}

3.的acrxEntryPoint.cpp文件的On_kInitAppMsg初始化函数中添加初始化代码:

public:

    CmyOPMApp () : AcRxArxApp () {}

    virtual AcRx::AppRetCode On_kInitAppMsg (void *pkt) {

        AcRx::AppRetCode retCode =AcRxArxApp::On_kInitAppMsg (pkt) ;

        appName=TEXT("TDQSXX");   //提取扩展属性的注册应用程序名

        //土地用途列表框选项初始化

        土地用途[0]=(TEXT("071/城镇住宅用地"));

        土地用途[1]=(TEXT("072/农村宅基地"));

        土地用途[2]=(TEXT("081/机关团体用地"));

        土地用途[3]=(TEXT("082/新闻出版用地"));

        土地用途[4]=(TEXT("083/科教用地"));

        土地用途[5]=(TEXT("061/工业用地"));

        土地用途[6]=(TEXT("062/采矿用地"));

        土地用途[7]=(TEXT("063/仓储用地"));

        土地用途[8]=(TEXT("094/宗教用地"));

        土地用途[9]=(TEXT("095/殡葬用地"));

        土地用途[10]=(TEXT("101/铁路用地"));

        土地用途[11]=(TEXT("102/公路用地"));

        土地用途[12]=(TEXT("103/街巷用地"));

        土地用途[13]=(TEXT("104/农村道路"));

        土地用途[14]=(TEXT("其他"));

        //权属性质列表框选项初始化

        权属性质[0]=(TEXT("10/国有土地所有权"));

        权属性质[1]=(TEXT("20/国有土地使用权"));

        权属性质[2]=(TEXT("30/集体土地所有权"));

        权属性质[3]=(TEXT("31/村民小组"));

        权属性质[4]=(TEXT("32/村集体经济组织"));

        权属性质[5]=(TEXT("33/乡集体经济组织"));

        权属性质[6]=(TEXT("34/其它农民集体经济组织"));

        权属性质[7]=(TEXT("40/集体土地使用权"));

        权属性质[8]=(TEXT("其他"));

        return (retCode) ;

   }

4.为了调试程序的正确性,在acrxEntryPoint.cpp文件添加创建、查看和删除扩展属性的函数:

static void GroupAddXData() {

        // 提示用户选择所要添加扩展数据的图形对象

        AcDbEntity *pEnt = NULL;

        AcGePoint3d pickPoint;

        if (PromptSelectEntity(TEXT("\n选择所要添加的扩展数据的实体:"),

            AcDbEntity::desc(),pEnt,pickPoint))

        {          

            //注册应用程序名称

            acdbRegApp(appName);

            //创建结果缓冲区链表

            struct resbuf* rb = acutBuildList(AcDb::kDxfRegAppName, appName,

                //应用程序名称

                AcDb::kDxfXdAsciiString, TEXT("00159"),               //宗地简码

                AcDb::kDxfXdAsciiString, TEXT("刘胜利"),              //权利人

                AcDb::kDxfXdAsciiString, TEXT("320102196906182735"),  //证件编号

                AcDb::kDxfXdAsciiString, TEXT("31/村民小组"),         //权属性质

                AcDb::kDxfXdAsciiString, TEXT("083/科教用地"),        //土地用途

                AcDb::kDxfXdAsciiString, TEXT("刘小兰"),              //共有人

                AcDb::kDxfXdReal,186.27,                              //宗地面积

                AcDb::kDxfXdAsciiString, TEXT("宗地备注"),            //宗地备注 

                RTNONE);

            //为选择的实体添加扩展数据

            pEnt->setXData(rb);

            acutRelRb(rb);

            acutPrintf(TEXT("\n成功为实体添加了扩展数据."));

            pEnt->close();

        }

    }

    static void GroupViewXData() {

        CString DataTitle[9];   //属性标题

        //属性标题初始化

        DataTitle[0]=TEXT("注册程序名");

        DataTitle[1]=TEXT("宗地简码");

        DataTitle[2]=TEXT("权利人");

        DataTitle[3]=TEXT("证件编号");

        DataTitle[4]=TEXT("权属性质");

        DataTitle[5]=TEXT("土地用途");

        DataTitle[6]=TEXT("共有人");

        DataTitle[7]=TEXT("宗地面积");

        DataTitle[8]=TEXT("宗地备注");

        //提示用户选择所要查看扩展数据的图形对象

        AcDbEntity *pEnt = NULL;

        AcGePoint3d pickPoint;

        if (PromptSelectEntity(TEXT("\n选择要查看扩展数据的实体:"), AcDbEntity::desc(), pEnt, pickPoint))

        {

            //struct resbuf *pRb = pEnt->xData(appName);

            vector<CString> OutDatas =GetDatas(appName,pEnt);   //从实体中获取XData

            pEnt->close();                //关闭实体           

            for (int i = 0;i<OutDatas.size();i++)

            {

                acutPrintf(TEXT("\n") +DataTitle[i]+TEXT("=")+OutDatas[i]);            

            }

        }

    }

    //注册新命令DeleteXData,用于从实体中删除特定的扩展数据

    static void GroupDeleteXData() {

        //提示用户选择所要删除扩展数据的图形对象

        AcDbEntity *pEnt = NULL;

        AcGePoint3d pickPoint;

        if (PromptSelectEntity(TEXT("\n选择所要删除扩展数据的实体:"),

            AcDbEntity::desc(),pEnt,pickPoint))

        {          

            acdbRegApp(appName);  //注册应用程序名称

            //利用扩展属性的应用程序名,称创建结果缓冲区链表

            struct resbuf *rb = acutBuildList(AcDb::kDxfRegAppName, appName, RTNONE);

            //把内容为空的结果缓冲区链表赋值给实体,就是删除实体的扩展数据

            pEnt->setXData(rb);

            acutRelRb(rb);     //释放pRb

            acutPrintf(TEXT("\n成功为实体删除了扩展数据."));

            pEnt->close();

        }

   }

5. acrxEntryPoint.cpp文件的底部注册三个命令:

IMPLEMENT_ARX_ENTRYPOINT(CmyOPMApp)

ACED_ARXCOMMAND_ENTRY_AUTO(CmyOPMApp, Group, AddXData, AddXData, ACRX_CMD_MODAL, NULL)

ACED_ARXCOMMAND_ENTRY_AUTO(CmyOPMApp, Group, ViewXData, ViewXData, ACRX_CMD_MODAL, NULL)

ACED_ARXCOMMAND_ENTRY_AUTO(CmyOPMApp, Group, DeleteXData, DeleteXData, ACRX_CMD_MODAL, NULL)

我们编译这个工程,然后加载到 AutoCAD 中。在 AutoCAD 创建一个图层“地块”,画一条封闭的多段线,用AddXData命令为多段线创建扩展属性,然后选中,并打开特性窗口(Ctrl + 1),就可以看到这个自已的动态属性了。

3.6添加列表框属性项(枚举属性)

 

枚举属性共生成17个函数,其中有9个函数需修改:

//-----------------------------------------------------------------------------

//----- ZDXX4.cpp : Implementation of CZDXX4

//-----------------------------------------------------------------------------

//修改项1.设定属性项的名称

STDMETHODIMP CZDXX4::GetDisplayName (BSTR *pBstrName) {

    if ( pBstrName == NULL )

        return (E_POINTER) ;

    *pBstrName =::SysAllocString (L"权属性质") ;

    return (S_OK) ;

}

//修改项2.属性项的提示描述文本

STDMETHODIMP CZDXX4::GetDescription (BSTR *pBstrName) {

    if ( pBstrName == NULL )

        return (E_POINTER) ;

    *pBstrName =::SysAllocString (L"指定本宗地的土地权属性质") ;

    return (S_OK) ;

}

//修改项3.属性值的数据类型

STDMETHODIMP CZDXX4::GetCurrentValueName (BSTR *pBstrName) {

    if ( pBstrName == NULL )

        return (E_POINTER) ;

    return (E_NOTIMPL) ;

    //当GetCurrentValueType函数定义的类型为预定义属性时,*pBstrName取值如下:

    //对话框类型

    //*pBstrName =::SysAllocString (L"ACAD_COLOR") ;     //内置的颜色对话框

    //*pBstrName =::SysAllocString (L"ACAD_LAYER") ;     //内置的图层对话框

    //*pBstrName =::SysAllocString (L"ACAD_DISTANCE") ;  //内置的距离对话框

    //*pBstrName =::SysAllocString (L"ACAD_ANGLE") ;     //内置的角度对话框

    //*pBstrName =::SysAllocString (L"ACAD_NOUNITS") ;   //无单位的属性值

    //*pBstrName =::SysAllocString (L"ACAD_LWEIGHT") ;   //内置的线宽对话框

}

//修改项4.获取属性项的值

STDMETHODIMP CZDXX4::GetCurrentValueData (IUnknown *pUnk, VARIANT *pVarData) {

    if ( pUnk == NULL )

        return (E_INVALIDARG) ;

    if ( pVarData == NULL )

        return (E_POINTER) ;

    //变体内容的初始化,   

    ::VariantInit( pVarData );

    V_VT( pVarData ) = VT_I4; //LONG

    LONG_PTR oldID;

    ((IAcadObject *)pUnk)->get_ObjectID(&oldID);   //利用 pUnk 获取当前选中实体对象的 ID

    AcDbObjectId objID;

    objID.setFromOldId(oldID); 

    AcDbEntityPointer pEntPtr( objID, AcDb::kForRead );   //利用 ID 以读方式打开实体

    Acad::ErrorStatus es = pEntPtr.openStatus();

    if ( es != Acad::eOk)   {   return E_FAIL;  }         //打开实体失败,返回 非

    //从实体中获取XData

    vector<CString> OutDatas =GetDatas( appName,pEntPtr);  

    pEntPtr->close();     //关闭实体

    if(实体图层名 ==TEXT("地块") && OutDatas.size()==9)  //如果实体的图层="地块"、扩展属性的项数=9

    {   //控件的值=扩展属性第二项(第一项的索引为0)

        bstr_t pBstr( OutDatas[4] );      //扩展属性的第4项

        pVarData->bstrVal = pBstr.copy();

        long 列表框当前选项的编号=8;

        for(int i=0;i<8;i++)

        {

            if(权属性质[i]==OutDatas[4])  { 列表框当前选项的编号=i; }

        }

        V_I4( pVarData ) =(LONG) 列表框当前选项的编号;   

        return (S_OK) ;

    }

    return E_FAIL

}

//修改项5.修改属性项的值(从pUnk中取得ID打开实体;varData.lVal中的列表框当前项的索引值取得新的属性值,更改实体)

STDMETHODIMP CZDXX4::SetCurrentValueData (IUnknown *pUnk, const VARIANT varData) {

    //变体数据类型 VARIANT varData 其中:

    //             varData.vt 是数据类型;

    //             varData.lVal 是数据的值,本例中varData.lVal 是列表框当前项的索引值

    if ( pUnk == NULL )

        return (E_INVALIDARG) ;

    long i=varData.lVal;    //修改了组合框的当前项,现在的当前项的索引值=i

    LONG_PTR oldID;

    ((IAcadObject *)pUnk)->get_ObjectID(&oldID);

    AcDbObjectId objID;

    objID.setFromOldId(oldID);

    //根据Id来锁定文档

    AcAxDocLock docLock( objID, AcAxDocLock::kNormal );

    if ( docLock.lockStatus() != Acad::eOk ){return E_FAIL; }

    //利用 ID 以写方式打开对象

    AcDbEntityPointer pEntPtr( objID, AcDb::kForWrite );

    Acad::ErrorStatus es = pEntPtr.openStatus();

    if ( es != Acad::eOk )  {return E_FAIL; }

    //从实体中获取XData

    vector<CString> OutDatas =GetDatas(appName,pEntPtr);    //从实体中获取XData

    if(实体图层名 ==TEXT("地块") && OutDatas.size()==9)      //如果实体的图层="地块"、扩展属性的项数=9

    {

        OutDatas[4]=权属性质[i];                  //当前组合框的值(i项)替换实体的属性值

        ModifyXData(pEntPtr,OutDatas);            //修改实体的扩展属性(关闭实体)

        m_pNotify->OnChanged ( pUnk ) ;           //在这里通知特性窗口更新组合框的值

        return (S_OK) ;    

    }

    else

    {

        pEntPtr->close();                //关闭实体

        return E_FAIL;

    }          

}

//修改项6.设定分类属性的标签名

STDMETHODIMP CZDXX4::GetCategoryName (PROPCAT propcat, LCID lcid, BSTR *pBstrName) {

    if ( pBstrName == NULL )

        return (E_POINTER) ;

    if ( propcat != 0 )

        return (E_INVALIDARG) ;

    *pBstrName =::SysAllocString (L"土地权属信息") ;

    return (S_OK) ;

}

//----- IDynamicEnumProperty

//枚举属性修改项1.pNumValues 为该枚举属性的个数,必须为正整数

STDMETHODIMP CZDXX4::GetNumPropertyValues (LONG *pNumValues) {

    if ( pNumValues == NULL )

        return (E_POINTER) ;

    *pNumValues =9 ;

    return (S_OK) ;

}

//枚举属性修改项2.按 index 的次序设置在 comboBox 内显示的条目文本

STDMETHODIMP CZDXX4::GetPropValueName (LONG index, BSTR *pBstrValueName) {

    if ( pBstrValueName == NULL )

        return (E_POINTER) ;

    //根据index以次添加组合列表框的条目,内容在acrxEntryPoint.cpp>On_kInitAppMsg中初始化

    bstr_t bStr( 权属性质[index] );

    *pBstrValueName = bStr.copy();  

    return (S_OK) ;

}

//枚举属性修改项3.按 index 的次序显示在 comboBox 内添加条目

STDMETHODIMP CZDXX4::GetPropValueData (LONG index, VARIANT* pValue) {

    if ( pValue == NULL )

        return (E_POINTER) ;

    ::VariantInit (pValue) ;

    V_VT(pValue) =VT_I4 ;  

    V_I4(pValue) = (LONG) index;   //获取当前选项的索引值

    return (S_OK) ;

}

按同样的方法添加第5个属性项:参考代码中的说明完成代码的修改。

按3.1同样的方法添加第2、第3、第6、第7、第8等5个属性项,参考代码中的说明完成代码的修改。

我们编译这个工程,然后加载到 AutoCAD 中。在 AutoCAD 创建一个图层“地块”,画一条封闭的多段线,用AddXData命令为多段线创建扩展属性,然后选中,并打开特性窗口(Ctrl + 1),就可以看到完整的动态属性了。

 

3.7属性项的显示顺序

属性项的显示顺序是根据属性文件(类)的名称按序进行排列,为了能按你的要求次序显示属性项,应预先设计好所有属性文件(类)的名称、类型、连接实体扩展属性的序号等信息,逐个添加属性项。本例中8个属性项的类名分别为CZDXX1;CZDXX2;CZDXX3;-----CZDXX8。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值