Jump to content

Click to Replace and Increment Alphanumeric Text


wwakefield

Recommended Posts

First of all, thank you all for your generosity in helping out here; I've learned a lot from reading past posts and dissecting bits of code here. I've had several programming courses back in engineering (a decade ago, C, C++, Java, etc) but haven't really kept up with it. That being said, I'm teaching myself auto/visualLISP and trying to make my professional life a little easier.

 

Special thanks to Lee Mac, who's posts here and website has helped get me this far.

 

I'm trying to recreate a program I've seen before and have hit a snag. I want to be able to click an object that has text replace it with a value I input, then be able to click on another object's text, increment it, click/increment, etc.

 

I've made this work with mtext objects, but am stuck on how to expand that functionality to block attributes, or even a group of a text object and a few lines. I've seen this work previously independent of it being a single text object or a block attribute, but never looked at the code (kicking myself now, but nothing I can do about it)

 

Here's what I currently have that works with mtext. Questions:

  • How do I modify this to work on any text object, whether it's in a group or a block attribute? (I realize this may be complicated/impossible?)
  • Are there better, more efficient ways to do what I'm doing?

 

;;; INC1.lsp [command name: INC1]
;;; Increments alphanumeric text.
;;; Wes Wakefield Dec 2016

(defun C:INC1 (/ flg flg2 txt temp)
 (if (not *pfix*)(setq *pfix* "N"));_Initalize *pfix* if nil
 (if (not *num*)(setq *num* "1000"));_Initalize *num* if nil

 (setq temp (getstring (strcat "\nEnter Prefix<" *pfix* ">: ")))
 (if (/= temp "")(setq *pfix* temp))
 
 (setq temp (getstring (strcat "\nEnter Starting Number<" *num* ">: ")))
 (if (/= temp "")(setq *num* temp))

 (setq flg2 1)
 (while (= flg2 1);_Loop until user hits "ESC"
   (setq txt (entsel)
  flg 1)
   (while (= flg 1);_Loop if user click doesn't select object
     (if (= txt nil)
(setq txt (entsel));_Repeat selection if nil
(setq
  flg 0
  txt (car txt)
)
     )
   )
   (setq txt (vlax-ename->vla-object txt)) ;_Convert to object
   (vla-put-TextString txt (strcat *pfix* *num*)) ;_Replace text
   (setq *num*  (itoa (1+ (atoi *num*))));_Increment *num*
   )
 )
 (princ)
)

Link to comment
Share on other sites

Also, if this has been covered somewhere, please feel free to point me in the right direction; I don't mind doing some research on my own. :-)

Link to comment
Share on other sites

Firstly, welcome to CADTutor and thank you for your gratitude - I'm pleased that you found my contributions useful.

 

I have prepared the following commented version of your code which should point you in the right direction - I have tried not to veer too far from your original in terms of complexity so that you may follow the code without getting overwhelmed.

 

I think you were perhaps overthinking the loop with the use of flag variables and nested while loops - it suffices to check the return of the entsel/nentsel function:

