Author Topic: Modify a variable in a block  (Read 2939 times)

0 Members and 1 Guest are viewing this topic.

latour_g

  • Newt
  • Posts: 184
Modify a variable in a block
« on: March 13, 2013, 11:41:27 AM »
Hi,

I have a function that change the height of all the attributes in a block.  The problem is sometime there is a text in a block so the height doesn't change for that.
I need to find a way to catch this text and modify his height.  I try to find it in the DynamicBlockReferencePropertyCollection but obviously it's not there.

This is what I have for the attribute :

Code: [Select]
                    if (br.AttributeCollection.Count > 0)
                    {
                        foreach (ObjectId id in br.AttributeCollection)
                        {
                            AttributeReference att = (AttributeReference)tr.GetObject(id, OpenMode.ForWrite);
                            att.WidthFactor = ratio;
                        }
                    }

n.yuan

  • Bull Frog
  • Posts: 348
Re: Modify a variable in a block
« Reply #1 on: March 13, 2013, 12:13:44 PM »
I hope you do understand the concept of block (BlockTablerecord) and block reference (BlockReference), AttributeDefinition and AttributeReference.

Yes, you can change properties of an AttributeReference in a BlockReference, because AttributeReference is not "hard" reference of AttributeDefinition in a BlockTableRecord.

However, for the other entities you see in a Blockreference, which are defined in a BlockTableRecord (text, be it DBText or MText, in your case), are "hard" reference to the block definition. They are not individual entities that you can manipulate. For the change you want to do, you have to redifine the block definition (BlockTableRecord). Then, all references (blocks user see in the drawing) would also be changed.

Well, you may define the block as dynamic block (since you mentioned dynamic property), so that you can have different text with different height stacking in the same location and set the visibility property so that only one is visible at a time. This way, you can then later "change" the text height via your code by changing visibility of the dynamic property. By using dynamic block, AutoCAD does the same thing as redifine block definition behind the scene.

So, to achieve what you want, you either redefine the block through your code, or you use a properly defined dynamic block and update its dynamic property through your code.

fixo

  • Guest
Re: Modify a variable in a block
« Reply #2 on: March 13, 2013, 02:14:13 PM »
If you realy want to change text (DBText) in the block,
in this case you need to change the contents of BlockTableRecord of block reference
so try this code (tested on A2010 only)
Code: [Select]
        // Change the text object in the BlockTableRecord by selecting them on screen
        // This method may have any name
        [CommandMethod("cato", CommandFlags.UsePickSet | CommandFlags.Redraw)]
        public static void ChangeTextInBlockDef()
        {
            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;

            Database db = doc.Database;

            Editor ed = doc.Editor;

            Transaction tr = db.TransactionManager.StartTransaction();
            using (tr)
            {
                doc.TransactionManager.EnableGraphicsFlush(true);
                PromptNestedEntityOptions pno = new PromptNestedEntityOptions("\nSelect text within block instance: ");
                pno.AllowNone = true;
                pno.UseNonInteractivePickPoint = false;
                PromptNestedEntityResult rs = ed.GetNestedEntity(pno);
                if (rs.Status != PromptStatus.OK) return;
                Entity selent = (Entity)tr.GetObject(rs.ObjectId, OpenMode.ForRead);
                ed.WriteMessage("\nSelected type of {0}", selent.GetType().Name);

                PromptStringOptions pso = new PromptStringOptions("\nEnter new text: ");
                pso.AllowSpaces = true;
                PromptResult res;
                res = ed.GetString(pso);
                if (res.Status != PromptStatus.OK) return;
                string newstr = res.StringResult;
                ed.WriteMessage("\nNew Text Entered:\t{0}", newstr);

                BlockTableRecord btrec = tr.GetObject(selent.OwnerId, OpenMode.ForWrite) as BlockTableRecord;
                // prevent work with attributes and embedded blocks
                if (selent.ObjectId.ObjectClass.IsDerivedFrom(RXClass.GetClass(typeof(AttributeReference))) |
                    selent.ObjectId.ObjectClass.IsDerivedFrom(RXClass.GetClass(typeof(BlockReference)))) return;
                if (selent.ObjectId.ObjectClass.IsDerivedFrom(RXClass.GetClass(typeof(DBText))))
                {
                    DBText txt = selent as DBText;
                    string oldstr = txt.TextString;

                    BlockTableRecord owner = (BlockTableRecord)tr.GetObject(txt.OwnerId, OpenMode.ForRead);
                    ed.WriteMessage("\nName:\t{0}", owner.Name);
                    owner.UpgradeOpen();
                    foreach (ObjectId id in owner)
                    {
                        if (!id.ObjectClass.IsDerivedFrom(RXClass.GetClass(typeof(DBText)))) continue;
                        DBObject obj = tr.GetObject(id, OpenMode.ForRead);
                        DBText blktxt = obj as DBText;
                        if (blktxt.TextString != oldstr) continue;
                        blktxt.UpgradeOpen();
                        blktxt.TextString = newstr;

                    }

                    //--------------------------------------------------------------
                    // add other possible types such as mtext, dimension etc here
                    //--------------------------------------------------------------


                    tr.TransactionManager.QueueForGraphicsFlush();

                    doc.TransactionManager.FlushGraphics();

                    tr.Commit();

                    ed.Regen();
                }
            }
        }

