Author Topic: Layouts, Blocks, Attributes...  (Read 10247 times)

0 Members and 1 Guest are viewing this topic.

vegbruiser

  • Guest
Layouts, Blocks, Attributes...
« on: July 01, 2008, 05:43:36 AM »
Hi,
   I've been struggling with the following problem for a couple of weeks and I wondered if one of you fine chaps would be able to point me in the right direction:

In VBA, if I want to find and edit specific attributes contained within the layouts of a drawing I'd simply do this: -

Code: [Select]
Set layouts = thisdrawing.layouts
for each layout in layouts
 Thisdrawing.activelayout = layout
 If thisdrawing.activelayout.name <> "Model" then
  For each Bobj in thisdrawing.paperspace
   If Bobj.objectname = "AcDbBlockreference" Then
    varattributes = bobj.getattributes
    for i = lbound(varattributes) to ubound(varattributes)
     if ucase(varattributes(i).TagString = ucase("date") then
      varattributes(i).textstring = "some value"
     end if
    next i
   End if
  Next
 end if
next

Now, I realise that the .NET way of doing this is almost completely different, and, having paid for the latest .NET book by Jerry Winters, I am beginning to get to grips with the problem, but am still having a hard time getting the .NET equivalent of the above code working.

As I understand it, having searched both the Autodesk .NET newsgroups, and this very forum is that I need to search the Blocktablerecords and determine whether the various blockreferences I find are part of a layout, but having implemented the following code, it doesn't function as I'd have expected: -

Code: [Select]
<CommandMethod("UTB")> _
        Public Sub UpdateTitleBlock()
            Dim db As Database = HostApplicationServices.WorkingDatabase
            Using trans As Transaction = db.TransactionManager.StartTransaction()
                Try
                    Dim bt As BlockTable = DirectCast(trans.GetObject(db.BlockTableId, OpenMode.ForRead), BlockTable)
                    Dim btr As BlockTableRecord = DirectCast(trans.GetObject(bt(BlockTableRecord.PaperSpace), OpenMode.ForRead), BlockTableRecord)
                    For Each bId As ObjectId In btr
                        Using ent As Entity = DirectCast(trans.GetObject(bId, OpenMode.ForRead, False), Entity)
                            If ent.GetRXClass().Name.ToString() = "AcDbBlockReference" Then
                                Dim br As BlockReference = DirectCast(ent, BlockReference)
                                Dim blkObj As BlockTableRecord = DirectCast(trans.GetObject(br.BlockTableRecord, OpenMode.ForRead), BlockTableRecord)
                                If blkObj.IsDynamicBlock = False Then
                                    btr = DirectCast(trans.GetObject(br.BlockTableRecord, OpenMode.ForRead), BlockTableRecord)
                                Else
                                    btr = DirectCast(trans.GetObject(br.DynamicBlockTableRecord, OpenMode.ForRead), BlockTableRecord)
                                End If
                                MsgBox(btr.Name & " : " & vbTab & blkObj.Name) ' these end up the same?
                                If (blkObj.HasAttributeDefinitions) AndAlso (btr.Name = "Drawing Border") Then
                                    Dim attcol As Autodesk.AutoCAD.DatabaseServices.AttributeCollection = br.AttributeCollection
                                    For Each attId As ObjectId In attcol
                                        Dim attRef As AttributeReference = DirectCast(trans.GetObject(attId, OpenMode.ForWrite), AttributeReference)
                                        MsgBox(attRef.Tag & " : " & vbTab & attRef.TextString)
                                    Next
                                End If
                            End If
                        End Using
                    Next
                    trans.Commit()
                Catch ex As System.Exception
                    System.Windows.Forms.MessageBox.Show(ex.ToString())
                    MessageBox.Show("Unexpected Error: " + ex.ToString())
                End Try
            End Using
        End Sub
Given what I've learnt reading Jerry's very informative book, this should be able to at least list the attributes contained within the block called drawing border, but it doesn't work. Any suggestions?

Glenn R

  • Guest
Re: Layouts, Blocks, Attributes...
« Reply #1 on: July 01, 2008, 06:17:26 AM »
What version of AutoCAD are you using?

Glenn R

  • Guest
Re: Layouts, Blocks, Attributes...
« Reply #2 on: July 01, 2008, 06:18:04 AM »
Also, what version of Visual Studio (if any) and Framework version are you targeting?

vegbruiser

  • Guest
Re: Layouts, Blocks, Attributes...
« Reply #3 on: July 01, 2008, 06:20:47 AM »
:oops: It's for AutoCAD 2006 and .NET Framework 3.5 - I'm using VB.NET 2008 (Express) (although I do have a trial (full) version of VS 2008 that I can use for debugging)

Thanks in advance.

Glenn R

  • Guest
Re: Layouts, Blocks, Attributes...
« Reply #4 on: July 01, 2008, 07:04:18 AM »
What is the EXACT spelling of the block 'drawing border'?

Also, don't open things for Write unless you are actually going to modify the object and even then, open for write for the shortest time possible.

vegbruiser

  • Guest
Re: Layouts, Blocks, Attributes...
« Reply #5 on: July 01, 2008, 07:19:08 AM »
Quote
The exact spelling is "Drawing Border"  :whistle: , that's one reason why it may not be working correctly.

Also, the open for write bit is a mistake as I only want to read the attributes and bung them into an XML "reporting" file.

I'll add a (couple of) Ucase entries to my code and see what happens.

Actually, I have just changed this: -

Code: [Select]
If blkobj.IsDynamicBlock = False then
to this: -

Code: [Select]
If br.IsDynamicBlock = False then
and it finds the correct block no problem

Cheers.

What it doesn't do however is find the same block in multiple layouts?

Glenn R

  • Guest
Re: Layouts, Blocks, Attributes...
« Reply #6 on: July 01, 2008, 07:31:31 AM »
You do understand the difference between a BlockTableRecord (Block Definition) and a BlockReference (INSERT)?

vegbruiser

  • Guest
Re: Layouts, Blocks, Attributes...
« Reply #7 on: July 01, 2008, 07:58:23 AM »
I do, yes. (at least I think I do): -

A Blocktablerecord  (Block Definition) is the block as initially defined (or subsequently updated) and the blockreference is the unique copy of that definition contained in either Modelspace or paperspace. (which then has unique attribute references)

So what you're saying is that I should be looking for Blockreferences, not blocktablerecords? I thought that's what the line: -

Code: [Select]
If ent.GetRXClass().Name.ToString() = "AcDbBlockReference" Then
was for (or have I missed the point of what you were saying entirely)?

:oops:

Glenn R

  • Guest
Re: Layouts, Blocks, Attributes...
« Reply #8 on: July 01, 2008, 08:08:59 AM »
Correct - you should be looking for BlockReferences.

The block definition is the master blueprint/look of all the BlockReferences that 'reference' the definition - hence all references will look exactly the same (excluding rotation/scale/attrib values), so they are NOT a unique copy by any means.

As far as this goes:
Code: [Select]
If ent.GetRXClass().Name.ToString() = "AcDbBlockReference" Then

you're correct, however it's in a loop over paperspace ONLY. If you want to get ALL references of your block def, then either:

A. 'Loop the layouts'. Essentailly do what you do now, except put an outer loop to loop the layouts, or
B. Look up GetBlockReferenceIds (this is the fastest way and the way I would do it)

vegbruiser

  • Guest
Re: Layouts, Blocks, Attributes...
« Reply #9 on: July 01, 2008, 09:27:26 AM »
Correct - you should be looking for BlockReferences.

The block definition is the master blueprint/look of all the BlockReferences that 'reference' the definition - hence all references will look exactly the same (excluding rotation/scale/attrib values), so they are NOT a unique copy by any means.

As far as this goes:
Code: [Select]
If ent.GetRXClass().Name.ToString() = "AcDbBlockReference" Then

you're correct, however it's in a loop over paperspace ONLY. If you want to get ALL references of your block def, then either:

A. 'Loop the layouts'. Essentailly do what you do now, except put an outer loop to loop the layouts, or
B. Look up GetBlockReferenceIds (this is the fastest way and the way I would do it)

Ok, I shall give that a try - I think there are some examples of how to use GetBlockReferenceIds in Jerry's book. Thanks for your help Glenn.

:)

