I am attempting to add several new attributes to every block in my drawing with autolisp. Currently, adding them all left aligned is working perfectly. However, when I try to add the attributes and then center or right align them, it causes a staircase effect.
I create my new attribute att, and then center it
(setq apt (vla-get-insertionpoint att)) (vla-put-alignment att acalignmentcenter) (vla-put-textalignmentpoint att apt) (vla-update att)
But it looks like when I center it, the current insertion point (the left most side) becomes the center, and the new insertion point is the new leftmost side.
Left Aligned
Centered
Right Aligned
It appeared to me that the insertion point is based on the leftmost side of the text, so I figured if before I add an attribute, I change the value of the attribute above it to be blank, it would align how I want it to. It would align under the blank (or single character) value, then I would restore the text after the new attribute was inserted.
I manually edited the first attribute (Associated) using BATTMAN, changing the Default value to *, so I could see if this approach would work. I then added one value centered underneath. It worked, and New1 was created and centered underneath the *.
Replicating this in code has so far proved unsuccessful. I've used entmod, entupd, attsync, regen, attedit, and all have the same staircase result. It looks like the insertion point isn't changing/updating after I change the value programatically.
(setq placementAttribute (subst (cons 1 "*") (assoc 1 placementAttribute) placementAttribute )) (entmod placementAttribute) (command "-attedit" "N" "N" blk placementName "*" placementValue "l") (command "_.attsync" "_N" blk) (command "_.regen")
(Note: all these approaches were not attempted at the same time)
Does anyone have any advice as to how to update the insertion point of an attribute after changing it's value? Or any advice as to centering new attributes in a column in general?
Side note: While reading through Lee Mac's page about editing text here, I read this paragraph:
"When using an ObjectDBX interface to modify the content of attribute references which do not have justification set to 'Left', there is a known bug which results in the attribute position not being updated following a change to the text field length (e.g. extending the text content of middle-center justified attributes will cause the attributes to become positioned off-center to the right)."
I only started learning lisp last week, so I don't know what an ObjectDBX interface is, but could this be at all similar to my issue?
Solved! Go to Solution.
You might need to post more code .. I cannot replicate the issue you're seeing. Here is an image with two attributes added then changed to middle center justification and attsync.
I am adding and centering in a loop, so it looks like add new1, center new1, add new2, center new2. Are you adding all attributes and then centering them?
@Anonymous wrote:I am attempting to add several new attributes to every block in my drawing with autolisp. Currently, adding them all left aligned is working perfectly. However, when I try to add the attributes and then center or right align them, it causes a staircase effect.
I create my new attribute att, and then center it
(setq apt (vla-get-insertionpoint att)) (vla-put-alignment att acalignmentcenter) (vla-put-textalignmentpoint att apt) (vla-update att)
But it looks like when I center it, the current insertion point (the left most side) becomes the center, and the new insertion point is the new leftmost side.
Left Aligned
Centered
Right Aligned
It appeared to me that the insertion point is based on the leftmost side of the text, so I figured if before I add an attribute, I change the value of the attribute above it to be blank, it would align how I want it to. It would align under the blank (or single character) value, then I would restore the text after the new attribute was inserted.
I manually edited the first attribute (Associated) using BATTMAN, changing the Default value to *, so I could see if this approach would work. I then added one value centered underneath. It worked, and New1 was created and centered underneath the *.
Replicating this in code has so far proved unsuccessful. I've used entmod, entupd, attsync, regen, attedit, and all have the same staircase result. It looks like the insertion point isn't changing/updating after I change the value programatically.
(setq placementAttribute (subst (cons 1 "*") (assoc 1 placementAttribute) placementAttribute )) (entmod placementAttribute) (command "-attedit" "N" "N" blk placementName "*" placementValue "l") (command "_.attsync" "_N" blk) (command "_.regen")
You are getting the staircase effect because I assume you are getting the insertion point for the last attribute, calculating the new insertion point for the new attribute then setting it as the text alignment point. When you do this, a new "insertion point" is calculated as the BL point for the attribute. In a loop this will cause a staircase effect. You need to get the text alignment point and calculate the new point from that. Hope that makes sense.
I am not one of the robots you're looking for
Here's a loop example. Run this then attsync the block.
(defun c:foo (/ a bname pt n o p pt v) ;; RJP » 2018-08-30 ;; Enter your blockname here to test (setq bname "nameofyourblock") (cond ((and (setq e (tblobjname "block" bname)) (setq e (cdr (assoc 330 (entget e))))) (setq e (vlax-ename->vla-object e)) (setq n 0) (setq p '(0. 0. 0.)) (repeat 10 (setq v (strcat "MyTestAtt" (itoa n))) (setq a (vlax-invoke e 'addattribute 0.5 acattributemodepreset v p v v)) (setq pt (vla-get-insertionpoint a)) (vla-put-alignment a acalignmentcenter) (vla-put-textalignmentpoint a pt) (setq p (mapcar '- p '(0. 1. 0.))) (setq n (1+ n)) ) ) ) (princ) ) (vl-load-com)
If I understand your code, you are hard coding the original insertion point
(setq p '(0. 0. 0.))
And in the loop adding 1 to the y position, making the next attribute appear directly below it.
Insertion points are a little more complicated for me, as I am adding attributes under each other based off name (Insert new1 under associated, new2 under new1, etc). I have no idea going into the loop only knowing the name of the attribute I want to insert under.
Lets say I want to insert a new attribute called New1 under an existing attribute Associated.
I am getting placement position (associated insertion point) after editing the text value:
(command "-attedit" "N" "N" blk placementName "*" placementValue "0") (command "_.attsync" "_N" blk) (setq placementPosition (cdr (assoc 10 placementAttribute)))
I am calculating the insertion point of the new attribute by finding the offset of the block insertion point and the "placement" insertion point. (IE, if I want to insert new 1 below Associated, I find the insertion point of Associated, calculate the offset, add a spacing value to the y coordinate, and then use that point to place new1)
(setq x (- (car placementPosition) (car checkerposition))) (setq y (- (cadr placementPosition) (cadr checkerposition))) (setq y (- y offset))
I use the x and y value when I create the attribute - (vlax-3D-point x y). Checker position here is the coordinates of the block insertion point.
I thought that editing the placement attribute (Associated) to be blank, then getting its new insertion point would enable me to insert the new attribute (New1) below and center correctly. But even after I change Associated to be blank, the insertion point is still where the A was, not the new left-most point.
Is there some other way besides attsync to update an attribute, or is there something I'm overlooking while trying to get the new insertion point after editing the value?
Post your full code and an example drawing.
Maybe this will help you get your existing attribute location, then you can place your new one in relation to it.
(defun _getattcoord (bname extag / atts e i) ;; RJP » 2018-08-30 (cond ((and (setq e (tblobjname "block" bname)) (setq e (cdr (assoc 330 (entget e))))) (vlax-for x (vlax-ename->vla-object e) (if (= "AcDbAttributeDefinition" (vla-get-objectname x)) (setq atts (cons (cons (strcase (vla-get-tagstring x)) x) atts)) ) ) (cond ((setq i (cdr (assoc (strcase extag) atts))) (vlax-get i 'insertionpoint))) ) ) ) (vl-load-com) (_getattcoord "YourBlockName" "Associated") ;; Might return '(0. 0. 0.) .. or wherever it is located within the block definition
Right now, I'm just focused on getting different coordinates after changing a value, I'm not working in my main file. I provided previous code for context of how attributes were being placed.
Here is a rough example of the tests I'm running now:
(setq en (entnext en) ad (entget en) ) (if (eq (cdr (assoc 2 ad)) (MyField)) (setq placementAttribute ad) (setq placementPosition (cdr (assoc 10 ad))) ) ;;--------------------------------------------------------------------;; (princ "\nOriginal Position") (princ placementPosition) (command "_.attedit" "N" "N" "MyBlock" "MyField" "*" "Oldtext" "NewText") (command "_.regen") (command "_.attsync" "_N" "MyBlock") (setq placementPosition (cdr (assoc 10 placementAttribute))) (princ "\nNEW Position") (princ placementPosition)
But the Original and New position are exactly the same.
Command: Original Position(-48.1697 -8.69546 2.75335e-14) -attedit Edit attributes one at a time? [Yes/No] <Y>: N Performing global editing of attribute values. Edit only attributes visible on screen? [Yes/No] <Y>: N Drawing must be regenerated afterwards. Enter block name specification <*>: Test_Block Enter attribute tag specification <*>: Associated Enter attribute value specification <*>: * 1 attributes selected. Enter string to change: Enter new string: 0 Command: _.regen Regenerating model. Command: _.attsync Enter an option [?/Name/Select] <Select>: _N Enter name of block to sync or [?]: Test_Block ATTSYNC complete. Command: NEW Position(-48.1697 -8.69546 2.75335e-14)
I then thought that maybe the way I was getting the coordinates was faulty, maybe since placementAttribute was an old reference it wasn't updated, so I looked into vla-get-InsertionPoint, but using that I'm getting the exact same coordinates. I added this below the attsync command:
(setq testEntity (vlax-ename->vla-object testplacemententity)) (setq currInsertionPoint (vlax-safearray->list (vlax-variant-value (vla-get-InsertionPoint testEntity))))
(princ (strcat "The insertion point of the text is " (rtos (nth 0 currInsertionPoint) 2) ", "
(rtos (nth 1 currInsertionPoint) 2) ", "
(rtos (nth 2 currInsertionPoint) 2)))
But that give me the same coordinates. "The insertion point of the text is -48.6697, -8.6955, 0.0000"
Is it possible to change an attributes text value and get its updated coordinates / new insertion point right afterwards? Is the way I'm getting the insertion point after editing incorrect?
Sorry .. I'm not following what you're describing. Pleeease post a sample drawing with desired result.
Also, we might be talking about two different things here:
;; Within 'insert'
"IAcadAttributeReference"
;; Within block definition
"AcDbAttributeDefinition"
I have figured out what I was doing wrong. I was using the DXF code 10 for all insertions, when I should have been using the DXF 11 code when an attribute was not left aligned.
I used 1 for left aligned, 2 for center, and 3 for right aligned in my newAttrib list.
(cond ((eq 1 (atoi(nth 8 newAttrib))) ;If the alignment is left (progn (setq placementPosition (cdr (assoc 10 ad)))) ) ((eq 2 (atoi(nth 8 newAttrib))) ;If the alignment is center (progn (setq placementPosition (cdr (assoc 11 ad)))) ) ((eq 3 (atoi(nth 8 newAttrib))) ;If the alignment is right (progn (setq placementPosition (cdr (assoc 11 ad)))) ) (t (setq placementPosition (cdr (assoc 10 ad)))) ;Else, get the dxf 10 code )
Thank you to everyone who replied to this post
Hello ,
I have kind of similar needs,
I can't figure out how to define my attributes alignment as center.
Someone now what is not working with (vla-put-Alignment def acAlignmentCenter) in my code?
(defun c:kad2 ( / ss i blk blks def )
(and
(setq ss (ssget '((0 . "INSERT"))))
(setq i (sslength ss))
(while (> i 0)
(setq blk (cdr (assoc 2 (entget (ssname ss (setq i (1- i)))))))
(if (not (vl-position blk blks))(setq blks (cons blk blks)))
)
)
(foreach blk blks
(setq def (vla-item (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object))) blk))
(vla-addattribute def
;------------ATTRIBUT 01 ---------------------------------------------------
3
acattributemodelockposition
"DENOMBREMENT"
(vlax-3D-point 0 +9)
;(vlax-put def 'Alignment 4) -NOT WORKING
;(vla-put-Alignment def acAlignmentCenter) -NOT WORKING
;(vla-put-Alignment def acAlignmentMiddleCenter) -NOT WORKING
"DENOMBREMENT"
"xxxx"
)
(command "_.attsync" "_N" blk)
)
(princ)
)
(vl-load-com) (princ)
Thank in advance.
Dany
When changing the Alignment property you also have to change the either the textalignmentpoint property or the insertionpoint property.
When moving from left aligned to center aligned make the text alignmentpoint property the same as the insertionpoint property.
When moving to left alignment make the insertionpoint property the same as the textalignmentpoint property.
Both of these need to be changed AFTER you have set the new alignment property.
I am not one of the robots you're looking for
Thanks I'm sorry but I don't know to code it properly ,
You are talking about this line ?(vlax-3D-point 0 +9) as insertionpoint?
(foreach blk blks
(setq def (vla-item (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object))) blk)) ;DEF is the block to which you are adding the attribute
(setq pt (vlax-3D-point 0. 9. 0.)) ;set the insertionpoint separately
; This is the layout for vla-addattribute
; RetVal = (vla-addattribute obj Height Mode PromptString InsertionPoint NewAttributeTagname NewAttributeDefaultValue)
(setq natt (vla-addattribute def 3 acattributemodelockposition "DENOMBREMENT" pt "DENOMBREMENT" "xxxx")); This now returns the object of the new attribute
;You then need to work on the properties of the new attribute, not the block
(vlax-put-property natt 'alignment acAlignmentCenter); or acAlignmentMiddleCenter
(vlax-put-property natt 'textalignmentpoint pt) ;set the textalignmentpoint to the insertionpoint
;You could shorten the two lines above to
(mapcar '(lambda (x y) (vlax-put-property natt x y)) (list 'alignment 'textalignmentpoint) (list acAlignmentCenter pt))
)
I am not one of the robots you're looking for
Hmmm.. I've tried to insert it in few ways,but seems to not working in every ways I've tried.. 😓
(defun c:testkad ( / ss i blk blks def )
(and
(setq ss (ssget '((0 . "INSERT"))))
(setq i (sslength ss))
(while (> i 0)
(setq blk (cdr (assoc 2 (entget (ssname ss (setq i (1- i)))))))
(if (not (vl-position blk blks))(setq blks (cons blk blks)))
)
)
(foreach blk blks
(setq def (vla-item (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object))) blk))
(vla-addattribute def
;------------ATTRIBUT 01 ---------------------------------------------------
3
acattributemodelockposition
"DENOMBREMENT"
(setq pt (vlax-3D-point 0 +9))
"DENOMBREMENT"
"xxxx"
)
RetVal = (vla-addattribute obj Height Mode PromptString InsertionPoint NewAttributeTagname NewAttributeDefaultValue)
(setq natt (vla-addattribute def 3 acattributemodelockposition "DENOMBREMENT" pt "DENOMBREMENT" "xxxx"))
(vlax-put-property natt 'alignment acAlignmentCenter)
(vlax-put-property natt 'textalignmentpoint pt)
(command "_.attsync" "_N" blk)
)
(princ)
)
(vl-load-com) (princ)
(defun c:testkad ( / ss i blk blks def )
(and
(setq ss (ssget '((0 . "INSERT"))))
(setq i (sslength ss))
(while (> i 0)
(setq blk (cdr (assoc 2 (entget (ssname ss (setq i (1- i)))))))
(if (not (vl-position blk blks))(setq blks (cons blk blks)))
)
)
(foreach blk blks
(setq def (vla-item (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object))) blk))
(setq pt (vlax-3D-point 0 +9))
(setq natt (vla-addattribute def 3 acattributemodelockposition "DENOMBREMENT" pt "DENOMBREMENT" "xxxx"))
(vlax-put-property natt 'alignment acAlignmentCenter)
(vlax-put-property natt 'textalignmentpoint pt)
(command "_.attsync" "_N" blk)
)
(princ)
)
(vl-load-com) (princ)
I am not one of the robots you're looking for
Thanks!!! just a last thing, I need to add 10 attributes under the first one.
I ve tried the code below, but only the first attribut is created 😓
Besides I cannot change the size of the characters anymore vla-addattribute def 3 -> 30
(defun c:testkad ( / ss i blk blks def )
(and
(setq ss (ssget '((0 . "INSERT"))))
(setq i (sslength ss))
(while (> i 0)
(setq blk (cdr (assoc 2 (entget (ssname ss (setq i (1- i)))))))
(if (not (vl-position blk blks))(setq blks (cons blk blks)))
)
)
(foreach blk blks
(setq def (vla-item (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object))) blk))
;------------ATTRIBUT 01 ---------------------------------------------------
(setq pt (vlax-3D-point 0 +9))
(setq natt (vla-addattribute def 10 acattributemodelockposition "DENOMBREMENT" pt "DENOMBREMENT" "xxxx")
;------------ATTRIBUT 02 ---------------------------------------------------
(setq pt (vlax-3D-point 0 +13))
(setq natt (vla-addattribute def 3 acattributemodelockposition "TYPE/CLASSE" pt "TYPE/CLASSE" "xxxx")
;------------ATTRIBUT 03 ---------------------------------------------------
(setq pt (vlax-3D-point 0 +17))
(setq natt (vla-addattribute def 3 acattributemodelockposition "TYPE/CLASSE" pt "TYPE/CLASSE" "xxxx")
(vlax-put-property natt 'alignment acAlignmentCenter)
(vlax-put-property natt 'textalignmentpoint pt)
(command "_.attsync" "_N" blk)
)
(princ)
)
(vl-load-com) (princ)
Can't find what you're looking for? Ask the community or share your knowledge.