Mtext replace color

Mtext replace color

msarqui
Collaborator Collaborator
7,771 Views
25 Replies
Message 1 of 26

Mtext replace color

msarqui
Collaborator
Collaborator

Hi everyone,

 

I have a tricky one...

 

I have a hundred Mtexts on the Bylayer color. In those Mtexts, I have some words on the Red color, some on the Green color and some on the Blue color, for office standards purposes.

Is there a way to have a routine that allows to select one Mtext at a time and then swap only the Red colored words for another color, like for exemple 216, without change the Green or the Blue colored words?

 

It will be something like the Find and Replace command, but with color formatting option...

 

Thanks!

 

0 Likes
Accepted solutions (2)
7,772 Views
25 Replies
Replies (25)
Message 2 of 26

Kent1Cooper
Consultant
Consultant

As a start, look at StackStyleForce.lsp here.  It locates the code elements within Mtext that define stacked fractions, but if you look in Mtext content at the code for assigning internal override colors, it's very similar -- an alteration of that approach could probably be made to do what you want.  Are you capable of adjusting something like that?

Kent Cooper, AIA
0 Likes
Message 3 of 26

msarqui
Collaborator
Collaborator
I am sorry Kent, but I have no clue how to edit this level of lisp. My knowledge is very basic 😞
0 Likes
Message 4 of 26

hmsilva
Mentor
Mentor

@msarqui wrote:
I am sorry Kent, but I have no clue how to edit this level of lisp. My knowledge is very basic 😞

msarqui,

 

a quick and dirty 'demo'

 