Glenn R

  • Guest
Re: Layouts, Blocks, Attributes...
« Reply #10 on: July 01, 2008, 09:45:54 AM »
No probs veg. I wouldn't be following Jerry's book too closely though.

vegbruiser

  • Guest
Re: Layouts, Blocks, Attributes...
« Reply #11 on: July 02, 2008, 08:12:27 AM »
Right, I figured it was worth posting an update seeing as I've managed to cobble something together that seems to work (using Jerry's book as a guide, and some code I found here - and then converted to VB .Net): -

Code: [Select]
<CommandMethod("FindBlockInLayout")> _
        Public Sub FindBlockInLayout()
            Dim myDB As DatabaseServices.Database
            Dim myDWG As ApplicationServices.Document
            Dim myEd As EditorInput.Editor
            Dim myBlockRef As DatabaseServices.BlockReference
            Dim myTransMan As DatabaseServices.TransactionManager
            Dim myTrans As DatabaseServices.Transaction
            Dim I As Integer
            Dim J As Integer
            Dim myBT As DatabaseServices.BlockTable
            Dim myBTR As DatabaseServices.BlockTableRecord
            Dim myBTR2 As DatabaseServices.BlockTableRecord
            Dim myBTE As IEnumerator
            Dim MyBlockstoCheckIds As New DatabaseServices.ObjectIdCollection
            Dim myOtherIDs As New DatabaseServices.ObjectIdCollection
            Dim tmpObjIDs As New DatabaseServices.ObjectIdCollection
            Dim myLayoutIDs As New DatabaseServices.ObjectIdCollection
            myDWG = ApplicationServices.Application.DocumentManager.MdiActiveDocument
            myDB = myDWG.Database
            myEd = myDWG.Editor
            myTransMan = myDB.TransactionManager
            myTrans = myTransMan.StartTransaction
            myBT = DirectCast(myTrans.GetObject(myDB.BlockTableId, OpenMode.ForRead), BlockTable)
            myBTE = myBT.GetEnumerator
            While myBTE.MoveNext = True
                myBTR = DirectCast(myTrans.GetObject(myBTE.Current, OpenMode.ForRead), BlockTableRecord)
                ' Debug.Print(myBTR.Name)
                Select Case myBTR.Name.ToUpper
                    Case "DRAWING BORDER"
                        tmpObjIDs = myBTR.GetBlockReferenceIds(False, False)
                        For I = 1 To tmpObjIDs.Count
                            myBlockRef = DirectCast(myTrans.GetObject(tmpObjIDs(I - 1), OpenMode.ForRead), BlockReference)
                            MyBlockstoCheckIds.Add(myBlockRef.ObjectId)
                        Next
                    Case Else
                        If myBTR.IsAnonymous Then
                            tmpObjIDs = myBTR.GetBlockReferenceIds(False, False)
                            For I = 1 To tmpObjIDs.Count
                                myBlockRef = DirectCast(myTrans.GetObject(tmpObjIDs(I - 1), OpenMode.ForRead), BlockReference)
                                myBTR2 = DirectCast(myTrans.GetObject(myBlockRef.DynamicBlockTableRecord, OpenMode.ForRead), BlockTableRecord)
                                Select Case myBTR2.Name.ToUpper
                                    Case "DRAWING BORDER"
                                        MyBlockstoCheckIds.Add(myBlockRef.ObjectId)
                                End Select
                            Next
                        End If
                End Select
            End While
            myBT = DirectCast(myTrans.GetObject(myDB.BlockTableId, OpenMode.ForRead), BlockTable)
            myBTE = myBT.GetEnumerator
            While myBTE.MoveNext
                myBTR = DirectCast(myTrans.GetObject(myBTE.Current, OpenMode.ForRead), BlockTableRecord)
                If myBTR.IsLayout Then
                    If Not myBTR.Name.ToUpper Like "*MODEL*" Then 'should provide us with the paperspace layouts only
                        myLayoutIDs.Add(myBTR.ObjectId)
                    End If
                End If
            End While

            For I = 1 To MyBlockstoCheckIds.Count
                myBlockRef = DirectCast(myTrans.GetObject(MyBlockstoCheckIds(I - 1), OpenMode.ForRead), BlockReference)
                For J = 1 To myLayoutIDs.Count
                    Dim mylayoutBtr As BlockTableRecord = DirectCast(myTrans.GetObject(myLayoutIDs(J - 1), OpenMode.ForRead), BlockTableRecord)
                    Dim LayoutName As String = ""
                    If myBlockRef.OwnerId = mylayoutBtr.ObjectId Then
                        myBTR = DirectCast(myTrans.GetObject(myBlockRef.BlockTableRecord, OpenMode.ForRead), BlockTableRecord)
                        Dim layoutdict As DBDictionary = DirectCast(myTrans.GetObject(myDB.LayoutDictionaryId, OpenMode.ForRead), DBDictionary)
                        Dim iLayout As Int32 = 0
                        For Each id As DictionaryEntry In layoutdict
                            Dim ltr As Layout = DirectCast(myTrans.GetObject(DirectCast(id.Value, ObjectId), OpenMode.ForRead), Layout)
                            If mylayoutBtr.ObjectId = ltr.BlockTableRecordId Then
                                LayoutName = ltr.LayoutName
                                Debug.Print(ltr.LayoutName)
                            End If
                            ed.WriteMessage("" & Chr(10) & "Layout N{0} = {1}", System.Threading.Interlocked.Increment(iLayout), ltr.LayoutName)
                        Next
                        MessageBox.Show("We found a drawing border on a layout!" & vbCr & LayoutName & " Was where we found it!")
                    End If
                Next
            Next

            myTrans.Dispose()
            myTransMan.Dispose()

        End Sub

