super_troy Posted December 13, 2009 Posted December 13, 2009 hello all, i was wondering if someone could help me. i have 1000s of dwgs that i need to PDF. they come out in the format "filename(layoutname).pdf" there is a block, "titleblock" and it has the attribute "ATT" in each drawing i need to extract the revision information from the block in each drawing and rename the layout tab accordingly. how do i extract that attribute's value so i can rename the layouttab using the layout command? each file has 1 layout with 1 insertion of the block in the layout space. any help would be greatly appreciated. i tried manipulatinng other attribute orientated lisps but had no luck. thanks, Quote
Lee Mac Posted December 13, 2009 Posted December 13, 2009 Try this: (defun c:layName (/ bNme aNme lay ss att e) (vl-load-com) (setq bNme "TITLEBLOCK" aNme "ATT") (vlax-for lay (vla-get-layouts (vla-get-ActiveDocument (vlax-get-acad-object))) (if (and (not (eq "MODEL" (strcase (vla-get-Name lay)))) (setq ss (ssget "_X" (list (cons 0 "INSERT") (cons 2 bNme) (cons 66 1) (cons 410 (vla-get-Name lay)))))) (foreach att (vlax-invoke (vlax-ename->vla-object (ssname ss 0)) 'GetAttributes) (if (apply 'eq (mapcar 'strcase (list aNme (vla-get-TagString att)))) (if (vl-catch-all-error-p (setq e (vl-catch-all-apply 'vla-put-Name (list lay (vla-get-TextString att))))) (princ (strcat "\n** Error: " (vl-catch-all-error-message e) " **"))))))) (princ)) Quote
super_troy Posted December 14, 2009 Author Posted December 14, 2009 that works a treat thanks mate Quote
muthu123 Posted December 14, 2009 Posted December 14, 2009 Dear friend, Can you explain these code in detail which will help me to lean Vlisp. Try this: (defun c:layName (/ bNme aNme lay ss att e) (vl-load-com) (setq bNme "TITLEBLOCK" aNme "ATT") (vlax-for lay (vla-get-layouts (vla-get-ActiveDocument (vlax-get-acad-object))) (if (and (not (eq "MODEL" (strcase (vla-get-Name lay)))) (setq ss (ssget "_X" (list (cons 0 "INSERT") (cons 2 bNme) (cons 66 1) (cons 410 (vla-get-Name lay)))))) (foreach att (vlax-invoke (vlax-ename->vla-object (ssname ss 0)) 'GetAttributes) (if (apply 'eq (mapcar 'strcase (list aNme (vla-get-TagString att)))) (if (vl-catch-all-error-p (setq e (vl-catch-all-apply 'vla-put-Name (list lay (vla-get-TextString att))))) (princ (strcat "\n** Error: " (vl-catch-all-error-message e) " **"))))))) (princ)) Quote
bkm Posted December 14, 2009 Posted December 14, 2009 FYI, this is how you can do it using VBA (I'm lisp illiterate). For catching errors, its worthwhile upper-casing the name as well as exiting the sub if the attribute text is empty. This works assuming your titleblock is in paperspace and there is only one layout tab. Sub Rename_Layout_Tab() Dim aeEntity As AcadEntity Dim varAttributes As Variant Dim ThisAttribute As AcadAttributeReference Dim intCount As Integer Dim strDrawingNo As String Dim intArrayCount As Integer For Each aeEntity In ThisDrawing.PaperSpace If TypeOf aeEntity Is AcadBlockReference Then If UCase(aeEntity.EffectiveName) Like "TITLEBLOCK*" Then varAttributes = aeEntity.GetAttributes For intCount = LBound(varAttributes) To UBound(varAttributes) Set ThisAttribute = varAttributes(intCount) If ThisAttribute.TagString = "ATT" Then If ThisAttribute.TextString = "" Then Exit Sub strDrawingNo = ThisAttribute.TextString ThisDrawing.PaperSpace.Layout.Name = strDrawingNo End If Next intCount End If End If Next aeEntity End Sub Quote
Lee Mac Posted December 14, 2009 Posted December 14, 2009 Dear friend, Can you explain these code in detail which will help me to lean Vlisp. Muthu, I'm afraid I don't have the time to explain every element of the code, but I would recommend that you copy the code into the Visual LISP Editor in AutoCAD (VLIDE at command line), and use the help files in the VLIDE to understand every function that I have used - and then, if you are still stuck, ask about which part of the code you are stuck on. Lee Quote
Lee Mac Posted December 14, 2009 Posted December 14, 2009 that works a treat thanks mate You're welcome Mr Troy Quote
rvignacio Posted November 22, 2010 Posted November 22, 2010 hi lee mac, I had a similar issue above, but my case is extracting the layout to a single drawing (layout to drawing) I used the routine above and it works well for me and thanks for that. Could you be able to help if I need to extract the layout tabs and use the filenames from one block in two attributes. (ie attribute "att1" + "att2" and output will appear as ATT1-ATT2) Appreciate the help. Thanks, Rvignacio Quote
irneb Posted November 22, 2010 Posted November 22, 2010 Dear friend, Can you explain these code in detail which will help me to lean Vlisp. Just to clarify, if you want to understand only the "V"Lisp portion - it's a lot similar to btm's VBA example. Only major difference is that it's using lisp to call the same ActiveX objects' methods and properties. I'll disregard all the pure lisp portions, since I'm assuming you know ALisp already. So here goes: (vl-load-com) ensures that the VLisp extensions are loaded. It only needs to be called once per drawing, but it does nothing to call it again - just makes the code easier to copy to these forums, since not everyone would have such a call already in one of their lisps. (vlax-for is a function which steps through the items contained in an ActiveX collection (much like foreach does with lists). (vla-get-Layouts is a shorthand way of obtaining the Layouts property of an object (in this case the active document object, see later). The Layouts property contains a reference to a collection of layout objects. The "long-hand" way of writing this would be (vlax-get-property Object PropertyName). Or the slightly modified (undocumented) method your be (vlax-get Object PropertyName) - this way is nice when you want to convert some forms of data to pure lisp data. E.g. when the property contains an array, the later method will convert it to a list - otherwise you'll have to work with the variant/safearray returned. (vla-get-ActiveDocument gets the active drawing's object. It could again have been written using the long-hand vlax-get-property / vlax-get. (vlax-get-acad-object) gets an ActiveX reference to the AutoCAD application itself. So from the previous 4 portions the following is happening: Step through each layout contained in the layouts collection of the current drawing which acad has open. (vla-get-Name lay) returns the string containing the Tab's name. Same again it could have been written (vlax-get-property lay 'Name) or (vlax-get lay 'Name). (vlax-invoke ... 'GetAttributes) calls an object's GetAttributes method. This is the undocumented version. If the vlax-invoke-method or the short-hand vla-GetAttributes function was used it would return a variant containing a safearray - which makes it a bit more difficult to work with in lisp. The vlax-invoke converts that variant/safearray into a normal list - so you can directly use the foreach on it. (vlax-ename->vla-object (ssname ss 0)) converts the ename returned by ssname to an ActiveX object representing the entity. It can be seen as similar to the entget, but rather than the DXF data list you get an object reference. (vla-get-TagString att) gets the Tag name property of the attribute. (vl-catch-all-apply ... performs some action without crashing your routine, even if an ActiveX error occurs - which would otherwise stop the entire lisp function. (vl-catch-all-error-p ... checks if the value is an error. (vla-get-TextString att) returns the attribute's contents. From this you should be able to figure out 90% of the ActiveX portion of VLisp. In some instances it's easier to use than the old DXF methods, e.g. instead of doing (cdr (assoc 1 att)) you do (vla-get-TextString att). In most instances it's also more efficient, since entget obtains all the data of an entity and returns all of it in a list. Vlax-ename->vla-object only returns a reference to the entity's object interface, subsequent calls to get properties only queries that piece of the entities data - instead of using assoc to search through the list to find the relevant data. Calls to put property or run methods only affect that small piece of data, not the entire thing as entmod would have. To figure out how to work with ActiveX objects, you'll need to check the ActiveX reference of the developer help. There are simply too many different object types (each with their properties and methods) to explain here. The major difference to what you'd have been used to is the Object Oriented programming approach of ActiveX: an object contains its own data and actions which can be performed on it. So you ask an object: What is contained in property X by calling a get on that property. You can set (most of) the properties' values using a put, except if they're read-only. The methods are more like functions which can return a value (not necessarily) or modify the value(s) contained in one (or more) of the method's arguments. Usually methods modify an object, but that should not be considered a rule at all - it's more like a possibility. Properties nearly always modify the object when you put a new value to them, sometimes the property is a hidden aspect (e.g. Hyperlinks) or it could be the layer name on which the object is drawn. For some strange reason M$ (and also ADesk) had this "bright" idea to not stick consistently with the same design of the ActiveX library throughout. E.g. to get hold of the block definitions in a drawing you use the Blocks property. This returns a collection of blocks, so you can use the collection's Item method to get hold of a block definition through an index or through its name. Or you could step through the collection using vlax-for. But when you want to get hold of a block reference's attributes you have to use the GetAttributes method which returns an array of objects - which needs other ways of going through. If the attributes were simply a property pointing to a collection, it would have been a lot simpler. Unfortunately that's how it is, and that's how we're stuck with it. BTW, due to many of these inconsistencies (and ACad is no exception - nearly all other Windows programs have the same problems) M$ decided to redesign the library - that's the major reason behind DotNet (it's partially a replacement for ActiveX, with some added features). Not that ActiveX doesn't work anymore, it just won't get updated. As for VBA (which near-exclusively uses ActiveX) it's not even included in a normal ACad install anymore - you need to download an add-on from ADesk to use DVB files. M$ has discontinued it in totality, so I wouldn't advise going that route. If you like the VB language above Lisp, I'd highly recommend learning VB.Net - and as a start, port your old VBA stuff into VB.Net. The 2 languages are not miles different from each other, it's more the DotNet libraries as opposed to the ActiveX - even though VB.Net can still link to ActiveX as well. Your major difference is that your code will have to be compiled into DLL files for each major version of ACad - it's no longer an interpreted language like VBA and Lisp. Quote
irneb Posted November 22, 2010 Posted November 22, 2010 To get more than one attribute's value you'll need to check for the 2nd attribute tag name as well in the (if (apply 'eq .... line. Many ways of doing that, through wcmatch, using an or, going with a cond, etc. Quote
CADkitt Posted November 22, 2010 Posted November 22, 2010 @irneb Tnx for your post I learned a lot from it. But I always thought VBA was the way to go and lisp was dead. But lisp is still dead but visual lisp or activx is the way to go? Quote
irneb Posted November 22, 2010 Posted November 22, 2010 Uhmm ... I think you got the wrong end of the stick. Lisp is not dead at all, in fact there are whole communities of programmers who have even evolved it into a much more capable language than many of the "newer" languages. There's a few caveats to this: AutoLisp (which is what's used in AutoCAD) was taken from an extremely early (80's) version of the entire Lisp language. And then it was even chopped down at that stage. It has hardly grown with the other Lisps in existence (e.g. Common Lisp / Scheme). So it's been left in the dust in comparison to more recent inventions and improvements. ADesk has not updated lisp in many years, so lispers need to find new and novel ways to interact with Acad's newer features. All that said, ADesk would be shooting themselves in the foot if they kill it off: There's simply too much customizations already available through ALisp / VLisp. This is arguably the biggest reason ACad has become so popular. They don't really have any reason to remove it from ACad either, there's no licensing issues as with VBA - so it costs them nothing. Also the lisp interpreter was built in the days when programmers actually tried to make programs as efficient as possible (they had to with the extreme limitations of CPU / RAM) so it uses an inordinately small amount of the performance of ACad as a whole - thus it would not even make a dent in ACad's performance to remove it. As opposed to all that: M$ is the owner of VBA. If any company wants to add VBA capability to their product, they have to pay M$ a fee for each license sold. M$ has literally discontinued any new licenses of VBA. They only allow existing programs which had VBA to start with to continue using it. This is in part due to the alluded inconsistencies of ActiveX (the backbone behind VBA). M$ wants to have VSTA instead - the "new" VBA (but with a choice of VB.Net, C# or F# languages), but with a similar licensing scheme. VBA in relation to Lisp uses a lot more resources - thus removing it to make performance better makes more sense. There's a whole lot less existing customizations in VBA than Lisp. M$ has provided reasonably simple ways of converting from VBA to the new VB.Net - so even these customizations are not dead in the water. The new VB.Net / C# (or any DotNet capable language) creates more efficient add-ons than VBA (simply because of compiled code instead of interpreted), so it's a boon both ways. ADesk don't need to package anything for someone to be able to use Dot Net - they can get hold of a free VB.Net / C# IDE from M$. VBA is not optimized for 64bit environments, and due to its discontinuation by M$ will never be. So it's an extremely slow beast when running on 64bit - making ACad slow as well. For that reason ADesk has allowed their customers to download the plugin which makes VBA available, but for the vast majority (who don't use it) it's not something which hampers the performance. They have not bought license for VSTA though, which I'm not sure is the best move. The ActiveX is something slightly different, it's simply a set of libraries (like DLL files) which can be called in order for any programming language to interact with existing applications. M$ didn't discontinue this, but they're not updating and maintaining it either. Neither is ADesk, there's already huge gaps in the new functions & entity types which simply cannot work through ActiveX (also known as COM - Common Object Model). ALisp had some methods already which are capable of direct / raw manipulation of DWG objects - this is usually where Lisp is still capable where VBA fails. And then Lisp already has (through VLisp) the same capabilities which VBA had. There's even some attempts at implementing the DotNet libraries into lisp as well, which would make it surpass VBA by a large margin. But then just to throw another curve-ball: there's an implementation of Python inside ACad. Python's a newer language which some say is a better functional language than even the "original" functional language known as Lisp. And it comes standard with all the advanced programming features such as Object Orientation, not to mention it already works seamlessly with both ActiveX and DotNet. If someone makes a translator from A/VLisp into ACad Python, I can see many porting to that in favour of even VB.Net / C#. And if an integrated editor (such as VLIDE) is available, there should be no stopping it. Not to mention, it's code looks a whole lot less cryptic than lisp - yet still works in a similar way {those mapcar, lambda, apply, etc. functions are also in python} As I've stated in my previous post as well as here above, it's not such a huge task to convert from VBA to VB.Net. There are various tutorials showing how. And if you go with VB.Net the language is nearly the same in any case - thus very small learning curve. So don't be scared that you've wasted your time in VBA, what you've learned there can still be applied in VB.Net. Quote
CADkitt Posted November 24, 2010 Posted November 24, 2010 I btw don't know anything about VBA my colleagues asked me: Why are you doing lisp that is a dead script? I said because it can do what I want with it. But now I can throw it in there face that lisp owns VBA or something like that and vba is pretty much dead. Python would also be cool since I also use Blender.org and so one programming language to do them all would be handy. But I would like some python classes in programming since doing it from the interwebs and help is taking ages. Edit: Did some research on Python to Autocad. http://tomsthird.blogspot.com/2009/04/autocad-customization-search-to-replace.html But at the second blog part he gives up on drawing a circle.. Quote
irneb Posted November 24, 2010 Posted November 24, 2010 You may want to look into Kean Wamsley's blogs on how he's implemented an IronPython script engine into ACad: http://through-the-interface.typepad.com/through_the_interface/ironpython/ He's even got a sample script (type / copy direct into the command line) which steps through the ribbon panels and collapses them. And then a much more involved PY script for drawing pipes. The trick with using Python would be that you will either link through the ActiveX libraries or the DotNet libraries. So you'll need either / both of those as help files - which would show you how in VB / C#, in which case you need to "translate" as we do now with VLisp for the VBA samples of ActiveX. Quote
asos2000 Posted November 24, 2010 Posted November 24, 2010 =irneb;369810] Just to clarify, ... What a great work you did. Quote
sakinen Posted March 2, 2011 Posted March 2, 2011 I know that this is an old topic but i ran on this bit of code just the other day. I couldnt get it to work so i got into details. I put some of the code that i didnt understood in google search and "voila", exactly the same lisp. I made the block with an attribute to experiment with it but i couldnt get the layout to rename. Im sending you the dwg i tried on Q.dwg. If you find the time please just give me some pointers. Quote
Johnc Posted November 4, 2011 Posted November 4, 2011 Afternoon All, Just wondered if you clever people could give me a little advice on amending this routine. Is it possible to amend the routine to except an attribute value containing a back slash “/”. Our title blocks attribute is of the form 000/000. I’m not worried about having the “/” in the layout name and would be happy to replace it with say a space. Any help and advice gratefully received Many thanks John Quote
Lee Mac Posted November 4, 2011 Posted November 4, 2011 Try this updated code: (defun c:layname ( / blk ent enx inc itm lay lst sel tag val ) (setq blk [color=red]"BLOCK"[/color] tag [color=red]"TAG1"[/color] tag (strcase tag) ) (if (setq sel (ssget "_X" (list '(0 . "INSERT") '(66 . 1) (cons 2 blk)))) (progn (repeat (setq inc (sslength sel)) (setq ent (ssname sel (setq inc (1- inc))) val nil ) (if (not (assoc (setq lay (cdr (assoc 410 (entget ent)))) lst)) (progn (while (and (null val) (eq "ATTRIB" (cdr (assoc 0 (setq enx (entget (setq ent (entnext ent)) ) ) ) ) ) ) (if (eq (strcase (cdr (assoc 2 enx))) tag) (setq val (vl-string-translate "<>/\\\":;?*|,=`" " " (cdr (assoc 1 enx)))) ) ) (if (and val (not (eq "" val)) (not (member (strcase val) (mapcar 'strcase (mapcar 'cdr lst)))) ) (setq lst (cons (cons lay val) lst)) ) ) ) ) (vlax-for lay (vla-get-layouts (vla-get-activedocument (vlax-get-acad-object))) (if (setq itm (assoc (vla-get-name lay) lst)) (vla-put-name lay (cdr itm)) ) ) ) (princ "\nNo Blocks Found.") ) (princ) ) (vl-load-com) (princ) Change the block and tag name in red to suit. Quote
Johnc Posted November 4, 2011 Posted November 4, 2011 That’s totally excellent! Many thanks John Quote
irneb Posted November 4, 2011 Posted November 4, 2011 Or sticking with "pure" VLisp : (defun c:RenTab (/) (vl-load-com) (vlax-for tab (vla-get-Layouts (vla-get-ActiveDocument (vlax-get-acad-object))) (if (not (eq (strcase (vla-get-Name tab)) "MODEL")) (vlax-for entity tab (if (and (eq (vla-get-ObjectName entity) "AcDbBlockReference") (eq (strcase (vla-get-Name entity)) "TITLE_BLOCKS_NAME") ) (foreach attribute (vlax-invoke entity 'GetAttributes) (if (eq (vla-get-TagString attribute) "REVISION_ATTRIBUTES_NAME") (vl-catch-all-apply 'vla-put-Name (list tab (vl-string-translate "<>/\\\":;?*|,=`" " " (vla-get-TextString attribute))) ) ) ) ) ) ) ) (princ) ) BTW, here's a direct translation of bkm's VBA routine into VLisp: (defun Rename_Layout_Tab (/ PS) (vl-load-com) (vlax-for aeEntity (setq PS (vla-get-PaperSpace (vla-get-ActiveDocument (vlax-get-acad-object)))) (if (and (eq (vla-get-ObjectName aeEntity) "AcDbBlockReference") (wcmatch (strcase (vla-get-Name aeEntity)) "TITLEBLOCK*") ) (foreach ThisAttribute (vlax-invoke aeEntity 'GetAttributes) (if (eq (vla-get-TagString ThisAttribute) "ATT") (vl-catch-all-apply 'vla-put-Name (list (vla-get-Layout PS) (vla-get-TextString ThisAttribute))) ) ) ) ) ) A few differences: Due to the closures on vlax-for and foreach it's unnecessary to explicitly declare the aeEntity and ThisAttribute variables as local. Due to the functional behaviour of Lisp it's not necessary to assign variables pointing to the entity collection and attribute array as per VBA. No need to use array indexing for the attributes, that's handled with the foreach. I've introduced a PS local variable since it's used twice (once to obtain the PaperSpace collection to step through the entities on it, and again to get hold of its Layout object). VLisp can't directly get hold of an ActiveX object's type, thus I use the ObjectName property to compare it to a string. BTW, I'd not go with this route. It only renames the paper space tab which was last active. So if you have more than one tab, only the last one viewed would get renamed. Thus Lee's or my code is more comprehensive. 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.