Help: automatically number page tag in blocks of multiple drawing files?

Help: automatically number page tag in blocks of multiple drawing files?

Anonymous
Not applicable
2,770 Views
35 Replies
Message 1 of 36

Help: automatically number page tag in blocks of multiple drawing files?

Anonymous
Not applicable

Hi,

 

I have more than 600 drawing files that have same block title.

I need to update their page number tag. That can be done manually. But it's tedious and time consuming.

I have a routine that modifies a specific tag's value but just in a drawing. 

Could someone give me some advice on how to do it with a routine?

Is it possible to do with batch file?

Any help would be greatly appreciated.

 

Thank you.

0 Likes
Accepted solutions (1)
2,771 Views
35 Replies
Replies (35)
Message 21 of 36

hmsilva
Mentor
Mentor
OK,
tonight I'll see what I can do...

Henrique

EESignature

0 Likes
Message 22 of 36

hmsilva
Mentor
Mentor
Accepted solution

Hi maikhanhmst,

 

the following code uses ObjectDBX, and as I have said in message #9, each dwg will
'lose the dwg's thumbnail until the next time you open/save each dwg.'
and if your .csv file keeps the same configuration as the sample 'title block with numbering pages.csv', the code will do the trick...

 

Ensures that none of DWG's to process is open when you run the code...

 