The next logical step (for each "Drawing Border" block at least) would be to iterate through it's attributereferences, and check their values against some known values (things like site number, issue date, revision etc.)

Glenn R

  • Guest
Re: Layouts, Blocks, Attributes...
« Reply #12 on: July 02, 2008, 08:23:40 AM »
Why are you using an IEnumerator? There are few places you need to do this and this isn't one of them.

If you looping the BlockTable, use a for each like so:

Code: [Select]
foreach (ObjectId btrId in bt)
{
  BlockTableRecord btr = trans.GetObject(btrId, OpenMode.ForRead, false) as BlockTableRecord;
  // ... do more mojo here
}

That's just typed in the edit post section, so don't take it as gospel.

vegbruiser

  • Guest
Re: Layouts, Blocks, Attributes...
« Reply #13 on: July 02, 2008, 09:12:12 AM »
Why are you using an IEnumerator? There are few places you need to do this and this isn't one of them.

If you looping the BlockTable, use a for each like so:

Code: [Select]
foreach (ObjectId btrId in bt)
{
  BlockTableRecord btr = trans.GetObject(btrId, OpenMode.ForRead, false) as BlockTableRecord;
  // ... do more mojo here
}

That's just typed in the edit post section, so don't take it as gospel.
Looking back at some other similar code, that was the way I had already done it, I did indeed just copy+paste the code that Jerry provided. Ah well.
« Last Edit: July 02, 2008, 09:25:15 AM by vegbruiser »

