小众知识

ObjectArx2010图层操作总结
2016-08-05 09:08:06   来源:   评论:0 点击:

图层操作是ObjectArx2010对AutoCAD2010进行开发的一个重点,本文将其进行总结,主要包括使用ObjectArx2010创建图层,删除一个已经存在的图层,修改图层的属性等图层操作相关的内容。

图层操作是ObjectArx2010对AutoCAD2010进行开发的一个重点,对AutoCAD2010有一定使用经验的用户都知道,AutoCAD2010默认的图层几乎总是无法满足实际需要,我们得定义自己的图层,那么如何使用ObjectArx2010完成图层的定制呢?网上各大论坛有很多答案,本文将其进行总结,主要包括使用ObjectArx2010创建图层,删除一个已经存在的图层,修改图层的属性等图层操作相关的内容,为方便理解,本文将给出一个相对完整的图层操作工具类实现相关功能,读者可以直接使用其中的全部或者部分源代码。

首先定义一个图层信息类,

#include <sstream>
/**
图层参数的类
**/
class LayerInfo{
public:
    //图层名称
    std::wstring layerName;
    //颜色序号
    Adesk::UInt16 colorIndex;
    //线型
    std::wstring typeName;
    //线宽
    AcDb::LineWeight weight;
public:
    LayerInfo();
    LayerInfo(ACHAR* layerName,       
        Adesk::UInt16 color,    
        ACHAR* ltype,AcDb::LineWeight w);
    //格式化成字符串
    CString ToString();    
    //格式化标题
    static CString FormatTitle();
    //通过字符串实例化一个图层
    static LayerInfo LoadByStr(CString line);
};

LayerInfo类的目的是方便图层信息的操作,同时实现了将图层信息格式化成预设格式的字符串,格式化自定义的标题行以及从文件行实例化一个图层信息类的功能接口,LayerInfo的完整实现如下:

LayerInfo::LayerInfo():
layerName(_T("")),
colorIndex(0),
typeName(_T("")),
weight(AcDb::LineWeight::kLnWt000){
}
LayerInfo::LayerInfo(ACHAR* layerName,
        Adesk::UInt16 color,
        ACHAR* ltype,
        AcDb::LineWeight w):
layerName(layerName),
colorIndex(color),
typeName(ltype),
weight(w)
{
}
//格式化成字符串
CString LayerInfo::ToString(){
    CString strLayer;
    strLayer.Format(_T("%-20s%-20d%-20s%-20d"),
        layerName.c_str(),
        colorIndex,
        typeName.
        c_str(),
        weight);
    //strLayer.Format(_T("%s%d%s%d"),"0",7,"Continuous",-3);
    return strLayer;
}
//格式化标题
CString LayerInfo::FormatTitle(){
    CString strTitle;
    strTitle.Format(_T("%-20s%-20s%-20s%-20s"),
        _T("layerName"),
        _T("colorIndex"),
        _T("typeName"),
        _T("weight"));
    return strTitle;
}
//通过字符串实例化一个图层
LayerInfo LayerInfo::LoadByStr(CString line){
    LayerInfo layer;
    std::wstring str(line.GetBuffer());    
    std::wistringstream input_istring(str);
    int lineWeight=0;
    input_istring
        >>layer.layerName
        >>layer.colorIndex
        >>layer.typeName
        >>lineWeight;
    layer.weight=static_cast<AcDb::LineWeight>(lineWeight);
    //释放缓存区
    line.ReleaseBuffer();
    return layer;
}

现在开始设计图层操作工具类CLayerOperator,根据前面的讨论,CLayerOperator需要完成的功能包括:a.定义一个新图层;b.删除图层;c.编辑图层的属性,包括线宽,颜色,线型;在工具类CLayerOperator中,我们还增加了将当前图形导出到文件和从文件导入到模型空间的功能。CLayerOperator的完整定义如下:

