Soltana Posted January 25 Posted January 25 (edited) Hi Everyone, I am trying to create an AutoLISP that will replace and/or automatically update an MText field (which in my case are the amendments for a drawing) in the Layouts tab for a series of drawings. The Lisp uses Lee Mac's Object DBX Wrapper and his get files routines (Thank you btw :)) to obtain the drawings and supply the function to each drawing. I am pretty new to Visual Lisps and only understand the basic functions like the vla-get-<item>. I am able to update the first drawing/opened drawing, however cannot seem to get the lisp to loop for each drawing selected. I suspect that it has something to do with vlax-for function but i do not completely understand it, especially when multiple drawings are being evaluated. Autolisp Code: ;--------------------------------EDIT BOX SAVE VARIABLES-----------------------------------; (Defun saveVars () (setq Date (get_tile "Date")) (setq Initials (get_tile "Initials")) (setq Subject (get_tile "Subject")) (setq Rev1 (atoi (get_tile "Rev1"))) (setq Prelim (atoi (get_tile "Prelim"))) (setq Tender (atoi (get_tile "Tender"))) ) ;-------------------------------------LOAD FILES------------------------------------------; (defun LoadFiles (a) (cond ((= a 1) (setq flst (LM:getfiles "select Drawings" nil "dwg"))) ) ) ;-----------------------------EDIT BOX LOAD AND FUNCTIONS----------------------------------; (defun C:Editbox ( ) (vl-load-com) (if (not (setq dcl_id (load_dialog "DCL_DCL_Editbox.dcl"))) (progn (alert "The DCL file could not be loaded.") (exit) ) (progn (if (not (new_dialog "DCL_Editbox" dcl_id)) (progn (alert "The DCL_DCL_Editbox could not be found inside the DCL file") (exit) ) (progn (action_tile "but1" "(LoadFiles 1)") (action_tile "accept" "(saveVars) (done_dialog 2)") (action_tile "cancel" "(done_dialog 1)") (setq ddiag (start_dialog)) (unload_dialog dcl_id) (if (= ddiag 1) (progn (print "Editbox cancelled!") (exit) ) ) (if (and (= ddiag 2) (and (= prelim 1) (= tender 1))) (exit) (LM:ODBX 'SC:T2 flst t) ) ) ) ) ) (princ) ) ;--------------------------------REWRITE AMENDMENTS FUNCTION-----------------------------------; (defun SC:T2 ( doc / ss1 lst2 lst RstrP StrPP RevNP RstrT StrPT RevNT) (vl-load-com) (vlax-for layout (vla-get-layouts doc) (vlax-for object (vlax-get (vla-get-activedocument (vlax-get-acad-object)) 'PaperSpace ) (if (= "AcDbMText" (vla-get-objectname object)) (setq lst (cons object lst)) ) (setq lst2 (car lst)) ) lst (setq ss1 (vlax-get-property lst2 'Textstring)) (progn (cond ((and (= rev1 1) (= Prelim 1)) (progn (vla-put-textstring lst2 (strcat "\\pxi-15,l15,tc2,c7,c12,15;\tP1\t" Date "\t" Initials "\t" Subject)) ) ) ((and (= rev1 1) (= tender 1)) (progn (vla-put-textstring lst2 (strcat "\\pxi-15,l15,tc2,c7,c12,15;\t00\t" Date "\t" Initials "\t" Subject)) ) ) ((= Prelim 1) (progn (setq RstrP (vl-list->string (reverse (vl-string->list ss1)))) (if (setq StrPP (vl-string-position (ascii "{") RstrP)) (setq RevNP (substr (vl-list->string (reverse (vl-string->list (substr RstrP (- StrPP 2) 2)))) 2 1)) (setq RevNP "1")) (vla-put-textstring lst2 (strcat ss1 "\\P{\t" (strcat "P" (rtos (+ (distof RevNP 2) 1) 2 3)) "\t" Date "\t" Initials "\t" Subject "}")) ) ) ((= Tender 1) (progn (setq RstrT (vl-list->string (reverse (vl-string->list ss1)))) (if (equal (vl-string-search "00" ss1) nil) (progn (vla-put-textstring lst2 (strcat ss1 "\\P{\t00\t" Date "\t" Initials "\t" Subject "}")) (exit) ) (if (setq StrPT (vl-string-position (ascii "{") RstrT)) (setq RevNT (substr (vl-list->string (reverse (vl-string->list (substr RstrT (- StrPT 2) 2)))) 2 1)) (setq RevNT "1")) ) (vla-put-textstring lst2 (strcat ss1 "\\P{\t" (strcat "0" (rtos (+ (distof RevNT 2) 1) 2 3)) "\t" Date "\t" Initials "\t" Subject "}")) ) ) ) ) (princ) ) ) ;--------------------------------GET TAB SPACING-----------------------------------; (defun _splitwords (str del / pos lst4 lst3 ss) (if (setq pos (vl-string-search del str)) (cons (substr str 1 pos) (_splitwords (substr str (+ pos 2))del)) (list str) ) ) (vlax-for obj2 (vlax-get (vla-get-activedocument (vlax-get-acad-object)) 'PaperSpace ) (if (= "AcDbMText" (vla-get-objectname obj2)) (setq lst4 (cons obj2 lst4)) ) (setq lst3 (car lst4)) ) lst4 (setq str (vlax-get-property lst3 'Textstring)) (_splitwords str "\t") DCL Code: DCL_Editbox : dialog { label = "Amendments Update"; : column { : boxed_column { : edit_box { key = "Date"; label = "Enter Date :"; edit_width = 5; value = "01.01.24"; initial_focus = true; } : edit_box { key = "Initials"; label = "Enter Initials :"; edit_width = 5; value = "XXX"; } : edit_box { key = "Subject"; label = "Enter Subject :"; edit_width = 25; value = "PRELIMINARY"; } } : boxed_column { : toggle { key = "Rev1"; label = "Check Box if this is First Revision."; value = "0"; } : toggle { key = "Prelim"; label = "Check Box if this is Preliminary."; value = "0"; } : toggle { key = "Tender"; label = "Check Box if this is Tender or Construction Issue."; value = "0"; } } : boxed_column { : button { key = "but1"; label = "Select Files"; is_default = false; } } : boxed_row { :button { key = "accept"; label = " Okay "; is_default = true; } : button { key = "cancel"; label = " Cancel "; is_default = false; is_cancel = true; } } } } I have found very little information on obtain MText on its own, not in a block, through ODBX and visual lisps; and even tried to wrap my head around Lee Mac's batch find and replace but could not quite work it out. Any help would be appreciated and if you need any additional info let me know. Thanks, Sol. P.S. This is my first post so apologies for any formatting errors and also thank you to everyone that has already helped with this lisp by providing functions on other topics/forums that have also been used here. Amendment Updates.lsp DCL_DCL_Editbox.dcl ODBX Wrapper.lsp Get Files.lsp Edited January 25 by Soltana Added Codes Quote
Lee Mac Posted January 25 Posted January 25 In your SC:T2 function, you are accessing the ActiveDocument, as opposed to the ObjectDBX Document: (vlax-for layout (vla-get-layouts doc) (vlax-for object (vlax-get (vla-get-activedocument (vlax-get-acad-object)) 'PaperSpace ) You should instead operate only on objects derived from the ObjectDBX, e.g.: (vlax-for layout (vla-get-layouts doc) (vlax-for obj (vla-get-block layout) ... ) ) Quote
Soltana Posted January 25 Author Posted January 25 Thanks for the quick reply Lee, I have gotten it to work now so I really appreciate it. I did not realise that MText was stored as a block so i thought i had to do the long work around but turns out that was my problem. Thanks again. Sol. Quote
Lee Mac Posted January 25 Posted January 25 4 hours ago, Soltana said: I did not realise that MText was stored as a block so i thought i had to do the long work around but turns out that was my problem. MText isn't stored as a block, but rather each Layout (including Model) is a block (essentially a container). Quote
Soltana Posted January 25 Author Posted January 25 4 hours ago, Lee Mac said: MText isn't stored as a block, but rather each Layout (including Model) is a block (essentially a container). Oh okay, so then it just searches within the block (layout space (container)) for what ever item you filtered for. Thanks for the insight. Quote
ronjonp Posted January 26 Posted January 26 @Soltana Take a look HERE to understand the Object Model. Quote
Soltana Posted February 8 Author Posted February 8 Hi Again, So i ran into further problems after i had 'fixed' the lisp routine i posted here, so i have amended it, but now it will repeat itself based on the number of MText objects found and i am unsure of why. For example, if 5 MText objects are found, the routine will enter the given data into the specific MText field (that is the one at the coordinates "16.0 42.75 0.0") 5 times. I figure it is something to do with the lambda function which is repeating itself somehow but i only understand the basic principles of the function. Here is the updated code : (defun SC:T2 ( doc / lst lst2 lst3 lst4 stri RstrP StrPP RevNP RstrT StrPT RevNT) (vl-load-com) (vlax-for layout (vla-get-layouts doc) (vlax-for object (vla-get-block layout) (if (= "AcDbMText" (vla-get-objectname object)) (progn (setq lst (cons object lst)) (setq stri (vlax-get-property (setq lst4 (nth (vl-position '(16.0 42.75 0.0) (mapcar '(lambda (coord) (vlax-safearray->list (vlax-variant-value (vla-get-InsertionPoint coord))) ) lst) ) lst) ) 'textstring) ) (_splitwords stri "\t") (progn (cond ( (and (= rev1 1) (= Prelim 1)) (progn (vla-put-textstring lst4 (strcat "\\pxi-15,l15,tc2,c7,c12,15;\tP1\t" Date "\t" Initials "\t" Subject)) ) ) ( (and (= rev1 1) (= tender 1)) (progn (vla-put-textstring lst4 (strcat "\\pxi-15,l15,tc2,c7,c12,15;\t00\t" Date "\t" Initials "\t" Subject)) ) ) ( (= Prelim 1) ; <--- here is where the code gets muddled up (progn (setq RstrP (vl-list->string (reverse (vl-string->list stri)))) (if (setq StrPP (vl-string-search "\\P" RstrP)) (setq RevNP (substr (vl-list->string (reverse (vl-string->list (substr RstrP (- StrPP 2) 2)))) 2 1)) (setq RevNP "1") ) (vla-put-textstring lst4 (strcat stri "\\P{\t" (strcat "P" (rtos (+ (distof RevNP 2) 1) 2 3)) "\t" Date "\t" Initials "\t" Subject "}")) ) ) ; ( (= Tender 1) ; (progn ; (setq RstrT (vl-list->string (reverse (vl-string->list stri)))) ; (if (equal (vl-string-search "00" stri) nil) ; (progn ; (vla-put-textstring lst4 (strcat stri "\\P{\t00\t" Date "\t" Initials "\t" Subject "}")) ; (exit) ; ) ; (if (setq StrPT (vl-string-search "\P" RstrT)) ; (setq RevNT (substr (vl-list->string (reverse (vl-string->list (substr RstrT (- StrPT 2) 2)))) 2 1)) ; (setq RevNT "1") ; ) ; ) ; (vla-put-textstring lst4 (strcat stri "\\P{\t" (strcat "0" (rtos (+ (distof RevNT 2) 1) 2 3)) "\t" Date "\t" Initials "\t" Subject "}")) ; ) ) ) ) ) ) ) (princ) ) ;--------------------------------GET TAB SPACING-----------------------------------; (defun _splitwords (str del / pos) (if (setq pos (vl-string-search del str)) (cons (substr str 1 pos) (_splitwords (substr str (+ pos 2))del)) (list str) ) ) If someone were to take a look at it, it would be really appreciated. Thanks, sol. Quote
Lee Mac Posted February 8 Posted February 8 The issue arises because once the target MText object has been encountered and added to the list, the nth function will return that object for every subsequent MText object encountered, thus causing the existing content to be concatenated with every iteration. Quote
Lee Mac Posted February 8 Posted February 8 Perhaps consider something like this (written quickly & untested): (defun sc:t2 ( doc ) (vlax-for lyt (vla-get-layouts doc) ( (lambda ( / lst mtx rev str ) (vl-catch-all-apply (function (lambda ( ) (vlax-for obj (vla-get-block lyt) (if (and (= "AcDbMText" (vla-get-objectname obj)) (equal '(16.0 42.75 0.0) (vlax-get obj 'insertionpoint) 1e-6) ) (progn (setq mtx obj) (exit) ;; Avoid subsequent iterations after MText is found ) ) ) ) ) ) (cond ( (null mtx)) ( (not (vlax-write-enabled-p mtx))) ( (and (= rev1 1) (= Prelim 1)) (vla-put-textstring mtx (strcat "\\pxi-15,l15,tc2,c7,c12,15;\tP1\t" Date "\t" Initials "\t" Subject)) ) ( (and (= rev1 1) (= tender 1)) (vla-put-textstring mtx (strcat "\\pxi-15,l15,tc2,c7,c12,15;\t00\t" Date "\t" Initials "\t" Subject)) ) ( (= Prelim 1) (setq str (vla-get-textstring mtx) lst (LM:str->lst str "\\P") rev (max 1 (atoi (substr (last lst) (1- (strlen (last lst)))))) ) (vla-put-textstring mtx (strcat str "\\P{\tP" (itoa (1+ rev)) "\t" Date "\t" Initials "\t" Subject "}")) ) ) ) ) ) ) ;; String to List - Lee Mac ;; Separates a string using a given delimiter ;; str - [str] String to process ;; del - [str] Delimiter by which to separate the string ;; Returns: [lst] List of strings (defun LM:str->lst ( str del / pos ) (if (setq pos (vl-string-search del str)) (cons (substr str 1 pos) (LM:str->lst (substr str (+ pos 1 (strlen del))) del)) (list str) ) ) Quote
Soltana Posted February 9 Author Posted February 9 Hi Lee, Thanks for the response, your code does not work right off the bat, but i will see how i can incorporate the changes you have made into the current code and get it to work. Quote
Lee Mac Posted February 9 Posted February 9 6 hours ago, Soltana said: Thanks for the response, your code does not work right off the bat, but i will see how i can incorporate the changes you have made into the current code and get it to work. I've probably overlooked something coding the solution "blind" - out of interest, what error do you receive, if any? Quote
Soltana Posted February 9 Author Posted February 9 Sorry i haven't had much time to look over the code, just the past hour or so, but it turns out it does work and does not work (i am unsure of what happened when i tried it earlier, but it was as if the sc:t2 just didnt want to run). At the moment when i run the code it will write the first and second line (P1 & P2), however, anything that follows will continue at P2. I tried to tinker with it and incorporate parts of my code into it but ran into "bad argument : VLA-OBJECT nil ". I am currently reviewing your code now after realising that it does work (my bad), and checking where it is going wrong. I believe that it is encountering a problem when it counts the characters in the string as it attempts to add 1 to the previous P#. Quote
BIGAL Posted February 9 Posted February 9 Have you thought about using a Title block in your layouts ? It is much easier to get a Block in a layout and play with the attributes, including multi line revisions. Quote
Soltana Posted February 9 Author Posted February 9 29 minutes ago, BIGAL said: Have you thought about using a Title block in your layouts ? It is much easier to get a Block in a layout and play with the attributes, including multi line revisions. My company uses a titleblock with attributes assigned to a sheet set, but for each amendment made is filled out in the paper space. Quote
Soltana Posted February 10 Author Posted February 10 (edited) 4 hours ago, Soltana said: My company Sorry i actually meant the company that i work for, not MY company. Anyway, i have gotten the code to work and for anyone that may find it helpful (not sure how likely as it is very tailored to my needs) i have posted it below. Thank you Lee for all your help, it is really appreciated and have learnt a lot more about lisps from this experience. ;--------------------------------EDIT BOX SAVE VARIABLES-----------------------------------; (Defun saveVars () (setq Date (get_tile "Date")) (setq Initials (get_tile "Initials")) (setq Subject (get_tile "Subject")) (setq Rev1 (atoi (get_tile "Rev1"))) (setq Prelim (atoi (get_tile "Prelim"))) (setq Tender (atoi (get_tile "Tender"))) ) ;-------------------------------------LOAD FILES------------------------------------------; (defun LoadFiles (a) (cond ((= a 1) (setq flst (LM:getfiles "select Drawings" nil "dwg"))) ) ) ;-----------------------------EDIT BOX LOAD AND FUNCTIONS----------------------------------; (defun C:RevAmend ( ) (vl-load-com) (if (not (setq dcl_id (load_dialog "DCL_DCL_Editbox.dcl"))) (progn (alert "The DCL file could not be loaded.") (exit) ) (progn (if (not (new_dialog "DCL_Editbox" dcl_id)) (progn (alert "The DCL_DCL_Editbox could not be found inside the DCL file") (exit) ) (progn (action_tile "but1" "(LoadFiles 1)") (action_tile "accept" "(saveVars) (done_dialog 2)") (action_tile "cancel" "(done_dialog 1)") (setq ddiag (start_dialog)) (unload_dialog dcl_id) (if (= ddiag 1) (progn (print "RevAmend cancelled!") (exit) ) ) (if (and (= ddiag 2) (and (= prelim 1) (= tender 1))) (exit) (LM:ODBX 'SC:T2 flst t) ) ) ) ) ) (princ) ) ;--------------------------------REWRITE AMENDMENTS FUNCTION-----------------------------------; (defun sc:t2 ( doc ) (vlax-for lyt (vla-get-layouts doc) ( (lambda ( / lst mtx rev str ) (vl-catch-all-apply (function (lambda ( ) (vlax-for obj (vla-get-block lyt) (if (and (= "AcDbMText" (vla-get-objectname obj)) (equal '(16.0 42.75 0.0) (vlax-get obj 'insertionpoint) 1e-6) ) (progn (setq mtx obj) (exit) ;; Avoid subsequent iterations after MText is found ) ) ) ) ) ) (cond ( (null mtx)) ( (not (vlax-write-enabled-p mtx))) ( (and (= rev1 1) (= Prelim 1)) (vla-put-textstring mtx (strcat "\\pxi-15,l15,tc2,c7,c12,15;\tP1\t" Date "\t" Initials "\t" Subject)) ) ( (and (= rev1 1) (= tender 1)) (vla-put-textstring mtx (strcat "\\pxi-15,l15,tc2,c7,c12,15;\t00\t" Date "\t" Initials "\t" Subject)) ) ( (= Prelim 1) (setq str (vla-get-textstring mtx) lst (LM:str->lst str "\\P") ) (cond ((if (vl-string-search "{" (last lst)) (setq rev (atoi (substr (last lst) 4 1))) ) ) ((= (car lst) (last lst)) (setq rev 1) ) ((if (and (equal (vl-string-search "{" (last lst)) nil) (not (equal (car lst) (last lst)))) (setq rev (atoi (substr (last lst) 3 1))) ) ) ) (vla-put-textstring mtx (strcat str "\\P{\tP" (itoa (1+ rev)) "\t" Date "\t" Initials "\t" Subject "}")) ) ( (= Tender 1) (setq str (vla-get-textstring mtx) lst (LM:str->lst str "\\P") ) (cond ((if (equal (vl-string-search "00" str) nil) (setq rev -1) )) ((if (vl-string-search "{" (last lst)) (setq rev (atoi (substr (last lst) 4 1))) ) ) ((= (car lst) (last lst)) (setq rev 0) ) ((if (and (equal (vl-string-search "{" (last lst)) nil) (not (equal (car lst) (last lst)))) (setq rev (atoi (substr (last lst) 3 1))) ) ) ) (if (= rev 9) (vla-put-textstring mtx (strcat str "\\P{\t" (itoa (1+ rev)) "\t" Date "\t" Initials "\t" Subject "}")) (vla-put-textstring mtx (strcat str "\\P{\t0" (itoa (1+ rev)) "\t" Date "\t" Initials "\t" Subject "}")) ) ) ) ) ) ) ) ;; String to List - Lee Mac ;; Separates a string using a given delimiter ;; str - [str] String to process ;; del - [str] Delimiter by which to separate the string ;; Returns: [lst] List of strings (defun LM:str->lst ( str del / pos ) (if (setq pos (vl-string-search del str)) (cons (substr str 1 pos) (LM:str->lst (substr str (+ pos 1 (strlen del))) del)) (list str) ) ) ;--------------------------------GET TAB SPACING-----------------------------------; (defun _splitwords (str del / pos) (if (setq pos (vl-string-search del str)) (cons (substr str 1 pos) (_splitwords (substr str (+ pos 2))del)) (list str) ) ) One last question (hopefully): Is it possible to error handle using objectdbx. Error handling mostly by providing the ability to undo if a mistake is made. Not essential to the code but a nice safety precaution, otherwise could it be coded in by replacing the file with the .bak file? Thanks once again . Edited February 10 by Soltana Quote
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.