[color=GREEN];; Define function & declare local variables (*prefix* & *number* are global)[/color]
([color=BLUE]defun[/color] c:inc2 ( [color=BLUE]/[/color] ent obj tmp )

   [color=GREEN];; Initialise global variables to first-time defaults[/color]
   ([color=BLUE]if[/color] ([color=BLUE]null[/color] *prefix*)
       ([color=BLUE]setq[/color] *prefix* [color=MAROON]"N"[/color])
   )
   ([color=BLUE]if[/color] ([color=BLUE]null[/color] *number*)
       ([color=BLUE]setq[/color] *number* 1000) [color=GREEN];; Use a number here[/color]
   )

   [color=GREEN];; If the user has entered a prefix (getstring returns an empty string on ENTER)[/color]
   ([color=BLUE]if[/color] ([color=BLUE]/=[/color] [color=MAROON]""[/color] ([color=BLUE]setq[/color] tmp ([color=BLUE]getstring[/color] [color=BLUE]t[/color] ([color=BLUE]strcat[/color] [color=MAROON]"\nEnter prefix <"[/color] *prefix* [color=MAROON]">: "[/color])))) [color=GREEN];; t to allow spaces[/color]
       ([color=BLUE]setq[/color] *prefix* tmp) [color=GREEN];; Redefine the global variable to use the new prefix[/color]
   )
   [color=GREEN];; If the user has entered a number (getint returns nil on ENTER)[/color]
   ([color=BLUE]if[/color] ([color=BLUE]setq[/color] tmp ([color=BLUE]getint[/color] ([color=BLUE]strcat[/color] [color=MAROON]"\nEnter starting number <"[/color] ([color=BLUE]itoa[/color] *number*) [color=MAROON]">: "[/color]))) [color=GREEN];; AutoLISP is dynamically typed, so can use same variable name[/color]
       ([color=BLUE]setq[/color] *number* tmp) [color=GREEN];; Redefine the global variable to use the new starting number[/color]
   )

   [color=GREEN];; While the user is still selecting objects[/color]
   ([color=BLUE]while[/color] ([color=BLUE]setq[/color] ent ([color=BLUE]car[/color] ([color=BLUE]nentsel[/color]))) [color=GREEN];; nentsel to allow nested selection[/color]

       [color=GREEN];; Convert the entity to a vla-object (not absolutely necessary, but we'll stick with ActiveX)[/color]
       ([color=BLUE]setq[/color] obj ([color=BLUE]vlax-ename->vla-object[/color] ent))

       [color=GREEN];; If the selected object is Text, MText or an Attribute[/color]
       ([color=BLUE]if[/color] ([color=BLUE]wcmatch[/color] ([color=BLUE]vla-get-objectname[/color] obj) [color=MAROON]"AcDb*Text,AcDbAttribute"[/color])

           [color=GREEN];; If the object is write-enabled[/color]
           ([color=BLUE]if[/color] ([color=BLUE]vlax-write-enabled-p[/color] obj)

               [color=GREEN];; Evaluate the following expressions as part of a single progn expression (the 'then' argument)[/color]
               ([color=BLUE]progn[/color]
                   [color=GREEN];; Modify the ActiveX textstring property to a concatenation of the *prefix* and *number* converted to a string[/color]
                   ([color=BLUE]vla-put-textstring[/color] obj ([color=BLUE]strcat[/color] *prefix* ([color=BLUE]itoa[/color] *number*)))

                   [color=GREEN];; Increment *number*[/color]
                   ([color=BLUE]setq[/color] *number* ([color=BLUE]1+[/color] *number*))
                   
               ) [color=GREEN];; end progn[/color]

               [color=GREEN];; Inform the user of a write-protected object[/color]
               ([color=BLUE]princ[/color] [color=MAROON]"\nSelected object is on a locked layer."[/color])
               
           ) [color=GREEN];; end if[/color]
       
           [color=GREEN];; Inform the user of an invalid object[/color]
           ([color=BLUE]princ[/color] [color=MAROON]"\nSelected object is not text, mtext or attribute."[/color])
           
       ) [color=GREEN];; end if[/color]
       
   ) [color=GREEN];; end while[/color]

   [color=GREEN];; Suppress the value returned by the last evaluated expression[/color]
   ([color=BLUE]princ[/color])
   
) [color=GREEN];; end defun

;; Load the ActiveX component of Visual LISP and suppress the value returned on load
[/color]([color="blue"]vl-load-com[/color]) ([color="blue"]princ[/color])

Of course, feel free to ask if you have any further questions about the above.

 

Lee

Link to comment
Share on other sites

Wow, thanks for the quick replies! I'll play around with this tonight. Didn't know about nentsel; I feel so handicapped learning a new language, haha...

Link to comment
Share on other sites

Update: works like a charm, with one exception. When I click a blank space (if I misclick when trying to select a block), the program terminates. This is what I was trying to originally solve with the flag in the while loop... Any better way to do that?

Link to comment
Share on other sites

Update: works like a charm, with one exception. When I click a blank space (if I misclick when trying to select a block), the program terminates. This is what I was trying to originally solve with the flag in the while loop... Any better way to do that?

 

Consider the following -

[color=GREEN];; Define function & declare local variables (*prefix* & *number* are global)[/color]
([color=BLUE]defun[/color] c:inc3 ( [color=BLUE]/[/color] ent obj tmp )

   [color=GREEN];; Initialise global variables to first-time defaults[/color]
   ([color=BLUE]if[/color] ([color=BLUE]null[/color] *prefix*)
       ([color=BLUE]setq[/color] *prefix* [color=MAROON]"N"[/color])
   )
   ([color=BLUE]if[/color] ([color=BLUE]null[/color] *number*)
       ([color=BLUE]setq[/color] *number* 1000) [color=GREEN];; Use a number here[/color]
   )

   [color=GREEN];; If the user has entered a prefix (getstring returns an empty string on ENTER)[/color]
   ([color=BLUE]if[/color] ([color=BLUE]/=[/color] [color=MAROON]""[/color] ([color=BLUE]setq[/color] tmp ([color=BLUE]getstring[/color] [color=BLUE]t[/color] ([color=BLUE]strcat[/color] [color=MAROON]"\nEnter prefix <"[/color] *prefix* [color=MAROON]">: "[/color])))) [color=GREEN];; t to allow spaces[/color]
       ([color=BLUE]setq[/color] *prefix* tmp) [color=GREEN];; Redefine the global variable to use the new prefix[/color]
   )
   [color=GREEN];; If the user has entered a number (getint returns nil on ENTER)[/color]
   ([color=BLUE]if[/color] ([color=BLUE]setq[/color] tmp ([color=BLUE]getint[/color] ([color=BLUE]strcat[/color] [color=MAROON]"\nEnter starting number <"[/color] ([color=BLUE]itoa[/color] *number*) [color=MAROON]">: "[/color]))) [color=GREEN];; AutoLISP is dynamically typed, so can use same variable name[/color]
       ([color=BLUE]setq[/color] *number* tmp) [color=GREEN];; Redefine the global variable to use the new starting number[/color]
   )

   [color=GREEN];; Reset the ERRNO system variable to 0 to clear any possible previous value[/color]
   ([color=BLUE]setvar[/color] 'errno 0)

   [color=GREEN];; While the user is still selecting objects[/color]
   ([color=BLUE]while[/color]
       
       ([color=BLUE]or[/color] [color=GREEN];; While either of the following expressions is True[/color]
           
           ([color=BLUE]setq[/color] ent ([color=BLUE]car[/color] ([color=BLUE]nentsel[/color]))) [color=GREEN];; Either the user has selected an object (nentsel to allow nested selection)[/color]

           ([color=BLUE]=[/color] 7 ([color=BLUE]getvar[/color] 'errno)) [color=GREEN];; Or the ERRNO system variable = 7 (Missed Pick)[/color]
           
       ) [color=GREEN];; end or[/color]

       [color=GREEN];; ERRNO system variable = 7 (Missed Pick)[/color]
       ([color=BLUE]if[/color] ([color=BLUE]=[/color] 7 ([color=BLUE]getvar[/color] 'errno))

           [color=GREEN];; Inform the user[/color]
           ([color=BLUE]princ[/color] [color=MAROON]"\nMissed, try again."[/color])

           [color=GREEN];; Else we have a selected entity[/color]
           ([color=BLUE]progn[/color]

               [color=GREEN];; Convert the entity to a vla-object (not absolutely necessary, but we'll stick with ActiveX)[/color]
               ([color=BLUE]setq[/color] obj ([color=BLUE]vlax-ename->vla-object[/color] ent))

               [color=GREEN];; If the selected object is Text, MText or an Attribute[/color]
               ([color=BLUE]if[/color] ([color=BLUE]wcmatch[/color] ([color=BLUE]vla-get-objectname[/color] obj) [color=MAROON]"AcDb*Text,AcDbAttribute"[/color])

                   [color=GREEN];; If the object is write-enabled[/color]
                   ([color=BLUE]if[/color] ([color=BLUE]vlax-write-enabled-p[/color] obj)

                       [color=GREEN];; Evaluate the following expressions as part of a single progn expression (the 'then' argument)[/color]
                       ([color=BLUE]progn[/color]
                           [color=GREEN];; Modify the ActiveX textstring property to a concatenation of the *prefix* and *number* converted to a string[/color]
                           ([color=BLUE]vla-put-textstring[/color] obj ([color=BLUE]strcat[/color] *prefix* ([color=BLUE]itoa[/color] *number*)))

                           [color=GREEN];; Increment *number*[/color]
                           ([color=BLUE]setq[/color] *number* ([color=BLUE]1+[/color] *number*))
                           
                       ) [color=GREEN];; end progn[/color]

                       [color=GREEN];; Inform the user of a write-protected object[/color]
                       ([color=BLUE]princ[/color] [color=MAROON]"\nSelected object is on a locked layer."[/color])
                       
                   ) [color=GREEN];; end if[/color]
               
                   [color=GREEN];; Inform the user of an invalid object[/color]
                   ([color=BLUE]princ[/color] [color=MAROON]"\nSelected object is not text, mtext or attribute."[/color])
                   
               ) [color=GREEN];; end if[/color]

           ) [color=GREEN];; end progn[/color]

       ) [color=GREEN];; end if[/color]
           
       [color=GREEN];; Reset the ERRNO system variable to 0 to clear any possible previous value[/color]
       ([color=BLUE]setvar[/color] 'errno 0)
       
   ) [color=GREEN];; end while[/color]

   [color=GREEN];; Suppress the value returned by the last evaluated expression[/color]
   ([color=BLUE]princ[/color])
   
) [color=GREEN];; end defun[/color]

[color=GREEN];; Load the ActiveX component of Visual LISP and suppress the value returned on load[/color]
([color=BLUE]vl-load-com[/color]) ([color=BLUE]princ[/color])

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...