/**
图层操作的工具类
**/
class CLayerOperator
{
public:
    CLayerOperator(void);
    ~CLayerOperator(void);
    // 新建一个图层
    static void NewLayer(ACHAR* layerName);
    // 使用图形对话框设置指定图层的颜色
    static void SetLayerColor(ACHAR* layerName);
    // 删除一个图层
    static void DelLayer(ACHAR* layerName);
    // 导出图层到文件中
    static void ExportLayers(ACHAR* fileName);
    // 从文件导入图层
    static void ImportLayers(ACHAR* fileName);
    // 采用命令方式加载一种新的线型
    static bool _CMDLoadLineType(ACHAR* linetype);
    //加载一种新的线型
    static AcDbObjectId LoadLineType(const ACHAR* linetype,
        const ACHAR* fileName=_T("acadiso.lin"),
        AcDbDatabase* pDb=acdbCurDwg());
    //取得线型ID
    //输入参数:AcDbDatabase* pDb, 数据库
    // const ACHAR *LineName 线型名称 
    static AcDbObjectId CLayerOperator::GetLineId(const ACHAR *LineName,
        AcDbDatabase* pDb=acdbCurDwg());
    //加载图层到图形数据库
    static void CLayerOperator::LoadLayer(const LayerInfo& layerInfo,
        AcDbDatabase* pDb=acdbCurDwg());
};

下面讨论CLayerOperator类的具体实现。

 

1. 新建一个图层

CLayerOperator定义了NewLayer函数,用于完成图层的新建操作,NewLayer的完整代码如下:

// 新建一个图层
void CLayerOperator::NewLayer(ACHAR* layerName)
{
    //获得当前图形的层表
    AcDbLayerTable *pLayerTbl;
    acdbHostApplicationServices()
        ->workingDatabase()
        ->getLayerTable(pLayerTbl,AcDb::kForWrite);

    //是否已经包含指定的层表记录
    if(pLayerTbl->has(layerName)){
        pLayerTbl->close();
        acedPrompt(_T("对应名称的图层已经存在!"));
        return;
    }

    //创建层表记录
    AcDbLayerTableRecord *pLayerTblRcd;
    pLayerTblRcd=new AcDbLayerTableRecord();
    pLayerTblRcd->setName(layerName);

    //将新建的层表记录添加到层表中
    AcDbObjectId layerTblRcdId;
    pLayerTbl->add(layerTblRcdId,pLayerTblRcd);

    //设置图形的当前图层
    acdbHostApplicationServices()
        ->workingDatabase()
        ->setClayer(layerTblRcdId);

    pLayerTblRcd->close();
    pLayerTbl->close();
}

NewLayer的具体实现注释已经非常详尽,首先获得当前图形的层表,然后判断层表中是否已经存在指定名称的图层,如果是,则直接返回,否则创建层表记录并将新建的层表记录添加到层表中,最后通过AcDbDatabase类的setClayer函数将新建的图层设置成当前图层。

2.使用图形对话框设置指定图层的颜色

// 使用图形对话框设置指定图层的颜色
void CLayerOperator::SetLayerColor(ACHAR* layerName)
{
    //获得当前图形的层表
    AcDbLayerTable *pLayerTbl;
    acdbHostApplicationServices()
        ->workingDatabase()
        ->getLayerTable(pLayerTbl,AcDb::kForRead);

    //判断是否包含指定名称的层表记录
    if(!pLayerTbl->has(layerName)){
        pLayerTbl->close();
        return;
    }

    //获得指定层表记录的指针
    AcDbLayerTableRecord *pLayerTblRcd;
    pLayerTbl->getAt(layerName,pLayerTblRcd,AcDb::kForWrite);

    //弹出“颜色”对话框
    AcCmColor oldColor=pLayerTblRcd->color();
    //图层修改前的颜色
    int nCurColor=oldColor.colorIndex();
    //用户选择的颜色
    int nNewColor=oldColor.colorIndex();
    if(acedSetColorDialog(nNewColor,Adesk::kFalse,nCurColor)){
        AcCmColor color;
        color.setColorIndex(nNewColor);
        pLayerTblRcd->setColor(color);
    }

    pLayerTblRcd->close();
    pLayerTbl->close();
}