nobody

  • Swamp Rat
  • Posts: 861
  • .net stuff
Re: Modify a variable in a block
« Reply #3 on: March 13, 2013, 10:42:56 PM »
You're the man fixo!

If you realy want to change text (DBText) in the block,
in this case you need to change the contents of BlockTableRecord of block reference
so try this code (tested on A2010 only)
Code: [Select]
        // Change the text object in the BlockTableRecord by selecting them on screen
        // This method may have any name
        [CommandMethod("cato", CommandFlags.UsePickSet | CommandFlags.Redraw)]
        public static void ChangeTextInBlockDef()
        {
            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;

            Database db = doc.Database;

            Editor ed = doc.Editor;

            Transaction tr = db.TransactionManager.StartTransaction();
            using (tr)
            {
                doc.TransactionManager.EnableGraphicsFlush(true);
                PromptNestedEntityOptions pno = new PromptNestedEntityOptions("\nSelect text within block instance: ");
                pno.AllowNone = true;
                pno.UseNonInteractivePickPoint = false;
                PromptNestedEntityResult rs = ed.GetNestedEntity(pno);
                if (rs.Status != PromptStatus.OK) return;
                Entity selent = (Entity)tr.GetObject(rs.ObjectId, OpenMode.ForRead);
                ed.WriteMessage("\nSelected type of {0}", selent.GetType().Name);

                PromptStringOptions pso = new PromptStringOptions("\nEnter new text: ");
                pso.AllowSpaces = true;
                PromptResult res;
                res = ed.GetString(pso);
                if (res.Status != PromptStatus.OK) return;
                string newstr = res.StringResult;
                ed.WriteMessage("\nNew Text Entered:\t{0}", newstr);

                BlockTableRecord btrec = tr.GetObject(selent.OwnerId, OpenMode.ForWrite) as BlockTableRecord;
                // prevent work with attributes and embedded blocks
                if (selent.ObjectId.ObjectClass.IsDerivedFrom(RXClass.GetClass(typeof(AttributeReference))) |
                    selent.ObjectId.ObjectClass.IsDerivedFrom(RXClass.GetClass(typeof(BlockReference)))) return;
                if (selent.ObjectId.ObjectClass.IsDerivedFrom(RXClass.GetClass(typeof(DBText))))
                {
                    DBText txt = selent as DBText;
                    string oldstr = txt.TextString;

                    BlockTableRecord owner = (BlockTableRecord)tr.GetObject(txt.OwnerId, OpenMode.ForRead);
                    ed.WriteMessage("\nName:\t{0}", owner.Name);
                    owner.UpgradeOpen();
                    foreach (ObjectId id in owner)
                    {
                        if (!id.ObjectClass.IsDerivedFrom(RXClass.GetClass(typeof(DBText)))) continue;
                        DBObject obj = tr.GetObject(id, OpenMode.ForRead);
                        DBText blktxt = obj as DBText;
                        if (blktxt.TextString != oldstr) continue;
                        blktxt.UpgradeOpen();
                        blktxt.TextString = newstr;

                    }

                    //--------------------------------------------------------------
                    // add other possible types such as mtext, dimension etc here
                    //--------------------------------------------------------------


                    tr.TransactionManager.QueueForGraphicsFlush();

                    doc.TransactionManager.FlushGraphics();

                    tr.Commit();

                    ed.Regen();
                }
            }
        }

WILL HATCH

  • Bull Frog
  • Posts: 450
