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

0 Members and 1 Guest are viewing this topic.

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.