Sunday, January 22, 2012

C#.Net: Use KeyWords To Provide Choices For Users

Let's add some keyword options to our circle MText program. The current version allows the user to enter a string to search for and then places a red circle around all matching MText entities in the drawing. To practice with the GetKeywords method we will let the user choose a different color for the circle from a list of choices.
Here is the C# code, note extended comments from previous versions have been removed.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;

namespace SLD_Demo
{
    public class MTextTools
    {
        [CommandMethod("SLDcirText")]
        public void SLDcirText()
        {
            //get current document
            Document acDoc =
                Application.DocumentManager.MdiActiveDocument;

            //get AutoCAD database
            Database acCurDb = acDoc.Database;

            //get string to search for
            String sldStrToSrch = SLDgetStringFromUser(acDoc);

            //get color of circle
            int sldCirColor = SLDgetColorFromUser(acDoc);

            //start db transaction
            using (Transaction acTrans =
                acCurDb.TransactionManager.StartTransaction())
            {
                //open block table
                BlockTable bt = (BlockTable)acTrans.GetObject
                    (acCurDb.BlockTableId, OpenMode.ForRead);

                BlockTableRecord btr = (BlockTableRecord)
                    acTrans.GetObject(bt[BlockTableRecord.ModelSpace],
                    OpenMode.ForRead);

                //iterate through block table to locate mtext objects
                foreach (ObjectId id in btr)
                {
                    //open each object to read
                    DBObject obj = acTrans.GetObject
                        (id, OpenMode.ForRead);

                    //only deal with MText objects
                    MText dbMText = obj as MText;

                    //if current object is Mtext
                    if (dbMText != null)
                    {
                        String curTxtValue = dbMText.Contents;
                        //and if the contents include the string entered
                        //by user 
                        if (string.Equals(sldStrToSrch, curTxtValue,
                            StringComparison.CurrentCultureIgnoreCase))
                        {
                            //draw a circle around the mtext entity
                            /*add an additional parameter from the last
                              version to pass the color index*/
                            SLDdrawCir(acCurDb, acTrans,
                                dbMText, sldCirColor);

                        }
                    }
                }
                //commit the transaction so we do not leave the db open
                acTrans.Commit();
            }
        }

        //function to get text string from user
        public String SLDgetStringFromUser(Document acDoc)
        {
            PromptStringOptions pStrOpts = new PromptStringOptions(
                "\nFind What: ");

            //control the prompt string options to behave like we want
            //such as allow spaces to be entered
            pStrOpts.AllowSpaces = true;

            //retrieve the string entered by user
            PromptResult pStrRes = acDoc.Editor.GetString(pStrOpts);

            //and assign to a new string variable
            String sldStr = pStrRes.StringResult;

            //return the string variable to calling function
            return sldStr;
        }

        /*function to get desired color from user. Gets preferred
          color entered as string, converts to int, and returns*/
        public int SLDgetColorFromUser(Document acDoc)
        {
            /*The GetKeywords method allows a selection to be presented
              to the user and requires a matching value to be entered.
              Error handling is already built in, if an invalid option
              is entered a message is displayed and the user is prompted
              again. Also, a matching value can be the first letter (not
              case sensitive) or some or all of a keyword. A default
              value can also be defined. The Message value is important
              too, this is the main message displayed along with the list
              of keywords.*/
            PromptKeywordOptions pKeyOpts = new PromptKeywordOptions("");
            pKeyOpts.Message = "\nSelect color of circle ";
            pKeyOpts.Keywords.Add("Red");
            pKeyOpts.Keywords.Add("Green");
            pKeyOpts.Keywords.Add("Yellow");
            pKeyOpts.Keywords.Add("Blue");
            pKeyOpts.Keywords.Default = "Red";

            //call GetKeywords and pass in our options
            PromptResult pKeyRes = acDoc.Editor.GetKeywords(pKeyOpts);

            //create int value to store color index (default to red)
            int sldCirColor = 1;

            /*switch statement to convert the color string
              to a color index value*/
            switch (pKeyRes.StringResult)
            {
                case "Green":
                    sldCirColor = 3;
                    break;
                case "Yellow":
                    sldCirColor = 2;
                    break;
                case "Blue":
                    sldCirColor = 5;
                    break;
            }

            return sldCirColor;
        }

        //function to draw circle around an MText object
        public void SLDdrawCir(Database acCurDb,
            Transaction acTrans, MText MtextObj,
            int cirColor)
        {
            //define a new point object for the center point of circle
            Point3d cenPoint = new Point3d();

            //use the location method of the Mtext object to define
            //the center point coordinates
            cenPoint = MtextObj.Location;

            //define a new Circle object
            Circle textCir = new Circle();
            textCir.Center = cenPoint;
            textCir.Diameter = 1.0;
            //assign color index the value entered by user
            textCir.ColorIndex = cirColor;

            //now add the circle to the drawing (model space)
            BlockTable acBlkTbl;
            acBlkTbl = acTrans.GetObject(
                acCurDb.BlockTableId, OpenMode.ForRead) as BlockTable;

            BlockTableRecord acBlkTblRec;
            acBlkTblRec = acTrans.GetObject(
                acBlkTbl[BlockTableRecord.ModelSpace],
                OpenMode.ForWrite)
                as BlockTableRecord;

            acBlkTblRec.AppendEntity(textCir);
            acTrans.AddNewlyCreatedDBObject(textCir, true);
        }
    }
}