Re: Modify a variable in a block
« Reply #4 on: March 13, 2013, 11:31:17 PM »
If you realy want to change text (DBText) in the block,
in this case you need to change the contents of BlockTableRecord of block reference
so try this code (tested on A2010 only)
Code: [Select]
        // Change the text object in the BlockTableRecord by selecting them on screen
        // This method may have any name
        [CommandMethod("cato", CommandFlags.UsePickSet | CommandFlags.Redraw)]
        public static void ChangeTextInBlockDef()
        {
            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;

            Database db = doc.Database;

            Editor ed = doc.Editor;

            Transaction tr = db.TransactionManager.StartTransaction();
            using (tr)
            {
                doc.TransactionManager.EnableGraphicsFlush(true);
                PromptNestedEntityOptions pno = new PromptNestedEntityOptions("\nSelect text within block instance: ");
                pno.AllowNone = true;
                pno.UseNonInteractivePickPoint = false;
                PromptNestedEntityResult rs = ed.GetNestedEntity(pno);
                if (rs.Status != PromptStatus.OK) return;
                Entity selent = (Entity)tr.GetObject(rs.ObjectId, OpenMode.ForRead);
                ed.WriteMessage("\nSelected type of {0}", selent.GetType().Name);

                PromptStringOptions pso = new PromptStringOptions("\nEnter new text: ");
                pso.AllowSpaces = true;
                PromptResult res;
                res = ed.GetString(pso);
                if (res.Status != PromptStatus.OK) return;
                string newstr = res.StringResult;
                ed.WriteMessage("\nNew Text Entered:\t{0}", newstr);

                BlockTableRecord btrec = tr.GetObject(selent.OwnerId, OpenMode.ForWrite) as BlockTableRecord;
                // prevent work with attributes and embedded blocks
                if (selent.ObjectId.ObjectClass.IsDerivedFrom(RXClass.GetClass(typeof(AttributeReference))) |
                    selent.ObjectId.ObjectClass.IsDerivedFrom(RXClass.GetClass(typeof(BlockReference)))) return;
                if (selent.ObjectId.ObjectClass.IsDerivedFrom(RXClass.GetClass(typeof(DBText))))
                {
                    DBText txt = selent as DBText;
                    string oldstr = txt.TextString;

                    BlockTableRecord owner = (BlockTableRecord)tr.GetObject(txt.OwnerId, OpenMode.ForRead);
                    ed.WriteMessage("\nName:\t{0}", owner.Name);
                    owner.UpgradeOpen();
                    foreach (ObjectId id in owner)
                    {
                        if (!id.ObjectClass.IsDerivedFrom(RXClass.GetClass(typeof(DBText)))) continue;
                        DBObject obj = tr.GetObject(id, OpenMode.ForRead);
                        DBText blktxt = obj as DBText;
                        if (blktxt.TextString != oldstr) continue;
                        blktxt.UpgradeOpen();
                        blktxt.TextString = newstr;

                    }

                    //--------------------------------------------------------------
                    // add other possible types such as mtext, dimension etc here
                    //--------------------------------------------------------------


                    tr.TransactionManager.QueueForGraphicsFlush();

                    doc.TransactionManager.FlushGraphics();

                    tr.Commit();

                    ed.Regen();
                }
            }
        }

I'm curious why the choice to use both the UsePickSet and Redraw flags.  It is my understanding that the function of the Redraw flag encompasses that of the UsePickSet flag and extends it. More info here


Quote from: docs
When the pickfirst set or grip set are retrieved, they are not cleared within AutoCAD.
Command can retrieve the pickfirst set and the grip set by using the ads_ssgetfirst function.
Command can retrieve the pickfirst set via ads_ssget("I.").
Command can set both the pickfirst and grip sets using the ads_sssetfirst function. Objects in these sets are redrawn with the proper grip handles and highlighting upon completion of the command.

Also, curious if there's a reason for the use of graphics flush and regen when if we had used doc.TransactionManager instead of db.TransactionManager to start the transaction the regen would have been implied (thanks to TT for that bit of info!).

TheMaster

  • Guest
Re: Modify a variable in a block
« Reply #5 on: March 14, 2013, 02:33:24 AM »
Hi,

I have a function that change the height of all the attributes in a block.  The problem is sometime there is a text in a block so the height doesn't change for that.
I need to find a way to catch this text and modify his height.  I try to find it in the DynamicBlockReferencePropertyCollection but obviously it's not there.

This is what I have for the attribute :

Code: [Select]
                    if (br.AttributeCollection.Count > 0)
                    {
                        foreach (ObjectId id in br.AttributeCollection)
                        {
                            AttributeReference att = (AttributeReference)tr.GetObject(id, OpenMode.ForWrite);
                            att.WidthFactor = ratio;
                        }
                    }


Perhaps Fixo didn't understand your question, which as I see it, is that you want to change the height of text to different values in each insertion of a block.

There is no way to do that. There is only one text object in a definition of a block, and that is what is drawn for each insertion. You can replace the text in the block with an attribute, and that would allow you to change the height on each insertion independently.

latour_g

  • Newt
  • Posts: 184
Re: Modify a variable in a block
« Reply #6 on: March 14, 2013, 01:41:24 PM »
Thank you all for your answer.

TT : Well the user choose the height, select blocks and everything (text and attribute) in those blocks has to change for the new height (only those selected blocks, not those who will be insert after).     
n.yuan : Thanks for your explanation.  Using visibility would have been a great option but since the height is the user choice I can't use this solution.

n.yuan

  • Bull Frog
  • Posts: 348
Re: Modify a variable in a block
« Reply #7 on: March 14, 2013, 03:48:24 PM »
 
n.yuan : Thanks for your explanation.  Using visibility would have been a great option but since the height is the user choice I can't use this solution.

Then you have to use TT's suggestion: define the block so that all text values are represended by Attribute. This way, you can let user to pick a instance of the block reference and change the Attribute's height without having to change the block definition, thus the block references to the same block definition inserted later (or earlier) will not be affected.