Glenn R

  • Guest
Re: Layouts, Blocks, Attributes...
« Reply #14 on: July 03, 2008, 07:20:01 AM »
An example for your indigestion :) :

Code: [Select]
[CommandMethod("BlocksInLayouts")]
static public void BlocksInLayoutsCommand()
{
Document doc = acadApp.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;

using (Transaction tr = db.TransactionManager.StartTransaction())
{
DBDictionary layoutDict = tr.GetObject(db.LayoutDictionaryId, OpenMode.ForRead, false) as DBDictionary;
if (layoutDict == null)
{
ed.WriteMessage("{0}Error: Failed to get Layout dictionary.", Environment.NewLine);
return;
}

foreach (DictionaryEntry dictEntry in layoutDict)
{
ed.WriteMessage("{0}Layout name: {1}", Environment.NewLine, dictEntry.Key);
ObjectId layoutId = (ObjectId)dictEntry.Value;

Layout layout = tr.GetObject(layoutId, OpenMode.ForRead, false) as Layout;
}

BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead, false) as BlockTable;

foreach (ObjectId btrId in bt)
{
BlockTableRecord btr = tr.GetObject(btrId, OpenMode.ForRead, false) as BlockTableRecord;

if (btr.IsLayout || btr.IsFromExternalReference || btr.IsDynamicBlock
|| btr.IsFromOverlayReference || !btr.HasAttributeDefinitions)
{

continue;
}

if (btr.Name.ToUpper() != "TESTBLOCK")
continue;

ObjectIdCollection blkRefIds = btr.GetBlockReferenceIds(true, false);
if (blkRefIds == null || blkRefIds.Count == 0)
break;

int counter = 0;
foreach (ObjectId blkRefId in blkRefIds)
{
BlockReference blkRef = tr.GetObject(blkRefId, OpenMode.ForRead, false) as BlockReference;
AttributeCollection attRefIds = blkRef.AttributeCollection;

foreach (ObjectId attRefId in attRefIds)
{
AttributeReference attRef = tr.GetObject(attRefId, OpenMode.ForRead, false) as AttributeReference;
switch (attRef.Tag)
{
case "ATTRIBUTE_A":
attRef.UpgradeOpen();
string update = string.Format("{0}. Hey there vege B!", ++counter);
attRef.TextString = update;
                                                        attRef.DowngradeOpen();
break;
default:
break;
}
}
}

break;
}

tr.Commit();
}
}

The layout stuff at the beginning doesn't need to be in there to accomplish what you were after, however I left it in there for illustrative purposes.
Have at it.

Cheers,
Glenn.
« Last Edit: July 03, 2008, 10:28:45 AM by Glenn R »

Glenn R

  • Guest
Re: Layouts, Blocks, Attributes...
« Reply #15 on: July 03, 2008, 07:22:20 AM »
After this line:

Code: [Select]
attRef.TextString = update;

you may want to add this:
Code: [Select]
attRef.DowngradeOpen();