(vl-load-com)
(defun c:demo (/ obj ss str)
  (if (setq ss (ssget "_+.:E:S:L" '((0 . "MTEXT"))))
    (progn
      (setq obj (vlax-ename->vla-object (ssname ss 0))
            str (vla-get-textstring obj)
      )
      (while (wcmatch str "*\\C1;*")
        (setq str (vl-string-subst "\\C216;" "\\C1;" str))
      )
      (vla-put-textstring obj str)
    )
  )
  (princ)
)

 

EDIT: If you don't understand something, just ask...

 

Hope this helps,
Henrique

 

EESignature

Message 5 of 26

Anonymous
Not applicable

(vl-load-com)
(defun c:12 ( / )
  (if (setq oldColor (getint "\nEnter the old color number:"))
    (if (setq newColor (getint "\nEnter the new color number:"))
    (progn
      (setq i 0 q 0)
      (prompt "\nSelect the Mtext to change color")
      (setq ss (ssget '((0 . "MTEXT"))))
      (if ss
        (setq q (sslength ss))
      )
      (repeat q
        (setq en (ssname ss i))
        (setq el (entget en))
        (setq txt (cdr (assoc 1 el)))
        (while (vl-string-search (strcat "\\C" (itoa oldColor)) txt)
          (setq txt (vl-string-subst (strcat "\\C" (itoa newColor)) (strcat "\\C" (itoa oldColor)) txt))
        )
        (setq el (subst (cons 1 txt) (assoc 1 el) el))
        (entmod el)
        (setq i (1+ i))
      )
    )
    )
  )
)

0 Likes
Message 6 of 26

msarqui
Collaborator
Collaborator

Hello guys,

 

Henrique : nothing happens...

gilsonrss : only the last paragraph changed from Yellow to Green. For the rest, nothing happens...

 

Please, see attached one of my texts. I have Autocad2012.

 

Thanks!

0 Likes
Message 7 of 26

Anonymous
Not applicable

Hello,

try this

 

(vl-load-com)
(defun c:12 ( / )
(if (and (setq oldColor (getint "\nEnter the old color number:"))
(<= 0 oldColor 256)
(setq newColor (getint "\nEnter the new color number:"))
(<= 0 newColor 256)
(princ "\nSelect the Mtext to change color")
(setq ss (ssget "_:L" '((0 . "MTEXT"))))
)
(repeat (setq i (sslength ss))
(setq el (entget (ssname ss (setq i (1- i))) (list "*")))
(setq new_el nil)
(foreach par el
(if (or (= (car par) 3) (= (car par) 1))
(progn
(setq txt (cdr par))
(while (vl-string-search (strcat "\\C" (itoa oldColor)) txt)
(setq txt (vl-string-subst (strcat "\\C" (itoa newColor)) (strcat "\\C" (itoa oldColor)) txt))
)
(setq par (cons (car par) txt))
)
)
(setq new_el (append new_el (list par)))
)
(entmod new_el)
)
)
(princ)
)

 

 

of this code was made by Henrique who sent me a private message.

 

 

0 Likes
Message 8 of 26

msarqui
Collaborator
Collaborator

Hello,

Henrique, I changed C1 (Red) for C2 (Yellow). Because I don't have Red in my exemple, but my AutoCAD stops.

Gilsonrss, your second routine is really good! The option to ask the color is very nice. I will do more tests and I will return to you. (Thanks also to Henrique for help you!)

0 Likes
Message 9 of 26

hmsilva
Mentor
Mentor

@msarqui wrote:
Henrique, I changed C1 (Red) for C2 (Yellow). Because I don't have Red in my exemple, but my AutoCAD stops.

Hi msarqui,

 

my demo was write just to show a way to change the color within a MTEXT entity....

To change the color 2, perhaps something like this:

(tested with your dwg, without any problems)

(vl-load-com)
(defun c:demo (/ obj ss str)
  (if (setq ss (ssget "_+.:E:S:L" '((0 . "MTEXT"))))
    (progn
      (setq obj (vlax-ename->vla-object (ssname ss 0))
            str (vla-get-textstring obj)
      )
      (while (wcmatch str "*\\C2;*")
        (setq str (vl-string-subst "\\C216;" "\\C2;" str))
      )
      (vla-put-textstring obj str)
    )
  )
  (princ)
)

 

Hope this helps,
Henrique

EESignature

0 Likes
Message 10 of 26

msarqui
Collaborator
Collaborator

Gilsonrss : I am having some weird behavior in some cases. See attachment.

 

Henrique : You're right, your routine works, it is really fast and I don't have the weird behavior. Could you modify a little to ask the user to enter the old color number and after ask the new color number? Like Gilsonrss's routine do? If it's not too hard.

 

Thanks a lot!

0 Likes
Message 11 of 26

Kent1Cooper
Consultant
Consultant

@Anonymous wrote:

....

(while (vl-string-search (strcat "\\C" (itoa oldColor)) txt)
(setq txt (vl-string-subst (strcat "\\C" (itoa newColor)) (strcat "\\C" (itoa oldColor)) txt))
....


One thing that needs to be adjusted about that:

 

If you ask for it to change, for example, color 1 to color 25, the red parts above will also change color 11 to color 251, and color 125 to color 2525 [which surprisingly doesn't result in an error, but just voids the color assignment].  If you ask it to change color 1 to color 11, it will get stuck in an endless loop, trying to change 1 to 11 and then 11 to 111 and then 111 to 1111, and so on.

 

Color assignment codes have a semicolon after the color number, so the lines above can be changed to include that, and look at only completed color numbers:

....

(while (vl-string-search (strcat "\\C" (itoa oldColor) ";") txt)
  (setq txt (vl-string-subst (strcat "\\C" (itoa newColor) ";") (strcat "\\C" (itoa oldColor) ";") txt))

....

Kent Cooper, AIA
Message 12 of 26

Anonymous
Not applicable

Sorry.

 

Carelessness on my part

 

following correction

 

(vl-load-com)
(defun c:12 ( / )
(if (and (setq oldColor (getint "\nEnter the old color number:"))
(<= 0 oldColor 256)
(setq newColor (getint "\nEnter the new color number:"))
(<= 0 newColor 256)
(princ "\nSelect the Mtext to change color")
(setq ss (ssget "_:L" '((0 . "MTEXT"))))
)

(repeat (setq i (sslength ss))
(setq en (ssname ss (setq i (1- i))))
(setq el (entget en (list "*")))
(setq new_el nil)
(foreach par el
(if (or (= (car par) 3) (= (car par) 1))
(progn
(setq txt (cdr par))
(while (vl-string-search (strcat "\\C" (itoa oldColor) ";") txt)
(setq txt (vl-string-subst (strcat "\\C" (itoa newColor) ";") (strcat "\\C" (itoa oldColor) ";") txt))
)
(setq par (cons (car par) txt))
)
)
(setq new_el (append new_el (list par)))
)
(entmod new_el)
)
)
(princ)
)

 

 

Gilson

Message 13 of 26

msarqui
Collaborator
Collaborator
Gilsonrss,
I am doing some tests. So far so good!
0 Likes
Message 14 of 26

hmsilva
Mentor
Mentor
Accepted solution

@msarqui wrote:

Henrique : You're right, your routine works, it is really fast and I don't have the weird behavior. Could you modify a little to ask the user to enter the old color number and after ask the new color number? Like Gilsonrss's routine do? If it's not too hard.


Hi msarqui,

I didn'd see your reply, sorry.

 

Like Gilson's routine... (sorry for borrowing your code Gilson)

 

(vl-load-com)
(defun c:demo (/ new obj old ss str)
  (if (and (setq old (getint "\nEnter the old color number:"))
	   (<= 0 old 256)
	   (setq new (getint "\nEnter the new color number:"))
	   (<= 0 new 256)
	   (princ "\nSelect Mtext object to change color: ")
	   (setq ss (ssget "_:L" '((0 . "MTEXT"))))
      )
    (repeat (setq i (sslength ss))
      (setq obj	(vlax-ename->vla-object (ssname ss (setq i (1- i))))
	    str	(vla-get-textstring obj)
      )
      (while (vl-string-search (strcat "\\C" (itoa old) ";") str)
	(setq str (vl-string-subst
		    (strcat "\\C" (itoa new) ";")
		    (strcat "\\C" (itoa old) ";")
		    str
		  )
	)
      )
      (vla-put-textstring obj str)
    )
  )
  (princ)
)

 

Hope this helps,
Henrique

EESignature

Message 15 of 26

msarqui
Collaborator
Collaborator

Hello!


Both routines tested, both are really good.


Gilson's routine have yet some text that insists on not to change. Henrique's routine do the change everywhere.
Thanks for your help, it saved-me hundreds hours of work.

0 Likes
Message 16 of 26

hmsilva
Mentor
Mentor

@msarqui wrote:

Gilson's routine have yet some text that insists on not to change.


@Anonymous 

 

Gilson's routine, using AUTO LISP, is limited to 250 characters, if a string have more then 250 characters, the string will be divided in multi strings, associated to dxf 3 with 250 characters, and the last string to dxf 1.

Using the AUTO LISP approach, we'll have to test the dxf 3 existence, strcat the sub-strings in one, change the color, divide the string in sub-strings with 250 characters, subst each dxf 3 and the dxf1, entmode.... many lines of code...

That's why I chose to use the VL approach.

 


@msarqui wrote:

Henrique's routine do the change everywhere.
Thanks for your help, it saved-me hundreds hours of work.


You're welcome, msarqui
Glad I could help

Henrique

EESignature

0 Likes
Message 17 of 26

msarqui
Collaborator
Collaborator

Hi Henrique,

 

I modified a little the routine.
Now it also includes to modify a TEXT and a single line ATTRIBUTE. The problem is, if I have a block, I need to enter in the BLOCKEDITOR to modify the colors.

 

My first question is: Is it possible to modify the colors of words contained in MTEXT, TEXT and single line ATTRIBUTE without entering the BLOCKEDITOR?
Just remember: in a MTEXT the change is made to the word/words containing the specified color. In a TEXT and single line ATTRIBUTE, the change is made to the hole TEXT or ATTRIBUTE.

 

My second question is: would it be possible to include to change the color of the words contained in a multiple lines ATTRIBUTE?
In this case, the change is made in the word/words containing specified color, like in a MTEXT.

 

Many thanks,

Marcelo

 

 

(defun c:ChangeTextColor (/ new obj old ss str)
(if (and (princ "\n Select Text, Mtext or Attribute object to change its color: ")
  (setq ss (ssget "_:L" '((0 . "MTEXT,TEXT,ATTDEF"))))
  (setq old (getint "\n Enter the old color number:"))
  (<= 0 old 256)
  (setq new (getint "\n Enter the new color number:"))
  (<= 0 new 256)  
 );and

 (progn
  (setq ssM (ssget "_P" '((0 . "MTEXT")))) 
  (command "_.select" ss "")
  (setq ssT (ssget "_P" (list (cons 0 "TEXT,ATTDEF")(cons 62 old))))

  (if ssM ;MTEXT
  (repeat (setq i (sslength ss))
   (setq obj (vlax-ename->vla-object (ssname ss (setq i (1- i))))
   str (vla-get-textstring obj)
   );setq obj
   (while (vl-string-search (strcat "\\C" (itoa old) ";") str)
   (setq str (vl-string-subst
     (strcat "\\C" (itoa new) ";")
     (strcat "\\C" (itoa old) ";")
     str
     );vl
   );setq str
   );while
   (vla-put-textstring obj str)
  );repeat
    );if ssM ;MTEXT
  
  (if ssT ;TEXT or ATTRIBUTE
  (command "_.chprop" ssT "" "c" new "")
  );if ssT ;TEXT
  
 );progn

);if and
(princ)
)

0 Likes
Message 18 of 26

hmsilva
Mentor
Mentor

Hi Marcelo,
do you need to change Text/Mtext inside the blocks, or Attribut Text/MText color?


Dealing with attributes, we can change each "INSERT" Attribute Text/MText independently, but you'll have to take into account, ATTSYNC will synchronize the Text/Mtext Attributes with the table defined Attribute...


As you have said, you need to go to block editor to change the Text/MText... do you have multiple blocks with the same attribute string?

 

Cheers

Henrique

EESignature

0 Likes
Message 19 of 26

hmsilva
Mentor
Mentor

Marcelo,

let's see if I did understood your goal...

 

(vl-load-com)
(defun c:ChangeTextColor (/ ch_str_color attlst new i obj objn old ss)

  (defun ch_str_color (str old new /)
    (while (vl-string-search (strcat "\\C" (itoa old) ";") str)
      (setq str (vl-string-subst
                  (strcat "\\C" (itoa new) ";")
                  (strcat "\\C" (itoa old) ";")
                  str
                );vl
      );setq str
    );while
    str
  );;ch_str_color

  (if (and (princ "\n Select Text, Mtext or Attribute object to change its color: ")
           (setq ss (ssget "_:L"
                           '((-4 . "<OR")
                             (0 . "MTEXT,TEXT")
                             (-4 . "<AND")
                             (0 . "INSERT")
                             (66 . 1)
                             (-4 . "AND>")
                             (-4 . "OR>")
                            )
                    )
           )
           (setq old (getint "\n Enter the old color number: "))
           (<= 0 old 256)
           (setq new (getint "\n Enter the new color number: "))
           (<= 0 new 256)
      );and
    (repeat (setq i (sslength ss))
      (setq obj  (vlax-ename->vla-object (ssname ss (setq i (1- i))))
            objn (vla-get-objectname obj)
      );setq
      (cond ((= objn "AcDbMText")
             (vla-put-textstring obj (ch_str_color (vla-get-textstring obj) old new))
            )
            ((and (= objn "AcDbText")
                  (= (vla-get-color obj) old)
             )
             (vla-put-color obj new)
            )
            ((= objn "AcDbBlockReference")
             (setq attlst (vlax-invoke obj 'GetAttributes))
             (foreach att attlst
               (if (= (vla-get-mtextattribute att) :vlax-false)
                 (if (= (vla-get-color att) old)
                   (vla-put-color att new)
                 )
                 (vla-put-textstring att (ch_str_color (vla-get-textstring att) old new))
               )
             )
            )
      );; cond
    );repeat
  );if and
  (princ)
)

 

Hope this helps,
Henrique

EESignature

0 Likes
Message 20 of 26

msarqui
Collaborator
Collaborator

Hi Henrique,

 

This is almost perfect.

Please, see the image attached. I tried to attach the CAD file, but it has more than 5mb and the site does not allow me.

 

So, I tested your routine and:

 

It changes multi line ATTRIBUTE colors inside a block, this is perfect and there is nothing to change here.

 

It changes single line ATTRIBUTE colors but, when I insert te same block to verify, the ATTRIBUTE color is still the old one. The nuance here is, in this particular case, I would like to change the color of the ATTRIBUTE itself, inside the block. This will change all INSERT copies of this block. It is like if I enter in the BLOCKEDITOR and I change the color of the ATTRIBUTE.

 

It changes MTEXT and TEXT colors, this is perfect and there is nothing to change here. But, if the MTEXT or TEXT is inside a block, it does not work. Is that possible to add this feature?

 

Thanks

 

0 Likes