Add new attributes to a block using ObjectARX

By Xiaodong Liang

The first thing you need to know is: in AutoCAD, block definitions are AcDbBlockTableRecords, just as are “MODEL_SPACE” and “PAPER_SPACE” records. A Block definition typically has entities and AcDbAttributeDefinition objects associated with it. To add a new attribute to the block definition, it is a matter of adding another AcDbAttributeDefinition to the AcDbBlockTableRecord in which you are interested.

Adding a New Attribute Definition

The following code adds one AcDbAttributeDefinition to a block definition. It assumes a drawing is open and there is a block named “Test” in the drawing.

void AddNewAtt()
{
    AcDbDatabase *pCurDb;
    AcDbBlockTable* pBlkTbl;
    AcDbBlockTableRecord* pBlkRec;
    AcDbObjectId attId;
    Acad::ErrorStatus es;
    AcDbAttributeDefinition* pAttDef;

    // Location of the AttributeDefinition in the block definition
    AcGePoint3d attLoc(1.2, -0.5, 0);

    // Specify the text, tag and prompt
    ACHAR text[] = {L"NEW VALUE ADDED"};
    ACHAR tag[] = {L"MYTAG"};
    ACHAR prompt[] = {L"Enter a new value"};

    pCurDb = acdbHostApplicationServices()->workingDatabase();
    es = pCurDb->getBlockTable(pBlkTbl, AcDb::kForRead);

    if(!pBlkTbl->has(L"TEST"))
    {
        acutPrintf(L"\nBlock definition TEST does not exist");
        pBlkTbl->close();
        return;
    }

    es = pBlkTbl->getAt(L"TEST", pBlkRec, AcDb::kForWrite);

    // Create an AttributeDefinition
    pAttDef = new AcDbAttributeDefinition(attLoc, text, tag, prompt);

    // Append the AttributeDefinition to the block definition
    es = pBlkRec->appendAcDbEntity(attId, pAttDef);

    pAttDef->close();
    pBlkRec->close();
    pBlkTbl->close();
}

Updating Existing Block References

Now the block definition is modified. If you insert a new block reference, you will be prompted for the attribute value. However, existing block references do not have these values yet. To set them, you must iterate through all block references and update them.

void UpdateATT()
{
    AcDbDatabase *pCurDb = acdbHostApplicationServices()->workingDatabase();
    AcDbBlockTable* pBlkTbl;
    Acad::ErrorStatus es = pCurDb->getBlockTable(pBlkTbl, AcDb::kForRead);

    if(!pBlkTbl->has(L"TEST"))
    {
        acutPrintf(L"\nBlock definition TEST does not exist");
        pBlkTbl->close();
        return;
    }

    AcDbBlockTableRecord *pBlkRec;
    es = pBlkTbl->getAt(L"TEST", pBlkRec, AcDb::kForWrite);
    if(es != Acad::eOk)
    {
        acutPrintf(L"\nError opening block definition.");
        pBlkTbl->close();
        return;
    }

    // Get the block references that use this definition
    AcDbObjectIdArray ids;
    pBlkRec->getBlockReferenceIds(ids);
    pBlkRec->close();
    pBlkTbl->close();

    // Iterate through each block reference
    for(int i=0; i < ids.length(); i++)
    {
        AcDbBlockReference *pBlkRef;
        es = acdbOpenObject(pBlkRef, ids[i], AcDb::kForWrite);
        
        if (es == Acad::eOk)
        {
            AcDbObjectIterator *pAttribIter = pBlkRef->attributeIterator();
            for(pAttribIter->start(); !pAttribIter->done(); pAttribIter->step())
            {
                AcDbObjectId blkRefAttId = pAttribIter->objectId();
                AcDbAttribute *pBlkRefAtt;
                es = pBlkRef->openAttribute(pBlkRefAtt, blkRefAttId, AcDb::kForWrite);

                if (es == Acad::eOk)
                {
                    ACHAR *pAttTag = pBlkRefAtt->tag();
                    if(_tcscmp(pAttTag, L"MYTAG") == 0)
                    {
                        // Update the attribute value
                        pBlkRefAtt->setTextString(L"My Value");
                    }
                    acutDelString(pAttTag);
                    pBlkRefAtt->close();
                }
            }
            delete pAttribIter;
            pBlkRef->close();
        }
    }
}

Comments

2 responses to “Add new attributes to a block using ObjectARX”

  1. Hi Xiaodong,
    Thanks a lot for your code here. I am really a beginner and I need to do the same thing as here, adding new attribute to an existing block. my problem is I dont know the parts that you have summarized in your code, like AcDbDatabase pCurDb;
    AcDbBlockTable
    pBlkTbl;
    AcDbBlockTableRecord* pBlkRec;
    AcDbObjectId attId;
    Acad::ErrorStatus es;
    can you please write the complete code
    Thanks
    Pouria

  2. How do I change the “Prompt” tab in the block attributes?

Leave a Reply

Discover more from Autodesk Developer Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading