Author Topic: How to repeat a command until the user presses escape.  (Read 3130 times)

0 Members and 1 Guest are viewing this topic.

Keith Brown

  • Swamp Rat
  • Posts: 601
How to repeat a command until the user presses escape.
« on: February 13, 2013, 09:35:46 PM »
Building upon my post about the DatabaseSummaryInfoBuilder I have created the code to create a command line version of the dwgprops command.  My question is how would you loop a command so that the command repeats the keywords until the user hits escape?  I chose to use a goto/label combination.  Is this a bad programming practice?  In addition, should the document be locked or the commands placed in a transaction?  I am still very fuzzy on when to do each.  Thanks for the help!

Code - C#: [Select]
  1.    [CommandMethod("DWGProperties")]
  2.     public void CommandDwgProperties()
  3.     {
  4.         Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
  5.  
  6.         string commandText = "Select a property to change: [Title/Author/Comments/Subject/Hyperlink/Revision]";
  7.         string commandKeywords = "Title Author Comments Subject Hyperlink Revision";
  8.  
  9.         Start:
  10.         PromptKeywordOptions getDWGPropertiesOptions = new PromptKeywordOptions(commandText, commandKeywords);
  11.         PromptResult getDWGPropertiesResult = ed.GetKeywords(getDWGPropertiesOptions);
  12.         if (getDWGPropertiesResult.Status == PromptStatus.OK)
  13.         {
  14.             switch(getDWGPropertiesResult.StringResult)
  15.             {
  16.                 case "Title":
  17.                     CommandDwgTitle();
  18.                     goto Start;
  19.                 case "Author":
  20.                     CommandDwgAuthor();
  21.                     goto Start;
  22.                 case "Comments":
  23.                     CommandDwgComments();
  24.                     goto Start;
  25.                 case "Subject":
  26.                     CommandDwgSubject();
  27.                     goto Start;
  28.                 case "Hyperlink":
  29.                     CommandDwgHyperlink();
  30.                     goto Start;
  31.                 case "Revision":
  32.                     CommandDwgRevision();
  33.                     goto Start;
  34.             }
  35.         }
  36.         else { return; }
  37.     }
  38.  
  39.     [CommandMethod("DwgTitle")]
  40.     public void CommandDwgTitle()
  41.     {
  42.         Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
  43.         Document doc = Application.DocumentManager.MdiActiveDocument;
  44.         Database db = doc.Database;
  45.  
  46.         DatabaseSummaryInfo Original = db.SummaryInfo;
  47.         DatabaseSummaryInfoBuilder infobuilder = new DatabaseSummaryInfoBuilder(Original);
  48.  
  49.         PromptStringOptions title = new PromptStringOptions(String.Format("Enter a new value for TITLE <{0}>: ", db.SummaryInfo.Title));
  50.         PromptResult getTitle = ed.GetString(title);
  51.         infobuilder.Title = getTitle.StringResult;
  52.  
  53.         DatabaseSummaryInfo info = infobuilder.ToDatabaseSummaryInfo();
  54.         db.SummaryInfo = info;
  55.  
  56.     }
  57.  
  58.     [CommandMethod("DwgAuthor")]
  59.     public void CommandDwgAuthor()
  60.     {
  61.         Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
  62.         Document doc = Application.DocumentManager.MdiActiveDocument;
  63.         Database db = doc.Database;
  64.  
  65.         DatabaseSummaryInfo original = db.SummaryInfo;
  66.         DatabaseSummaryInfoBuilder infobuilder = new DatabaseSummaryInfoBuilder(original);
  67.  
  68.         PromptStringOptions author = new PromptStringOptions(String.Format("Enter a new value for AUTHOR <{0}>: ", db.SummaryInfo.Author));
  69.         PromptResult getAuthor = ed.GetString(author);
  70.         infobuilder.Title = getAuthor.StringResult;
  71.  
  72.         DatabaseSummaryInfo info = infobuilder.ToDatabaseSummaryInfo();
  73.         db.SummaryInfo = info;
  74.  
  75.     }
  76.  
  77.     [CommandMethod("DwgComments")]
  78.     public void CommandDwgComments()
  79.     {
  80.         Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
  81.         Document doc = Application.DocumentManager.MdiActiveDocument;
  82.         Database db = doc.Database;
  83.  
  84.         DatabaseSummaryInfo original = db.SummaryInfo;
  85.         DatabaseSummaryInfoBuilder infobuilder = new DatabaseSummaryInfoBuilder(original);
  86.  
  87.         PromptStringOptions comments = new PromptStringOptions(String.Format("Enter a new value for COMMENTS <{0}>: ", db.SummaryInfo.Comments));
  88.         PromptResult getAuthor = ed.GetString(comments);
  89.         infobuilder.Comments = getAuthor.StringResult;
  90.  
  91.         DatabaseSummaryInfo info = infobuilder.ToDatabaseSummaryInfo();
  92.         db.SummaryInfo = info;
  93.  
  94.     }
  95.  
  96.     [CommandMethod("DwgSubject")]
  97.     public void CommandDwgSubject()
  98.     {
  99.         Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
  100.         Document doc = Application.DocumentManager.MdiActiveDocument;
  101.         Database db = doc.Database;
  102.  
  103.         DatabaseSummaryInfo original = db.SummaryInfo;
  104.         DatabaseSummaryInfoBuilder infobuilder = new DatabaseSummaryInfoBuilder(original);
  105.  
  106.         PromptStringOptions subject = new PromptStringOptions(String.Format("Enter a new value for SUBJECT <{0}>: ", db.SummaryInfo.Subject));
  107.         PromptResult getSubject = ed.GetString(subject);
  108.         infobuilder.Subject = getSubject.StringResult;
  109.  
  110.         DatabaseSummaryInfo info = infobuilder.ToDatabaseSummaryInfo();
  111.         db.SummaryInfo = info;
  112.  
  113.     }
  114.  
  115.     [CommandMethod("DwgHyperlink")]
  116.     public void CommandDwgHyperlink()
  117.     {
  118.         Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
  119.         Document doc = Application.DocumentManager.MdiActiveDocument;
  120.         Database db = doc.Database;
  121.  
  122.         DatabaseSummaryInfo original = db.SummaryInfo;
  123.         DatabaseSummaryInfoBuilder infobuilder = new DatabaseSummaryInfoBuilder(original);
  124.  
  125.         PromptStringOptions hyperlink = new PromptStringOptions(String.Format("Enter a new value for HYPERLINK <{0}>: ", db.SummaryInfo.HyperlinkBase));
  126.         PromptResult getHyperlink = ed.GetString(hyperlink);
  127.         infobuilder.HyperlinkBase = getHyperlink.StringResult;
  128.  
  129.         DatabaseSummaryInfo info = infobuilder.ToDatabaseSummaryInfo();
  130.         db.SummaryInfo = info;
  131.     }
  132.  
  133.     [CommandMethod("DwgRevision")]
  134.     public void CommandDwgRevision()
  135.     {
  136.         Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
  137.         Document doc = Application.DocumentManager.MdiActiveDocument;
  138.         Database db = doc.Database;
  139.  
  140.         DatabaseSummaryInfo original = db.SummaryInfo;
  141.         DatabaseSummaryInfoBuilder infobuilder = new DatabaseSummaryInfoBuilder(original);
  142.  
  143.         PromptStringOptions revision = new PromptStringOptions(String.Format("Enter a new value for REVISION <{0}>: ", db.SummaryInfo.RevisionNumber));
  144.         PromptResult getRevision = ed.GetString(revision);
  145.         infobuilder.RevisionNumber = getRevision.StringResult;
  146.  
  147.         DatabaseSummaryInfo info = infobuilder.ToDatabaseSummaryInfo();
  148.         db.SummaryInfo = info;
  149.  
  150.     }
Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

TheMaster

  • Guest
Re: How to repeat a command until the user presses escape.
« Reply #1 on: February 13, 2013, 10:21:40 PM »
Have a look at the code in this post:

http://www.theswamp.org/index.php?topic=43542.msg488087#msg488087

It shows an example of a command that repeatedly prompts for a point and exits when the user pressed ENTER or ESC.

In your case, you would only exit on ESCape, which isn't very different in how it would be done. Essentially you go into an infinite loop (e.g., while (true ){...}), and break when the Status is not PromptStatus.Keyword or PromptStatus.OK.

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: How to repeat a command until the user presses escape.
« Reply #2 on: February 13, 2013, 10:49:04 PM »
... how would you loop a command so that the command repeats the keywords until the user hits escape? ...

a while loop or a do while loop (see Tony's code he linked to)

Test for PromptStatus to break out of loop

I chose to use a goto/label combination.  Is this a bad programming practice?

It depends on who you ask. I don't particularly care if you use them or not .. as a rule I don't. YMMV

In addition, should the document be locked or the commands placed in a transaction?  I am still very fuzzy on when to do each.  Thanks for the help!

I'd say yes and yes in the functions that change the properties ... make sure to dispose the DocumentLock

Maybe Tony can explain when and why a transaction is needed

a DocumentLock is needed whenever you modify the database, so if you are modifying, lock it.
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: How to repeat a command until the user presses escape.
« Reply #3 on: February 14, 2013, 03:23:22 AM »
< .. >a DocumentLock is needed whenever you modify the database, so if you are modifying, lock it.

Not quite correct. 'It depends' on the command mode is the answer.
Is the form Modeless ?
are you using a Session command flag ?
You may need to lock the document.
http://docs.autodesk.com/ACD/2010/ENU/AutoCAD%20.NET%20Developer's%20Guide/files/WS1a9193826455f5ff-e569a0121d1945c0831d.htm
http://adndevblog.typepad.com/autocad/2012/05/when-to-lock-the-document.html
and there are several discussions here I'm sure.

Regarding transactions.
Short story : Use them for all database interaction until you can explain to someone why you won't for specific instances.
Use of the using keyword, which automatically calls Dispose() on the transaction object when it goes out of scope.

kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Keith Brown

  • Swamp Rat
  • Posts: 601
Re: How to repeat a command until the user presses escape.
« Reply #4 on: February 14, 2013, 07:46:24 AM »
Thanks for all of the advice.

I decided not to lock the document based on the links provided by Kerry.  I am not using the session command flag or accessing a document other than the current document.

Looking at the link provided by Tony I added the following line to allow the user to cancel the command with the RETURN key along with the ESC key.

Code - C#: [Select]
  1.       getDWGPropertiesOptions.AllowNone = true;

I decided not to implement an UNDO function at this time for main command.  The primary use will come from the  subcommands being called individually and more specifically the DwgRevision command.  It was created mainly to change the revision of the dwg on duct, pipe, and mvpart drawings for AutoCAD MEP and to be used in tandem with JTBWorlds addin to see the drawing properties in the explorer window. The main command with keywords to call the individual commands was created only as a learning exercise and was not the main intent of the design.

Transactions were added to each of the subcommands along with try/catch blocks to catch any errors that might occur.  The code is quite small and I don't foresee any errors but you never know.

Here is a snippet of the code that was added to the main command and one of the subcommands.

Code - C#: [Select]
  1.     [CommandMethod("DwgProperties")]
  2.     public void CommandDwgProperties()
  3.     {
  4.         Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
  5.  
  6.         string commandText = "Select a property to change: [Title/Author/Comments/Subject/Hyperlink/Revision]";
  7.         string commandKeywords = "Title Author Comments Subject Hyperlink Revision";
  8.  
  9.         Start:
  10.         PromptKeywordOptions getDWGPropertiesOptions = new PromptKeywordOptions(commandText, commandKeywords);
  11.         getDWGPropertiesOptions.AllowNone = true;
  12.         PromptResult getDWGPropertiesResult = ed.GetKeywords(getDWGPropertiesOptions);
  13.         if (getDWGPropertiesResult.Status == PromptStatus.OK)
  14.         {
  15.             switch(getDWGPropertiesResult.StringResult)
  16.             {
  17.                 case "Title":
  18.                     CommandDwgTitle();
  19.                     goto Start;
  20.                 case "Author":
  21.                     CommandDwgAuthor();
  22.                     goto Start;
  23.                 case "Comments":
  24.                     CommandDwgComments();
  25.                     goto Start;
  26.                 case "Subject":
  27.                     CommandDwgSubject();
  28.                     goto Start;
  29.                 case "Hyperlink":
  30.                     CommandDwgHyperlink();
  31.                     goto Start;
  32.                 case "Revision":
  33.                     CommandDwgRevision();
  34.                     goto Start;
  35.             }
  36.         }
  37.         else { return; }
  38.     }
  39.  
  40.     [CommandMethod("DwgTitle")]
  41.     public void CommandDwgTitle()
  42.     {
  43.         Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
  44.         Document doc = Application.DocumentManager.MdiActiveDocument;
  45.         Database db = doc.Database;
  46.  
  47.         DatabaseSummaryInfo original = db.SummaryInfo;
  48.         DatabaseSummaryInfoBuilder infobuilder = new DatabaseSummaryInfoBuilder(original);
  49.  
  50.         using (Transaction tm = db.TransactionManager.StartTransaction())
  51.         {
  52.             try
  53.             {
  54.                 PromptStringOptions title = new PromptStringOptions(String.Format("Enter a new value for TITLE <{0}>: ", db.SummaryInfo.Title));
  55.                 PromptResult getTitle = ed.GetString(title);
  56.                 infobuilder.Title = getTitle.StringResult;
  57.  
  58.                 DatabaseSummaryInfo info = infobuilder.ToDatabaseSummaryInfo();
  59.                 db.SummaryInfo = info;
  60.             }
  61.             catch (Autodesk.AutoCAD.Runtime.Exception autocadEx)
  62.             {
  63.                 ed.WriteMessage(string.Format(String.Format("{0}An AutoCAD exception has occured: {1}{0}", Environment.NewLine, autocadEx.Message)));
  64.                 return;
  65.             }
  66.             catch (System.Exception ex)
  67.             {
  68.                 ed.WriteMessage(string.Format(String.Format("{0}A System exception has occured: {1}{0}", Environment.NewLine, ex.Message)));
  69.                 return;
  70.             }
  71.             tm.Commit();
  72.         }
  73.     }

Thanks again for the help.  I actually did learn a lot from this exercise.

Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

Keith Brown

  • Swamp Rat
  • Posts: 601
Re: How to repeat a command until the user presses escape.
« Reply #5 on: February 14, 2013, 07:59:36 AM »
One last observation about the above code.  I kept the goto/label because when I changed the If statement to a while loop instead of repeating the main prompt it was repeating the individual prompts inside of the subcommands.  I assumed it was because autocad was remembering the last prompt used when checking for promptstatus.ok.  Instead of trying to figure it out, i just used the goto/label statement instead.  For 20 years of my life I was an electrician/mechanic so I figure if I have a tool in my toolbox I might as well use it.
Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: How to repeat a command until the user presses escape.
« Reply #6 on: February 14, 2013, 09:25:42 AM »
Kerry, thanks for clearing that up ... I generally use session flags for my code and didn't even think about it.

I would have made the while loop start where you have your start label and end before the else in the if, eliminating the else. The default on the switch could simply be break allowing the function to end.

But .. whatever works for you is ok ... like I said, as a rule I don't use them, although somewhere in my vast trove of code there is the occasional goto/label combination.
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

Keith Brown

  • Swamp Rat
  • Posts: 601
Re: How to repeat a command until the user presses escape.
« Reply #7 on: February 14, 2013, 09:48:09 AM »
I would have made the while loop start where you have your start label and end before the else in the if, eliminating the else. The default on the switch could simply be break allowing the function to end.

Thanks Keith.  I followed your recommendations, but kept the else statement to exit out of the loop if the RET or the ESC key had been pressed.
Keith Brown | AutoCAD MEP Blog | RSS Feed
AutoCAD MEP 2014 / Revit MEP 2014 / EastCoast CAD/CAM addon / Visual Studio 2013

WILL HATCH

  • Bull Frog
  • Posts: 450
Re: How to repeat a command until the user presses escape.
« Reply #8 on: February 14, 2013, 09:51:06 AM »
One last observation about the above code.  I kept the goto/label because when I changed the If statement to a while loop instead of repeating the main prompt it was repeating the individual prompts inside of the subcommands.  I assumed it was because autocad was remembering the last prompt used when checking for promptstatus.ok.  Instead of trying to figure it out, i just used the goto/label statement instead.  For 20 years of my life I was an electrician/mechanic so I figure if I have a tool in my toolbox I might as well use it.

I think that is because you forgot to include the prompt result in your while loop.