Although the code will run just fine without it.

vegbruiser

  • Guest
Re: Layouts, Blocks, Attributes...
« Reply #16 on: July 03, 2008, 07:40:40 AM »
Cheers Glenn, that's ace. :)

I was going to ask the following, and then I re-read your code:

Quote
I notice that you open the attributereference ForRead meaning you wouldn't be able to edit the entry?

I guess that the attRef.UpgradeOpen is enough to allow editing?

Glenn R

  • Guest
Re: Layouts, Blocks, Attributes...
« Reply #17 on: July 03, 2008, 07:49:57 AM »
It does exactly what is says it does - Upgrade the Open Status of the object. So, in this case, it was open for read and by upgrading it, it goes to OpenForWrite status.

Glenn R

  • Guest
Re: Layouts, Blocks, Attributes...
« Reply #18 on: July 03, 2008, 10:20:43 AM »
Scrap what I said about adding a call to DowngradeOpen()

This will cause it to not update the attribute at all - don't know what I was on when I made that statement...

Glenn R

  • Guest
Re: Layouts, Blocks, Attributes...
« Reply #19 on: July 03, 2008, 10:27:57 AM »
Having a bad day. The call to DowngradeOpen is ok.

I found an error in my logical negation.

This:
Code: [Select]
!btr.IsDynamicBlock

should have been this:
Code: [Select]
btr.IsDynamicBlock

Sorry about that. I've fixed the original code as well.

etorola

  • Guest