vl-load-com)
(defun c:demo (/ *error* change_number parse file line lst ofile)

  (defun *error* (msg)
    (if dbx
      (vlax-release-object dbx)
    )
    (if ofile
      (close ofile)
    )
    (cond
      ((not msg))
      ((wcmatch (strcase msg) "*QUIT*,*CANCEL*"))
      (T (princ (strcat "\nError: " msg)))
    )
    (princ)
  )

  (defun parse (str delim)
    (while (/= str (setq str (vl-string-subst "\"\"" delim str)))
    )
    (read (strcat "(\"" str "\")"))
  )

  (defun change_number (path blkname tagname val / attlst dbx id)
    (setq id (strcat "objectdbx.AxDbDocument." (substr (getvar "acadver") 1 2)))
    (setq dbx (vlax-create-object id))
    (vla-open dbx path)
    (vlax-for layt (vla-get-layouts dbx)
      (vlax-for blk (vla-get-block layt)
        (if (and
              (= (vla-get-ObjectName blk) "AcDbBlockReference")
              (= (strcase (vla-get-effectivename blk)) (strcase blkname))
              (= (vla-get-hasattributes blk) :vlax-true)
              (setq attlst (vlax-invoke blk 'GetAttributes))
            )
          (foreach a attlst
            (if (= (strcase (vla-get-TagString a)) (strcase tagname))
              (progn
                (vla-put-TextString a val)
                (vla-saveas dbx path)
              )
            )
          )
        )
      )
    )
    (vlax-release-object dbx)
  )

  (if (and (setq file (getfiled "Select the csv file... " (getvar 'DWGPREFIX) "csv" 0))
           (setq ofile (open file "r"))
      )
    (progn
      (while (setq line (read-line ofile))
        (setq line (vl-string-translate "\\" "/" line))
        (setq lst (parse line ","))
        (if (findfile (nth 0 lst))
          (change_number (nth 0 lst) (nth 1 lst) (nth 2 lst) (nth 3 lst))
        )
      )
      (close ofile)
    )
  )
  (princ)
)

 

Hope this helps,
Henrique

EESignature

Message 23 of 36

Anonymous
Not applicable
Hi Henrique,
It works great.
You're always a such of great help.
Thank you so much.
By the way, does this routine will save the dwg file with the lastest version of AutoCAD I'm using?
Is there something to run the routine with multiple files without inserting the file names into the csv file? Actually, I have a lot of files.


0 Likes
Message 24 of 36

hmsilva
Mentor
Mentor

@Anonymous wrote:
Hi Henrique,
It works great.
You're always a such of great help.
Thank you so much.

You're welcome, maikhanhmst!
Glad I could help.


@Anonymous wrote:
By the way, does this routine will save the dwg file with the lastest version of AutoCAD I'm using?

With the 'vla-saveas' method, without stating the 'file version', will be used the current file version.


@Anonymous wrote:
Is there something to run the routine with multiple files without inserting the file names into the csv file? Actually, I have a lot of files.

This routine was written to read a .csv file...

As I said beforethe hard part is to create a relation between the dwg name, and the new number, in this case was created by a .csv file...


Henrique

EESignature

0 Likes
Message 25 of 36

Anonymous
Not applicable
Hi Henrique,
I've searched for the way to export all file names to csv. So I can list all names without typing them in csv file.
My jobs is now easy to do with your great routine.
Many thanks.

0 Likes
Message 26 of 36

hmsilva
Mentor
Mentor
You're welcome, maikhanhmst!
Glad you have it sorted!

Henrique

EESignature

0 Likes
Message 27 of 36

Anonymous
Not applicable

Hi Henrique,

 

I'm studying your routine. 

I'm quite new to use the "cond" function.

Could I know how the "cond" function works in the following code?

 

(cond
      ((not msg))
      ((wcmatch (strcase msg) "*QUIT*,*CANCEL*"))
      (T (princ (strcat "\nError: " msg)))
    )

 At the 2nd and 3rd line, is it possible to use "cond" function without "result" if the expression is true? 

 

Thank you. 

0 Likes
Message 28 of 36

hmsilva
Mentor
Mentor

@Anonymous wrote:

Hi Henrique,

 

I'm studying your routine. 

I'm quite new to use the "cond" function.

Could I know how the "cond" function works in the following code?

 

(cond
      ((not msg))
      ((wcmatch (strcase msg) "*QUIT*,*CANCEL*"))
      (T (princ (strcat "\nError: " msg)))
    )

 At the 2nd and 3rd line, is it possible to use "cond" function without "result" if the expression is true? 

 

Thank you. 


Hi maikhanhmst ,

 

the *error* function in my post, is a generic function I usually use.

I use the (*error* nil) to call the *error* funtion without existing error and without a message, to restore the System Variables I have modified during the main code.

So, first test expression

(not msg)

will return T, with the (*error* nil), just restore the SysVar's, undo, etc, with no message

second test expression

(wcmatch (strcase msg) "*QUIT*,*CANCEL*")

will return T with a quit or a cancel, just restore the SysVar's, undo, etc, leaving the known error without more messages

the third test expression

T

all errors that are not true in the previous test expressions, will  restore the SysVar's, undo, etc, and will print the unknown error msg.

 

Hope this helps,
Henrique

 

EESignature

0 Likes
Message 29 of 36

Anonymous
Not applicable
Thank you, Henrique.
So, the error handler will return without message if the argument is nill.
By the way, when is the msg nill in the 1st expression?
Why don't we show messages if the 1st and 2nd expression are True?
Is there difference between these with 3rd expression?
I've read about the error handler from Lee Mac's site, but it does't mention about your way to use error handler.
0 Likes
Message 30 of 36

hmsilva
Mentor
Mentor

@Anonymous wrote:
Thank you, Henrique.

You're welcome, maikhanhmst.


@Anonymous wrote:
I've read about the error handler from Lee Mac's site, but it does't mention about your way to use error handler.

Lee Mac's error handler tutorial, is a very good one, and is designed to provide a starting point.

'This tutorials aims to teach you how to create an error handler for your programs to deal with the clean-up operation when something in the code goes wrong.'

 

Each of us has his own way of writing code, you'll find your own.

 

@Lee_Mac 

I'm missing your wise words here at the forums, my friend!


@Anonymous wrote:
So, the error handler will return without message if the argument is nill.
By the way, when is the msg nill in the 1st expression?
Why don't we show messages if the 1st and 2nd expression are True?
Is there difference between these with 3rd expression?

 

This three demo's will cover the three test expressions...

I only change the CMDECHO System Variable, and the error handler will restore the original value.

See the prompts difference, according to the provided msg, as an argument to the *error* function.

 

(defun c:demo1 (/ *error*)

  (defun *error* (msg)
    (if echo
      (setvar 'CMDECHO echo)
    )
    (cond
      ((not msg))
      ((wcmatch (strcase msg) "*QUIT*,*CANCEL*"))
      (T (princ (strcat "\nError: " msg)))
    )
    (princ)
  )

  (setq echo (getvar 'CMDECHO))
  (if (= echo 0)
    (setvar 'CMDECHO 1)
    (setvar 'CMDECHO 0)
  )
  (*error* nil);; <<< no msg, just to restore echo value
  (princ)
)

(defun c:demo2 (/ *error*)

  (defun *error* (msg)
    (if echo
      (setvar 'CMDECHO echo)
    )
    (cond
      ((not msg))
      ((wcmatch (strcase msg) "*QUIT*,*CANCEL*"))
      (T (princ (strcat "\nError: " msg)))
    )
    (princ)
  )

  (setq echo (getvar 'CMDECHO))
  (if (= echo 0)
    (setvar 'CMDECHO 1)
    (setvar 'CMDECHO 0)
  )
  (getpoint "\nPress Esc to create an error...");; <<<< the *CANCEL* will print after the prompt,
  ;; and in the same line, not an Error, just a Cancel or a Quit...
  (*error* nil)
  (princ)
)

(defun c:demo3 (/ *error*)

  (defun *error* (msg)
    (if echo
      (setvar 'CMDECHO echo)
    )
    (cond
      ((not msg))
      ((wcmatch (strcase msg) "*QUIT*,*CANCEL*"))
      (T (princ (strcat "\nError: " msg)))
    )
    (princ)
  )

  (setq echo (getvar 'CMDECHO))
  (if (= echo 0)
    (setvar 'CMDECHO 1)
    (setvar 'CMDECHO 0)
  )
  (/ 3 0);; will generate an error,
  ;; and will print in the last code line as an Error
  (*error* nil)
  (princ)
)

 

Hope this helps,
Henrique

 

EESignature

0 Likes
Message 31 of 36

Lee_Mac
Advisor
Advisor
hmsilva wrote:

@Lee_Mac 

I'm missing your wise words here at the forums, my friend!

 

Sorry for my recent absence Henrique - as you know, I still regularly participate over at the Swamp & CADTutor forums, but it can be difficult to find time for all three forums alongside full-time work committments...

 

Thank you for the mention - I see that you are still offering excellent help & advice around these parts Smiley Wink

 

Lee

0 Likes
Message 32 of 36

hmsilva
Mentor
Mentor

Hi Lee, it's great to hear from you! Smiley Happy

 

Cheers
Henrique

EESignature

0 Likes
Message 33 of 36

Anonymous
Not applicable

Hi Henrique,

 

Not all of the drawing files that I need to update their page number have the title block with page number tag.

Of course I can copy a title block from a drawing to others that don't have.

But it's really time consuming. 

 

In all the drawings that don't have title block have the "key text" named "pagenumber".

So, could you help me to write a similar routine that opens files listed in *.CSV file and allows users to input the "key text" and replace it with the value from *.CSV file?

 

I made some changes in your routine but it doesn't work.

The code:

 

 

(vl-load-com)
(defun c:numberingpage (/ *error* change_number parse file line lst ofile)
  
;;  ERROR HANDLE FUNCTION  ;;
  (defun *error* (msg)
    (if dbx
      (vlax-release-object dbx)
    ) ; if
    (if ofile
      (close ofile)
    ) ; if
    (cond
      ((not msg))
      ((wcmatch (strcase msg) "*QUIT*,*CANCEL*")) ; tests a string to see if it includes either "quit" or "cancel" or both
      (T (princ (strcat "\nError: " msg)))
    ) ; cond
    (princ)
  ) ; defun
  
;;  SUB FUNCTION  ;;
  (defun parse (str delim)
    (while (/= str (setq str (vl-string-subst "\"\"" delim str)))   
    ) ; while
    (setq a str)
    (read (strcat "(\"" str "\")"))
  ) ; defun
  
;;  SUB FUNCTION  ;;
  (defun change_number (path val / attlst dbx id)
    (setq id (strcat "objectdbx.AxDbDocument." (substr (getvar "acadver") 1 2)))
    (setq dbx (vlax-create-object id))
    (vla-open dbx path)
    (vlax-for layt (vla-get-layouts dbx)
      (setq ss (ssget "_X" '((0 . "*TEXT"))))
      (repeat
	(setq i (sslength ss))
	(setq prop (entget (ssname ss (1- i))))
	 ; Find the text whose string value is "pagenumber" and replace with the value from CSV file
	(if (= (cdr (assoc 1 prop)) "pagenumber")
	  (progn
	  (setq ed (subst (cons 1 val) (assoc 1 prop) prop))
	  (entmod ed)
	  ) ; progn
	  ) ; if
	(setq i (1- i))
	) ; repeat
      ) ; vlax-for
    (vlax-release-object dbx)
  ) ; defun

;;  CONTINUE MAIN FUNCTION  ;;
  (if (and (setq file (getfiled "Select the csv file... " (getvar 'DWGPREFIX) "csv" 0))
           (setq ofile (open file "r"))
      ) ; and
    (progn
      (while (setq line (read-line ofile))
        (setq line (vl-string-translate "\\" "/" line)) ; turn back slashes into forward ones
        (setq lst (parse line ","))
        (if (findfile (nth 0 lst))
	   ; Pass file's path and value to change_number sub function
          (change_number (nth 0 lst) (nth 1 lst))
        ) ; if
      ) ; while
      (close ofile)
    ) ; progn
  ) ; if
  (princ)
) ; defun, main function

 

I've also compressed the CSV file and DWG files as a *rar file

Thank you. 

0 Likes
Message 34 of 36

hmsilva
Mentor
Mentor

Hi maikhanhmst,

using ObjectDBX, we can't use selection sets, acess system variables, command calls and entmods...
We need to use the AutoCAD Object Model, the Document colection,... and find the object to process.

 

Untested...

 

(vl-load-com)
(defun c:numberingpage (/ *error* change_number parse file line lst ofile)
  
;;  ERROR HANDLE FUNCTION  ;;
  (defun *error* (msg)
    (if dbx
      (vlax-release-object dbx)
    ) ; if
    (if ofile
      (close ofile)
    ) ; if
    (cond
      ((not msg))
      ((wcmatch (strcase msg) "*QUIT*,*CANCEL*")) ; tests a string to see if it includes either "quit" or "cancel" or both
      (T (princ (strcat "\nError: " msg)))
    ) ; cond
    (princ)
  ) ; defun
  
;;  SUB FUNCTION  ;;
  (defun parse (str delim)
    (while (/= str (setq str (vl-string-subst "\"\"" delim str)))   
    ) ; while
    (setq a str)
    (read (strcat "(\"" str "\")"))
  ) ; defun
  
;;  SUB FUNCTION  ;;
(defun change_number (path val / dbx id)
  (setq id (strcat "objectdbx.AxDbDocument." (substr (getvar "acadver") 1 2)))
  (setq dbx (vlax-create-object id))
  (vla-open dbx path)
  (vlax-for layt (vla-get-layouts dbx)
    (vlax-for blk (vla-get-block layt)
      (if (and
            (= (vla-get-ObjectName blk) "AcDbText")
            (= (strcase (vla-get-textstring blk)) "PAGENUMBER")
            (vlax-write-enabled-p blk)
          )
        (progn
          (vla-put-TextString blk val)
          (vla-saveas dbx path)
        )
      )
    )
  )
  (vlax-release-object dbx)
)


;;  CONTINUE MAIN FUNCTION  ;;
  (if (and (setq file (getfiled "Select the csv file... " (getvar 'DWGPREFIX) "csv" 0))
           (setq ofile (open file "r"))
      ) ; and
    (progn
      (while (setq line (read-line ofile))
        (setq line (vl-string-translate "\\" "/" line)) ; turn back slashes into forward ones
        (setq lst (parse line ","))
        (if (findfile (nth 0 lst))
	   ; Pass file's path and value to change_number sub function
          (change_number (nth 0 lst) (nth 1 lst))
        ) ; if
      ) ; while
      (close ofile)
    ) ; progn
  ) ; if
  (princ)
) ; defun, main function

 

 

Hope this helps,
Henrique

EESignature

Message 35 of 36

Anonymous
Not applicable
Thanks, Henrique.
Nice routine. It works great.
0 Likes
Message 36 of 36

hmsilva
Mentor
Mentor
You're welcome, maikhanhmst.
Glad I could help

Henrique

EESignature

0 Likes