Jump to content

Edit MText using Object DBX Wrapper


Soltana

Recommended Posts

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 by Soltana
Added Codes
Link to comment
Share on other sites

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)
        ...
    )
)

 

 

Link to comment
Share on other sites

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.

 

Link to comment
Share on other sites

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).

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

  • 2 weeks later...

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.

Link to comment
Share on other sites

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.

 

 

Link to comment
Share on other sites

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)
    )
)

 

Link to comment
Share on other sites

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.

 

Link to comment
Share on other sites

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?

Link to comment
Share on other sites

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#.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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 by Soltana
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...