Re: Layouts, Blocks, Attributes...
« Reply #20 on: October 04, 2008, 09:16:35 PM »
Hello all (first post) (Some experience with .net c# and VB, but fairly new to AutoCAD)

I am using VS 2008 and ACad 2009

I have a similar requirment to this thread and I learned a lot from this thread, Thanks for posting lots of code!

Now in my application I have to read many title blocks from many files, allow the user to edit any and all attributes and then if they do edit them, udate the attributes in the files.

You can see from the code, that I am getting all the title blocks, even though they can be in model space or in one or more paper space blocks.  So far so good.  What I want to do is save the location of the title blocks from each file later updates (I don't keep the drawings open between reading and updating), so I want to track where they were found, either in model space or paper space, and if in paper space which paper space block they were in.  I can do this using tblock.InsertSpace.  The only problem is if one of the paper spaces is the current space, I can only get "*paper_space" instead of the "*paper_space##" name that I need.  Theoretically the file could be opened between the read and update and saved with another paper space as the current space.

So does anyone know of a way to get the actual name of a paper space when it is the current space?
Also I thought I saw somewhere how to get the name on the space tab instead of the paper space name, does anyone know how to get that?

TIA

Code: [Select]
    Public Function AddDrawing(ByVal fName As String) As Integer
        ' Read all title blocks in the current drawing and add to the drawings collection
        Dim tblock As sida_TBAttributes
        Dim iCount As Integer           ' The number of drawings added to the collection

        ' mark if we found anything or not
        Dim tbFound As Boolean = False

        If fName = "" Then
            AddDrawing = 0
        Else
            ' Create a document object
            Dim doc As Document
            doc = Application.DocumentManager.MdiActiveDocument

            ' create an editor object
            Dim ed As Editor = doc.Editor

            ' create a database and try to load the selected file
            Dim db As Database = New Database(False, True)
            Using (db)
                Try
                    ' open the file for reading
                    db.ReadDwgFile(fName, FileOpenMode.OpenForReadAndAllShare, False, "")

                    ' start a transaction
                    Dim tr As Transaction = db.TransactionManager.StartTransaction()
                    Using (tr)
                        Dim bFoundTB As Boolean = False
                        Dim btr As BlockTableRecord

                        ' open the block table
                        Dim bt As BlockTable = tr.GetObject(db.BlockTableId, OpenMode.ForRead)

                        ' If a title block exists then open the blocktable record
                        If bt.Has("Titleblock_Type1") Then
                            btr = tr.GetObject(bt("Titleblock_Type1"), OpenMode.ForRead)
                            tbFound = True
                        ElseIf bt.Has("Titleblock_Type2") Then
                            btr = tr.GetObject(bt("Titleblock_Type2"), OpenMode.ForRead)
                            tbFound = True
                        ElseIf bt.Has("Titleblock_Type3") Then
                            btr = tr.GetObject(bt("Titleblock_Type3"), OpenMode.ForRead)
                            tbFound = True                           
                        End If

                        If tbFound Then                           
                            Dim objIds As ObjectIdCollection = btr.GetBlockReferenceIds(False, False)
                            Dim objId As ObjectId

                            ' Get the info on all the titleblocks in a file
                            For Each objId In objIds
                                Dim i As Integer
                                Dim ac As Integer
                                Dim blockref As BlockReference = tr.GetObject(objId, OpenMode.ForRead)

                                ' A new attribute class for the new title block
                                tblock = New sida_TBAttributes()
                                iCount = 0

                                ' Save the drawing file name
                                tblock.DWGFilePathName = fName

                                ' Save the paper/model space the title block is on
                                '**** Current paperspace only returns "*paper_space" not actual name
                                '**** like "*paper_space12"                               
                                'tblock.InsertSpace = blockref.BlockName

                                ' get the attributes
                                ac = blockref.AttributeCollection.Count

                                For i = 0 To ac - 1
                                    Dim atr As AttributeReference

                                    ' Cast the enumerated type to an attribute reference
                                    atr = CType(tr.GetObject(blockref.AttributeCollection(i), OpenMode.ForRead, False, True), AttributeReference)
                                    tblock.AddTBlockAttInfo(blockref.Name, i, atr.TextString)

                                Next

                                ' Add the TB to the collection
                                Try
                                    Me.Drawings.Add(tblock, tblock.attProject.OrderNumber + _
                                                    tblock.attSheet.Number + tblock.attRev.CurrentRevisionLevel)
                                    ' Update the count of TB's we have found
                                    iCount += 1
                                Catch
                                    ' It already exists so we don't add, but also don't need to do anything here
                                End Try

                            Next
                        End If
                    End Using
                Catch
                End Try
            End Using
        End If

        AddDrawing = iCount
    End Function

Eric

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: Layouts, Blocks, Attributes...
« Reply #21 on: October 04, 2008, 11:50:59 PM »
Welcome to TheSwamp Eric!

I’m not sure what you mean by “space tab”, bit if you mean the Layout Name you can try to retrieve this by getting the owner id of the block reference then getting it’s LayoutId

i.e..

Code: [Select]
void Commands::doit()
  {
    Editor ^pEditor = Application::DocumentManager->MdiActiveDocument->Editor;
    Database ^pDatabase = HostApplicationServices::WorkingDatabase;

    try
    {
      AcDb::TransactionManager ^pTransactionManager = pDatabase->TransactionManager;
      Transaction ^pTransaction = pTransactionManager->StartTransaction();

      try
      {
        BlockTable ^pBlockTable = dynamic_cast<BlockTable^>
          (pTransaction->GetObject(pDatabase->BlockTableId, OpenMode::ForRead));

        if (pBlockTable->Has("n"))
        {
          BlockTableRecord ^pBlockTableRecord = dynamic_cast<BlockTableRecord^>
            (pTransaction->GetObject(pBlockTable["n"], OpenMode::ForRead));

          ObjectIdCollection ^pBlockReferenceIds =
            pBlockTableRecord->GetBlockReferenceIds(false, false);

          for each (ObjectId blockReferenceId in pBlockReferenceIds)
          {
            BlockReference ^pBlockReference = dynamic_cast<BlockReference^>
              (pTransaction->GetObject(blockReferenceId, OpenMode::ForRead));

            BlockTableRecord ^pOwnerRecord = dynamic_cast<BlockTableRecord^>
              (pTransaction->GetObject (pBlockReference->OwnerId, OpenMode::ForRead));

            Layout ^pLayout = dynamic_cast<Layout^>
              (pTransaction->GetObject (pOwnerRecord->LayoutId, OpenMode::ForRead));

            pEditor->WriteMessage("\n{0}",pLayout->LayoutName);
          }
        }
      }
      finally
      {
        delete pTransaction;
      }
    }
    catch (System::Exception ^ex)
    {
      pEditor->WriteMessage(ex->Message);
    }
  }

« Last Edit: October 05, 2008, 12:27:16 AM by Daniel »

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: Layouts, Blocks, Attributes...
« Reply #22 on: October 05, 2008, 12:09:45 AM »
Also…this might be a stupid question, but have you considered using fields? E.g.
CurrentRevisionLevel && OrderNumber could point to variables in your custom summary info. Then all you need to do is update those variables in each database.

etorola

  • Guest
Re: Layouts, Blocks, Attributes...
« Reply #23 on: October 05, 2008, 01:39:45 PM »
Welcome to TheSwamp Eric!

I’m not sure what you mean by “space tab”, bit if you mean the Layout Name you can try to retrieve this by getting the owner id of the block reference then getting it’s LayoutId



Thanks, I will take a look at this next week.

The tab name is the name that is diplayed in the tabs if you set the "Dispaly Model and Layout Tabs" check box in the "Layout Elements" group of the "Display" tab of the Options dialog window.

The sample file I am working on shows the paper space name as "*paper_space12" but the displayed tab shows "108" which is what the user changed it to.

Eric

etorola

  • Guest
Re: Layouts, Blocks, Attributes...
« Reply #24 on: October 05, 2008, 01:46:59 PM »
Also…this might be a stupid question, but have you considered using fields? E.g.
CurrentRevisionLevel && OrderNumber could point to variables in your custom summary info. Then all you need to do is update those variables in each database.


This is all legacy stuff that I have to deal with.  Hundreds (perhaps thousands) of existing files.  There is no DB of anything right now, everything is done manually: printing, editing title blocks, creating transmittals, cover letters, etc.  The plan is to automate the existing process using all existing Excel data while also dumping everything into a DB, so that eventually we can switch over to only a DB.  One of the title blocks is from an AutoCad add-on that uses there on data fields for some of the title block.  There will probably always be three different title blocks.  I could change 2 of them to use fields and have considered this, but it adds another process to manage or account for.

I will check into this though and appreciate your suggestion.

Eric

It's Alive!

  • Retired
  • Needs a day job
  • Posts: 8691
  • AKA Daniel
Re: Layouts, Blocks, Attributes...
« Reply #25 on: October 05, 2008, 09:22:18 PM »
Cool, then the code ought to work for you.

Yes, do have a look at putting field variables in those attributes, they works quite well. What I meant by database was the dwg file, not an external database

pb.Perksa

  • Guest
Re: Layouts, Blocks, Attributes...
« Reply #26 on: March 31, 2009, 07:10:08 PM »
An example for your indigestion :) :

Code: [Select]
[CommandMethod("BlocksInLayouts")]
static public void BlocksInLayoutsCommand()
{
Document doc = acadApp.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;

using (Transaction tr = db.TransactionManager.StartTransaction())
{
DBDictionary layoutDict = tr.GetObject(db.LayoutDictionaryId, OpenMode.ForRead, false) as DBDictionary;
if (layoutDict == null)
{
ed.WriteMessage("{0}Error: Failed to get Layout dictionary.", Environment.NewLine);
return;
}

foreach (DictionaryEntry dictEntry in layoutDict)
{
ed.WriteMessage("{0}Layout name: {1}", Environment.NewLine, dictEntry.Key);
ObjectId layoutId = (ObjectId)dictEntry.Value;

Layout layout = tr.GetObject(layoutId, OpenMode.ForRead, false) as Layout;
}

BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead, false) as BlockTable;

foreach (ObjectId btrId in bt)
{
BlockTableRecord btr = tr.GetObject(btrId, OpenMode.ForRead, false) as BlockTableRecord;

if (btr.IsLayout || btr.IsFromExternalReference || btr.IsDynamicBlock
|| btr.IsFromOverlayReference || !btr.HasAttributeDefinitions)
{

continue;
}

if (btr.Name.ToUpper() != "TESTBLOCK")
continue;

ObjectIdCollection blkRefIds = btr.GetBlockReferenceIds(true, false);
if (blkRefIds == null || blkRefIds.Count == 0)
break;

int counter = 0;
foreach (ObjectId blkRefId in blkRefIds)
{
BlockReference blkRef = tr.GetObject(blkRefId, OpenMode.ForRead, false) as BlockReference;
AttributeCollection attRefIds = blkRef.AttributeCollection;

foreach (ObjectId attRefId in attRefIds)
{
AttributeReference attRef = tr.GetObject(attRefId, OpenMode.ForRead, false) as AttributeReference;
switch (attRef.Tag)
{
case "ATTRIBUTE_A":
attRef.UpgradeOpen();
string update = string.Format("{0}. Hey there vege B!", ++counter);
attRef.TextString = update;
                                                        attRef.DowngradeOpen();
break;
default:
break;
}
}
}

break;
}

tr.Commit();
}
}