3.删除一个图层

// 删除一个图层
void CLayerOperator::DelLayer(ACHAR* layerName)
{
    //获得当前图形的层表
    AcDbLayerTable *pLayerTbl;
    acdbHostApplicationServices()
        ->workingDatabase()
        ->getLayerTable(pLayerTbl,AcDb::kForRead);

    //判断是否包含指定名称的层表记录
    if(!pLayerTbl->has(layerName)){
        pLayerTbl->close();
        return;
    }

    //获得指定层表记录的指针
    AcDbLayerTableRecord *pLayerTblRcd;
    pLayerTbl->getAt(layerName,pLayerTblRcd,AcDb::kForWrite);
    //为其设置“删除”标记
    pLayerTblRcd->erase();

    pLayerTblRcd->close();
    pLayerTbl->close();
}


4.导出图层到文件中

// 导出图层到文件中
void CLayerOperator::ExportLayers(ACHAR* fileName)
{
    //创建所要导出的文件
    CStdioFile f2;
    CFileException err;
    if(!f2.Open(fileName,CFile::modeCreate|CFile::modeWrite,&err)){
        acutPrintf(_T("
创建导出文件失败!"));
        return;
    }

    //获得层表指针
    AcDbLayerTable *pLayerTbl;
    AcDbLayerTableRecord *pLayerTblRcd;
    acdbHostApplicationServices()
        ->workingDatabase()
        ->getLayerTable(pLayerTbl,AcDb::kForRead);

    //使用遍历器访问每一条层表记录
    AcDbLayerTableIterator *pItr;
    pLayerTbl->newIterator(pItr);
    f2.WriteString(LayerInfo::FormatTitle());
    f2.WriteString(_T("
"));
    for(pItr->start();!pItr->done();pItr->step()){
        pItr->getRecord(pLayerTblRcd,AcDb::kForRead);

        //图层信息
        LayerInfo layerInfo;    
        //1.图层的名称
        ACHAR *layerName;
        pLayerTblRcd->getName(layerName);    //使用后需要手动free
        layerInfo.layerName=layerName;        
        free(layerName);
        //2.图层的颜色
        AcCmColor color=pLayerTblRcd->color();
        layerInfo.colorIndex=color.colorIndex();
        //3.图层的线型
        AcDbLinetypeTableRecord *pLineTypeTblRcd;
        acdbOpenObject(pLineTypeTblRcd,
            pLayerTblRcd->linetypeObjectId(),
            AcDb::kForRead);
        ACHAR* lineTypeName;
        pLineTypeTblRcd->getName(lineTypeName);    //使用后需要手动free
        pLineTypeTblRcd->close();
        layerInfo.typeName=lineTypeName;
        free(lineTypeName);            
        //4.图层的线宽
        AcDb::LineWeight lineWeight=pLayerTblRcd->lineWeight();
        layerInfo.weight=lineWeight;
        //将图层特性写入到文件中
        f2.WriteString(layerInfo.ToString());
        f2.WriteString(_T("
"));

        pLayerTblRcd->close();
    }
    delete pItr;
    pLayerTbl->close();
}

5. 从文件导入图层到模型空间

// 从文件导入图层
void CLayerOperator::ImportLayers(ACHAR* fileName)
{
    //打开所要导入的文本文件
    CStdioFile f;
    CFileException err;
    if(!f.Open(fileName,CFile::modeRead,&err)){
        acutPrintf(_T("
打开导入文件失败!"));
        return;
    }

    //读取文件中的每一行数据
    CString strLineText;
    //读取标题行
    if(!f.ReadString(strLineText))
        return;
    while(f.ReadString(strLineText)){
        //跳过空行
        if(strLineText.IsEmpty())
            continue;
        LayerInfo layInfo=LayerInfo::LoadByStr(strLineText);
        //加载图层到图形数据库
        LoadLayer(layInfo);        
    }
}

依据文件信息创建图层时,很可能出现指定的现在没有载入的情况,关于ObjectArx导入线型,网上搜集了很多资料,总结了以下两种方法。

a.使用命令的方式导入线型,具体代码如下:

// 采用命令方式加载一种新的线型
bool CLayerOperator::_CMDLoadLineType(ACHAR* linetype){

    AcDbLinetypeTable *pLinetypeTbl;
    bool flag1=true;

    acdbHostApplicationServices()
        ->workingDatabase()
        ->getSymbolTable(pLinetypeTbl, AcDb::kForRead);

    if(!pLinetypeTbl->has(linetype))
        flag1=false;

    pLinetypeTbl->close();

    if(!flag1){
        if(acedCommand(RTSTR,
            _T("LINETYPE"),
            RTSTR,
            _T("L"),
            RTSTR,
            linetype,
            RTSTR,
            _T(""),
            RTSTR,
            _T(""),
            0)!=RTNORM)
            acutPrintf(_T("
 调入线型%s时出现错误!"),linetype);
        return false;
    }
    return true;
}

b.直接使用ObjectArx2010提供的API函数

//加载线型
//数入参数:AcDbDatabase *pDb, 数据库
// const CString linetype 线型名称
AcDbObjectId CLayerOperator::LoadLineType(const ACHAR* linetype,
        const ACHAR* fileName,
        AcDbDatabase* pDb)
{
    AcDbObjectId lineTypeId=GetLineId(linetype,pDb);
    //对应名称的线型已经存在
    if(lineTypeId!=0)
        return lineTypeId;
    //从文件中加载线型
    Acad::ErrorStatus es=pDb->loadLineTypeFile(linetype,fileName);
    //如果加载成功
    if(es==Acad::eOk){
        lineTypeId=GetLineId(linetype,pDb);
    }else{//如果加载失败,返回默认的ID
        lineTypeId=GetLineId(_T("Continous"),pDb);        
    }
    return lineTypeId;
}

//取得线型ID
//输入参数:AcDbDatabase* pDb, 数据库
// const ACHAR *LineName 线型名称 
AcDbObjectId CLayerOperator::GetLineId(const ACHAR *LineName,
        AcDbDatabase* pDb)
{
    AcDbLinetypeTable* pTable=NULL;
    AcDbObjectId id=AcDbObjectId::kNull;
    pDb->getLinetypeTable(pTable,AcDb::kForRead);

    if(pTable){
        Acad::ErrorStatus Error=pTable->getAt(LineName,id);
        pTable->close();
    }
    return id;
}

读者可以根据实际情况选用,笔者建议在ObjectArx2010开发过程中尽量使用第二种方案。

6.加载图层到图形数据库

//加载图层到图形数据库
void CLayerOperator::LoadLayer(const LayerInfo& layerInfo,
        AcDbDatabase* pDb){
    //获得层表指针
    AcDbLayerTable *pLayerTbl;
    AcDbLayerTableRecord *pLayerTblRcd;
    pDb->getLayerTable(pLayerTbl,AcDb::kForWrite);
    //1.创建新的层表记录,或者打开已经存在的层表表记录
    AcDbObjectId layerTblRcdId;
    if(pLayerTbl->has(layerInfo.layerName.c_str())){
        pLayerTbl->getAt(layerInfo.layerName.c_str(),layerTblRcdId);
    }else{
        pLayerTblRcd=new AcDbLayerTableRecord();
        pLayerTblRcd->setName(layerInfo.layerName.c_str());
        pLayerTbl->add(layerTblRcdId,pLayerTblRcd);
        pLayerTblRcd->close();
    }

    acdbOpenObject(pLayerTblRcd,layerTblRcdId,AcDb::kForWrite);

    //2.设置层表记录的颜色
    AcCmColor color;
    Adesk::UInt16 colorIndex=layerInfo.colorIndex;
    color.setColorIndex(colorIndex);
    pLayerTblRcd->setColor(color);
    //3.设置线型
    AcDbObjectId lineTypeId;        
    lineTypeId=LoadLineType(layerInfo.typeName.c_str());        
    pLayerTblRcd->setLinetypeObjectId(lineTypeId);
    //4.设置线宽
    pLayerTblRcd->setLineWeight(layerInfo.weight);

    pLayerTblRcd->close();
    pLayerTbl->close();
}

7. 测试代码

读者可以使用ObjectArx的AddIn工具栏添加测试命令,下面是对图层操作类CLayerOperator进行测试的相关代码,前面的文章已经详细介绍了添加命令函数的方法,本文不再赘述。

    // - CHAP4._NewLayer command (do not rename)
    static void CHAP4_NewLayer(void)
    {
        //提示用户输入新建图层的名称
        ACHAR layerName[BUFSIZ]={0};
        if(acedGetString(Adesk::kFalse,_T("
输入新图层的名称:"),
            layerName)!=RTNORM){
            return;
        }

        CLayerOperator::NewLayer(layerName);        
    }

    // - CHAP4._LayerColor command (do not rename)
    static void CHAP4_LayerColor(void)
    {
        //提示用户输入要修改的图层名称
        ACHAR layerName[BUFSIZ];
        if(acedGetString(Adesk::kFalse,_T("
输入图层的名称:"),
            layerName)!=RTNORM){
            return;
        }

        CLayerOperator::SetLayerColor(layerName);        
    }

    // - CHAP4._DelLayer command (do not rename)
    static void CHAP4_DelLayer(void)
    {
        //提示用户输入要修改的图层名称
        ACHAR layerName[BUFSIZ];
        if(acedGetString(Adesk::kFalse,_T("
输入图层的名称:"),
            layerName)!=RTNORM){
            return;
        }

        CLayerOperator::DelLayer(layerName);        
    }

    // - CHAP4._ExportLayer command (do not rename)
    static void CHAP4_ExportLayer(void)
    {
        CFileDialog dlgFile(FALSE,
            _T(".lay"),
            _T("layer"),
            OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
            _T("layer files(*.lay)|*.lay||"));
        if(dlgFile.DoModal()==IDOK){
            CString flilePath=dlgFile.GetPathName();
            CLayerOperator::ExportLayers(flilePath.GetBuffer());
            flilePath.ReleaseBuffer();
        }
        
    }

    // - CHAP4._ImportLayer command (do not rename)
    static void CHAP4_ImportLayer(void)
    {
        CFileDialog dlgFile(TRUE,
            _T(".lay"),
            _T("layer"),
            OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
            _T("layer files(*.lay)|*.lay||"));
        if(dlgFile.DoModal()==IDOK){
            CString flilePath=dlgFile.GetPathName();
            CLayerOperator::ImportLayers(flilePath.GetBuffer());
            flilePath.ReleaseBuffer();
        }
    }

    // - CHAP4._LoadLineType command (do not rename)
    static void CHAP4_LoadLineType(void)
    {
        //提示用户输入要修改的图层名称
        ACHAR lineType[BUFSIZ];
        if(acedGetString(Adesk::kFalse,_T("
输入线型的名称:"),
            lineType)!=RTNORM){
            return;
        }

        CLayerOperator::LoadLineType(lineType);
    }
};

好了,使用ObjectArx2010对AutoCAD2010图层进行操作就介绍完了,本程序的所有代码在Win7+VC2008 SP1+ObjectArx2010+AutoCAD2010编译并运行通过,如果你还有补充和意见,欢迎在留言区进行讨论。

相关热词搜索:ObjectArx 图层

上一篇:CAD二次开发遇到 eLockViolation 的问题
下一篇:AcDbText设置文字对齐方式

分享到: 收藏
评论排行
最新发布