wwakefield Posted December 30, 2016 Share Posted December 30, 2016 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) ) Quote Link to comment Share on other sites More sharing options...
wwakefield Posted December 30, 2016 Author Share Posted December 30, 2016 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. :-) Quote Link to comment Share on other sites More sharing options...
Lee Mac Posted December 30, 2016 Share Posted December 30, 2016 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 Quote Link to comment Share on other sites More sharing options...
Grrr Posted December 30, 2016 Share Posted December 30, 2016 I was going to suggest to check at the nentsel function, until Lee flew here with an answer on his motorcycle. Quote Link to comment Share on other sites More sharing options...
wwakefield Posted December 31, 2016 Author Share Posted December 31, 2016 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... Quote Link to comment Share on other sites More sharing options...
wwakefield Posted January 3, 2017 Author Share Posted January 3, 2017 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? Quote Link to comment Share on other sites More sharing options...
Lee Mac Posted January 3, 2017 Share Posted January 3, 2017 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]) Quote Link to comment Share on other sites More sharing options...
wwakefield Posted January 3, 2017 Author Share Posted January 3, 2017 Ah, makes sense. Thanks! Wes Quote Link to comment Share on other sites More sharing options...
Lee Mac Posted January 3, 2017 Share Posted January 3, 2017 You're welcome! Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.