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!