I'm new to C, so just trying to get my head around this.  I'd know how to do this in VB, but am still getting to grips with C.  I don't understand how this works.

At this point in the code, it scrolls through all of the layouts...

Code: [Select]
DBDictionary layoutDict = tr.GetObject(db.LayoutDictionaryId, OpenMode.ForRead, false) as DBDictionary;
foreach (DictionaryEntry dictEntry in layoutDict)
{
ed.WriteMessage("{0}Layout name: {1}", Environment.NewLine, dictEntry.Key);
ObjectId layoutId = (ObjectId)dictEntry.Value;

Layout layout = tr.GetObject(layoutId, OpenMode.ForRead, false) as Layout;
}
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead, false) as BlockTable;

... but that seems to be nothing more than a loop.  How does this code tie the layouts to the blocks that exist in each of the layouts?  The code for extracting block information comes after this.  It would seem there's no relationship between the layouts an the blocks, and I've confirmed this.  This program lists the contents of blocks in layouts other than the current one.

Any ideas?

pb.Perksa

  • Guest
Re: Layouts, Blocks, Attributes...
« Reply #27 on: March 31, 2009, 09:13:12 PM »
I used a bit of Glenn R's code, and a bit of my own.  Forgive the ol' VB programmer turning it into code VB programmers would probably understand more easily, but I think this is more logical for us.