To test, NETLOAD the .dll into AutoCAD and place some MText entities. Try entering an invalid keyword. Also, test out entering just the first letter of a keyword, the first few letters, or the entire string. It all works!

Thursday, December 29, 2011

C#.Net: Circle MText Objects Matching String Entered By User

In my last post we created a C#.Net program to place a red circle around all MText entities in a drawing. Let's add some code to allow the user to enter a specific string value to place circles around. The descriptive inline comments that were in the first program are not duplicated here for clarity.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;

namespace SLD_Demo
{
    public class MTextTools
    {
        [CommandMethod("SLDcirText")]
        public void SLDcirText()
        {
            //get current document
            Document acDoc =
                Application.DocumentManager.MdiActiveDocument;

            //get AutoCAD database
            Database acCurDb = acDoc.Database;

            //get string to search for
            String sldStrToSrch = SLDgetStringFromUser(acDoc);

            //start db transaction
            using (Transaction acTrans =
                acCurDb.TransactionManager.StartTransaction())
            {
                //open block table
                BlockTable bt = (BlockTable)acTrans.GetObject
                    (acCurDb.BlockTableId, OpenMode.ForRead);

                BlockTableRecord btr = (BlockTableRecord)
                    acTrans.GetObject(bt[BlockTableRecord.ModelSpace],
                    OpenMode.ForRead);

                //iterate through block table to locate mtext objects
                foreach (ObjectId id in btr)
                {
                    //open each object to read
                    DBObject obj = acTrans.GetObject
                        (id, OpenMode.ForRead);

                    //only deal with MText objects
                    MText dbMText = obj as MText;

                    //if current object is Mtext
                    if (dbMText != null)
                    {
                        //assign value of current MText object to a new
                        //String variable
                        String curTxtValue = dbMText.Contents;
                        //now compare to the string entered by user
                        /*I am using the Equals method and overriding to
                         not be case sensitive. This method is returning
                         a boolean value and we are looking for true.
                         There are several string comparison methods.
                         The Contains method would return true if the
                         string entered by user is a part of any Mtext
                         entities. The code for this is:
                           if (curTxtValue.Contains(sldStrToSrch))
                        */

                        if (string.Equals(sldStrToSrch, curTxtValue,
                            StringComparison.CurrentCultureIgnoreCase))
                        {
                            //draw a circle around the mtext entity
                            SLDdrawCir(acCurDb, acTrans, dbMText);
                        }
                    }
                }
                //commit the transaction so we do not leave the db open
                acTrans.Commit();
            }
        }

        //function to get text string from user
        public String SLDgetStringFromUser(Document acDoc)
        {
            PromptStringOptions pStrOpts = new PromptStringOptions(
                "\nFind What: ");

            //control the prompt string options to behave like we want
            //such as allow spaces to be entered
            pStrOpts.AllowSpaces = true;

            //retrieve the string entered by user
            PromptResult pStrRes = acDoc.Editor.GetString(pStrOpts);

            //and assign to a new string variable
            String sldStr = pStrRes.StringResult;

            //return the string variable to calling function
            return sldStr;
        }

        //function to draw circle around an MText object
        public void SLDdrawCir(Database acCurDb,
            Transaction acTrans, MText MtextObj)
        {
            //define a new point object for the center point of circle
            Point3d cenPoint = new Point3d();

            //use the location method of the Mtext object to define
            //the center point coordinates
            cenPoint = MtextObj.Location;

            //define a new Circle object
            /*we use the center point defined above, assign a diameter
             and assign a color using the ColorIndex method from the
             circle object*/
            Circle textCir = new Circle();
            textCir.Center = cenPoint;
            textCir.Diameter = 1.0;
            textCir.ColorIndex = 1;

            //now add the circle to the drawing (model space)
            /*We need to add it to the block table, this is the same
             basic operations when adding geometry to a drawing*/
            BlockTable acBlkTbl;
            acBlkTbl = acTrans.GetObject(
                acCurDb.BlockTableId, OpenMode.ForRead) as BlockTable;

            BlockTableRecord acBlkTblRec;
            acBlkTblRec = acTrans.GetObject(
                acBlkTbl[BlockTableRecord.ModelSpace],
                OpenMode.ForWrite)
                as BlockTableRecord;

            acBlkTblRec.AppendEntity(textCir);
            acTrans.AddNewlyCreatedDBObject(textCir, true);
        }
    }
}

To test this build the solution and NETLOAD the .dll into AutoCAD. Place some MText objects in the drawing and then type in SLDcirText at the command line. You will be prompted to enter a string to search for. Enter a string and regardless of case the matching strings should be circled.