pman860507 Posted August 18, 2011 Posted August 18, 2011 This is only used for Inserted block's Mtext and Text. The problem i am having is If the item is Text then it will only replace the text of the last object since im using (setq ss1 (ssget "L")) there is also (entlast) but it does the same thing just gets the last entity created. is there a way to get all of them without having to select the copied text. Then a while loop to edit each one. Thanks Lisp file: (defun sVars() (setq text_edit(get_tile "text_edit")) (princ)) (defun edit () (setq dcl_id (load_dialog "copy_blk.dcl")) (if (not (new_dialog "copy_blk" dcl_id) ) (exit)) (set_tile "text_edit" temp1) (mode_tile "text_edit" 3) (action_tile "cancel" "(setq ddiag 1)(done_dialog 0)") (action_tile "accept" "(setq ddiag 2)(sVars)(done_dialog 1)") (start_dialog) (unload_dialog dcl_id) (if (= ddiag 1) (progn (setq newval temp1) (princ "\n Command cancelled\n") (exit))) (if (= ddiag 2) (progn (setq newval text_edit) (princ "\n Text Changed\n"))) (princ)) (defun C:Copy_blk (/ blkType INDEX COUNT en2 enlist temp temp1 enlist2 ins newblk newblk2 newent newent2 newval ss en newentlist2 ss1 INDEX1) (vl-load-com) (setq acadObject (vlax-get-acad-object)) (defun *Error* (Msg) (cond ((member Msg '("Function cancelled" "quit / exit abort"))) ((princ (strcat "Error: " Msg)) (princ "\nRestoring System Variables ") (terpri))) (princ)) (if (setq ss(ssget "_:L" '((0 . "INSERT,TEXT,MTEXT")))) (progn (setq INDEX1 -1) (setq en (ssname ss (setq INDEX1 (1+ INDEX1)))) (setq enlist(entget en)) (setq ins(cdr(assoc 10 enlist))) (command "copy" ss "" ins pause) (setq ss1 (ssget "L")) (setq INDEX -1 COUNT 0) (while (setq en1 (ssname ss1 (setq INDEX (1+ INDEX)))) (setq enlist1(entget en1)) (setq blkType(cdr(assoc 0 enlist))) (if (= blkType "INSERT") (progn (if(= (cdr(assoc 66 enlist)) 1) (progn (setq en2(entnext en1)) (setq enlist2(entget en2)) (setq temp1 (cdr (assoc 1 enlist2))) (edit) (setq enlist2 (subst (cons 1 newval)(assoc 1 enlist2)enlist2)) (entmod enlist2))))) (if (or(= blkType "TEXT")(= blkType "MTEXT")) (progn (setq temp1 (cdr (assoc 1 enlist1))) (edit) (setq enlist1 (subst (cons 1 newval)(assoc 1 enlist1)enlist1)) (entmod enlist1)))))) (princ)) DCL file: copy_blk : dialog { label = "Edit value of object"; initial_focus = "text_edit"; :column{ spacer; : edit_box { label = "Enter value:"; key = "text_edit"; edit_width = 75; edit_limit = 256; alignment = centered; allow_accept = true; } spacer; :row{ : button{ key = "accept"; label = "Ok"; is_default = true; edit_width = 1; alignment = centered; } :button{ key = "cancel"; label = "Cancel"; is_default = false; is_cancel = true; edit_width = 1; alignment = centered; } } } } Quote
BlackBox Posted August 18, 2011 Posted August 18, 2011 Welcome to CADTutor! To clarify: Using "L" as the sel-method in an ssget statement will create a selection set of the last visible object added to the database. Using "_:L" as the sel-method, will prompt the user to select objects who's layer(s) are unlocked. Perhaps you would benefit from the vla-copy Method, instead of repeated (command "._copy"... calls. Also, consider using a cond statement in lieu of multiple if statements. HTH Quote
pman860507 Posted August 18, 2011 Author Posted August 18, 2011 I consider my self a beginner to LISP and i find my self always using IF statments. Whats the pro's in using cond. also i dont know anything about Visual Lisp. I have read a few things on it when i need it but nothing i ever remember. i will look at the vla-copy. Quote
BlackBox Posted August 18, 2011 Posted August 18, 2011 I consider my self a beginner to LISP and i find my self always using IF statments. Whats the pro's in using cond. Cond is great when you need to test for multiple conditions (aptly named). As a quick example: (defun c:FOO ( / opt) (if (and (not (initget 1 "This tHat Other")) (setq opt (strcase (getkword "\nEnter an option [This/tHat/Other]: ")))) (prompt (strcat "\nYou entered: " (cond ((= "THIS" opt) "THIS ") ((= "THAT" opt) "THAT ") ((= "OTHER" opt) "OTHER "))))) (terpri) (princ)) Edit: Note that I purposely used the explicit text "THIS," "THAT," or "OTHER" for this example, normally if using a variable with said value, you'd just use the variable. See the developer documentation for more information. also i dont know anything about Visual Lisp. I have read a few things on it when i need it but nothing i ever remember. i will look at the vla-copy. No worries; we'll revisit Visual LISP later... it took me some time to get into the vl* functions, then it became my preference. Quote
pman860507 Posted August 18, 2011 Author Posted August 18, 2011 cool i will look into cond after i figure out how to automatically add the new objects that are copied to an entity or a selection set. Quote
BlackBox Posted August 18, 2011 Posted August 18, 2011 cool i will look into cond after i figure out how to automatically add the new objects that are copied to an entity or a selection set. Consider the ssadd function: (setq newSS (ssadd (entlast))) Quote
Lee Mac Posted August 18, 2011 Posted August 18, 2011 Another advantage of COND over multiple non-nested IF statements is that upon a test condition returning a non-nil value, no other test conditions are needlessly evaluated. For example: (defun c:test ( / num ) (if (setq num (getint "\nEnter a Number: ")) (cond ( (minusp num) (princ "\nYou Entered a Negative Number.") ) ( (zerop num) (princ "\nYou Entered Zero.") ) ( (= 3 num) (princ "\nYou Entered the Number 3.") ) ( t (princ "\nYou Enter a Positive Non-zero Number not equal to 3.") ) ) ) (princ) ) Instead of: (defun c:test ( / num ) (if (setq num (getint "\nEnter a Number: ")) (progn (if (minusp num) (princ "\nYou Entered a Negative Number.") ) (if (zerop num) (princ "\nYou Entered Zero.") ) (if (= 3 num) (princ "\nYou Entered the Number 3.") ) (if (not (or (minusp num) (zerop num) (= 3 num))) (princ "\nYou Enter a Positive Non-zero Number not equal to 3.") ) ) ) (princ) ) Since only one of the conditions can return T, it makes no sense to evaluate any other condition after a test condition has returned T. COND has the same order of evaluation as a set of nested IF statements, the "If/Else If" structure that you may see in other languages (the 'switch' statement found in other languages is also similar): (defun c:test ( / num ) (if (setq num (getint "\nEnter a Number: ")) (if (minusp num) (princ "\nYou Entered a Negative Number.") (if (zerop num) (princ "\nYou Entered Zero.") (if (= 3 num) (princ "\nYou Entered the Number 3.") (princ "\nYou Enter a Positive Non-zero Number not equal to 3.") ) ) ) ) (princ) ) But I think you'll agree the COND statement is far more readable. Lee Quote
pman860507 Posted August 18, 2011 Author Posted August 18, 2011 I do agree the cond statement is easier to read. It also make since to use then your program doesn't have to evaluate each if statement. making it run a little quicker. if i use (setq newSS (ssadd (entlast))) It only gets the last object put into the database. I want to use a multi line of dtext then it will only select one of the lines (which ever is put in last). Quote
BlackBox Posted August 18, 2011 Posted August 18, 2011 Perhaps this example will clarify: (defun c:FOO ( / ss e ss2) (if (setq ss (ssget "_:L")) (progn [color=blue](setq e (entlast))[/color] [color=red](command "._copy" ss "" '(0 0 0) '(0 0 0))[/color] (while (/= nil [color=seagreen](setq e (entnext e))[/color]) (setq ss2 (ssadd e (cond (ss2) ((setq ss2 (ssadd (entnext e)))))))) (sssetfirst nil ss2)) (prompt "\n** Nothing selected ** ")) (princ)) Note the order of entlast, the copy operation, then the subsequent entnext calls. Here's another way to do the same with less declared variables: (defun c:FOO (/ ss) (if (setq ss (ssget "_:L")) ((lambda (e / ss2) [color=red](command "._copy" ss "" '(0 0 0) '(0 0 0))[/color] (while (/= nil [color=seagreen](setq e (entnext e))[/color]) (setq ss2 (ssadd e (cond (ss2) ((setq ss2 (ssadd (entnext e)))))))) (sssetfirst nil ss2)) [color=blue] (entlast)[/color]) (prompt "\n** Nothing selected ** ")) (princ)) HTH Quote
BlackBox Posted August 18, 2011 Posted August 18, 2011 I will add though, having re-read some of your code... instead of making a selection set of the resultant copied items, then stepping through the secondary selection set... simply take action on the entities during the while loop itself. Less iteration. I'll post an example shortly. Quote
BlackBox Posted August 18, 2011 Posted August 18, 2011 I was thinking of a framework like this: (defun c:FOO (/ ss) (vl-load-com) (if (setq ss (ssget "_:L" '((-4 . "<OR") (-4 . "<AND") (0 . "INSERT") (66 . 1) (-4 . "AND>") (0 . "MTEXT,TEXT") (-4 . "OR>")))) ((lambda (e / typ eData) (command "._copy" ss "" '(0 0 0) '(0 0 0)) (while (/= nil (setq e (entnext e))) (cond ((= "INSERT" (setq typ (cdr (assoc 0 (setq eData (entget e)))))) [color=red];; <- Do something to the attributed block[/color] ) ((vl-position typ '("MTEXT" "TEXT")) [color=red];; <-Do something to Mtext & Text[/color] ) ) ) ) (entlast)) (prompt "\n** Nothing selected ** ")) (princ)) ... Forgive me, as I do not have time right now (I'm at work), to incorporate the rest of your code. HTH Quote
pman860507 Posted August 18, 2011 Author Posted August 18, 2011 I hope this helps you some. this was what i was doing. Selecting objects Getting the entity of the first object selected grabbing the insertion point (for copy command) running the copy command now i need to be able to break down all the objects that where copied. (my problem i can only get one.) i have a while loop to go though them all but i can only get one of the copied objects. then the text is changed and object is updated. Quote
BlackBox Posted August 18, 2011 Posted August 18, 2011 Right, so given 100 items selected, you will invoke the copy command 100 times, then take the action on each item. What I am suggesting you do (as shown in the pseudo code I just posted) is to Create a selection set Store the last entity (setq e (entlast)) COPY the entire selection set ONCE THEN iterate through the new entities using (entnext e) CONDitionally take action on each entity iterated Your code will be MUCH more efficient, especially given the command call. Simply perform your entity modification(s) within the COND statement. I hope this makes sense to you? Quote
pman860507 Posted August 18, 2011 Author Posted August 18, 2011 Right, so given 100 items selected, you will invoke the copy command 100 times, then take the action on each item. What I am suggesting you do (as shown in the pseudo code I just posted) is to Create a selection set Store the last entity (setq e (entlast)) COPY the entire selection set ONCE THEN iterate through the new entities using (entnext e) CONDitionally take action on each entity iterated Your code will be MUCH more efficient, especially given the command call. Simply perform your entity modification(s) within the COND statement. I hope this makes sense to you? I was thinking of a framework like this: (defun c:FOO (/ ss) (vl-load-com) (if (setq ss (ssget "_:L" '((-4 . "<OR") (-4 . "<AND") (0 . "INSERT") (66 . 1) (-4 . "AND>") (0 . "MTEXT,TEXT") (-4 . "OR>")))) ((lambda (e / typ eData) (command "._copy" ss "" '(0 0 0) '(0 0 0)) (while (/= nil (setq e (entnext e))) (cond ((= "INSERT" (setq typ (cdr (assoc 0 (setq eData (entget e)))))) [color=red];; <- Do something to the attributed block[/color] ) ((vl-position typ '("MTEXT" "TEXT")) [color=red];; <-Do something to Mtext & Text[/color] ) ) ) ) (entlast)) (prompt "\n** Nothing selected ** ")) (princ)) ... Forgive me, as I do not have time right now (I'm at work), to incorporate the rest of your code. HTH I dont know what the lambda function does (i guess it Defines an anonymous function) still lost on that part. so im kind of lost. i will read some more on lambda. I'm pretty sure thats the only part i dont understand. it looks like e is the entity. and edata is the data in the entity? dont know what the (0 0 0) does in copy. the ._copy actually doesnt work for me only the (command copy) Quote
BlackBox Posted August 18, 2011 Posted August 18, 2011 I dont know what the lambda function does (i guess it Defines an anonymous function) still lost on that part. so im kind of lost. i will read some more on lambda. I'm pretty sure thats the only part i dont understand. You are correct that lambda is an anonymous function, but that is not important. TO remove confusion, let's just use this: Edit: Guess it would help if I post that revised code, huh!? LoL (defun c:FOO (/ ss e typ eData) (vl-load-com) (if (setq ss (ssget "_:L" '((-4 . "<OR") (-4 . "<AND") (0 . "INSERT") (66 . 1) (-4 . "AND>") (0 . "MTEXT,TEXT") (-4 . "OR>")))) (progn (setq e (entlast)) (command "._copy" ss "" '(0 0 0) '(0 0 0)) (while (/= nil (setq e (entnext e))) (cond ((= "INSERT" (setq typ (cdr (assoc 0 (setq eData (entget e)))))) [color=red];; <- Do something to the block[/color] ) ((vl-position typ '("MTEXT" "TEXT")) [color=red];; <-Do something to Mtext & Text[/color] ) ) ) ) (prompt "\n** Nothing selected ** ")) (princ)) it looks like e is the entity. and edata is the data in the entity? Also correct. dont know what the (0 0 0) does in copy. '(0 0 0) specifies the origin, and instead of stepping through each entity in your selection set, then extracting the DXF 10 coordinate, then invoking the copy command, my version simply copies the entire selection set in place (from origin -> origin, i.e., no displacement) once... instead of multiple times, once for each entity. That's all. the ._copy actually doesnt work for me only the (command copy) This I find to be strange. The preceding period, and underscore "._" simply mean that the English version of the core AutoCAD command are to be used, as any AutoCAD command can be redefined. I do not yet have 2012 software installed, or I would test. But I can assure you that that should pose no issue. Quote
pman860507 Posted August 18, 2011 Author Posted August 18, 2011 I think i understand it now. where you have ;; is where you will go the edata and pull out what you need correct? Quote
BlackBox Posted August 18, 2011 Posted August 18, 2011 I think i understand it now. where you have ;; is where you will go the edata and pull out what you need correct? Correct. That is where you should include your code, which takes action(s) on that entity type ("INSERT", or "MTEXT,TEXT") respectively. Quote
Lee Mac Posted August 18, 2011 Posted August 18, 2011 (defun c:FOO (/ ss) (if (setq ss (ssget "_:L")) ((lambda (e / ss2) [color=black](command "._copy" ss "" '(0 0 0) '(0 0 0))[/color] (while (/= nil [color=black](setq e (entnext e))[/color]) [color=red] (setq ss2 (ssadd e (cond (ss2) ((setq ss2 (ssadd (entnext e))))))))[/color] (sssetfirst nil ss2)) [color=black] (entlast))[/color] (prompt "\n** Nothing selected ** ")) (princ)) A quick FYI, SelectionSets, like Entity Names and VLA-Objects, act like 'pointers' in that you don't have to reassign the variable when the data is manipulated, e.g. (defun c:foo ( / en s1 s2 ) (if (setq s1 (ssget "_:L")) (progn (setq en (entlast) s2 (ssadd)) (command "_.copy" s1 "" "_non" '(0. 0. 0.) "_non" '(0. 0. 0.)) (while (setq en (entnext en)) (ssadd en s2)) (sssetfirst nil s2) ) ) (princ) ) :wink: Quote
BlackBox Posted August 19, 2011 Posted August 19, 2011 Thanks Lee, I also realized that if I was going to use lambda, I could also have supplied the initial (sssdd) as an argument. Quote
pman860507 Posted August 19, 2011 Author Posted August 19, 2011 I have not looked at what you have posted still eating my eggs, i wanted to say Thanks to Lee Mac. I went to your webpage and incorporated the screenpoint for DCL into my command it works great. 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.