This code allows the developer to access the blocks on the current layout (whatever layout that is), and update their attributes.  It could, however, be used to find any object type on any layout, if that's what you wanted.

Code: [Select]
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// Edit the AutoCAD Drawing
//
// Place at the beginning of the module
/*
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application;
*/
// Placed earlier in the class.
/*
Document acdDOC = AcadApp.DocumentManager.MdiActiveDocument;
Database acdDB = acdDOC.Database;
Editor acdED = acdDOC.Editor;
*/
using ( Transaction acdTR = acdDB.TransactionManager.StartTransaction())
{
// get a BlockTableRecord of the current space being used in AutoCAD
        BlockTableRecord acdBTR  = (BlockTableRecord)acdTR.GetObject(acdDB.CurrentSpaceId, OpenMode.ForRead);
        // create the Layout Object
        Layout acdLayout = (Layout)acdTR.GetObject(acdBTR.LayoutId, OpenMode.ForRead);
        // write the layout name to the autocad console.
acdED.WriteMessage("{0}Layout name: {1}", Environment.NewLine, acdLayout.LayoutName);

// Get the block table record for that layout.
        BlockTableRecord acdLayoutBTR  = (BlockTableRecord)acdTR.GetObject(acdLayout.BlockTableRecordId, OpenMode.ForRead);
        if (acdLayoutBTR.IsLayout == true)
        {
        // scroll through each objectid in this layout
          foreach (ObjectId objId in acdLayoutBTR)
          {
// create an entity object from each objectid
          Entity acdENT = (Entity)acdTR.GetObject(objId,                   OpenMode.ForRead );
          System.Type objType = acdENT.GetType();
        string strEntType = objType.Name;

        // find out if this object is a BlockReference
if (strEntType == "BlockReference") {
        // create a BlockReference of that object
          BlockReference acdBR = (BlockReference)acdTR.GetObject(objId, OpenMode.ForRead);
         
          // if you want to only look for a specific block, put that if statement here.  I'm updating all attributes of a certain value in this code.
//        if (xx == yy)
// {
         
          AttributeCollection acdATTRefIds = acdBR.AttributeCollection;
foreach (ObjectId acdATTRefId in acdATTRefIds)
{
AttributeReference acdATTRef = acdTR.GetObject(acdATTRefId, OpenMode.ForRead, false) as AttributeReference;
switch (acdATTRef.Tag)
{
case "ATTRIBUTE_A":
acdATTRef.UpgradeOpen();
acdATTRef.TextString = "Blah Blah Blah";
                                                        acdATTRef.DowngradeOpen();
break;
default:
break;
}
       
}

// end the block conditional if statement here.
//             }

        }
          }
        }
acdED.WriteMessage("{0}Completed Processing Blocks", Environment.NewLine);
acdTR.Commit();
}

//
// Edit the AutoCAD Drawing
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Apologies for the formatting.  If you quote the message, the formatting actually works.  It just respaces it for this window.
« Last Edit: March 31, 2009, 09:16:35 PM by pb.Perksa »

kdub_nz

  • Mesozoic keyThumper
  • SuperMod
  • Water Moccasin
  • Posts: 2132
  • class keyThumper<T>:ILazy<T>
Re: Layouts, Blocks, Attributes...
« Reply #28 on: March 31, 2009, 10:12:01 PM »

can't make time to look at your code .. 

 ... regarding changing Glens variable names,
If you have a look around you will notice that there are some variable names like doc db ed tr tm btr ent that are used consistently by a lot of programmenrs ( here and elsewhere.
I had a giggle to see that those were the names you changed to make the code more readable.



Called Kerry in my other life
Retired; but they dragged me back in !

I live at UTC + 13.00

---
some people complain about loading the dishwasher.
Sometimes the question is more important than the answer.

Glenn R

  • Guest
Re: Layouts, Blocks, Attributes...
« Reply #29 on: April 01, 2009, 05:27:58 AM »
I concur Kerry :D

I also find the penchant for VB'ers to use string comparisons for entity types funny...use typeof or 'as' would be my recommendation.