TheSwamp
Code Red => VB(A) => Topic started by: hardwired on March 19, 2008, 12:04:49 PM
-
Hi,
Have a program that creates a block, add a table of attiributes and then inserts it, will all works spot on now (thanks to all who helped me before)...
...but if there is already a block reference of the same type in the drawing i want to redefine it with the new information that the user enters NOT add to it, which what it seems to do...
In the program, when the userform loads, it checks if the block exists and populates the userform with its attribute values, which works fine, and this allows the user to edit the information in the block and not start over each time, but when the user finishes the program and the block is inserted, its an almagamation of the existing and new information..
Any ideas?
-
If there is already a block reference in the drawing, you can do a few different things ...
a) rename the old block reference
b) programmatically delete all objects in the old definition
c) delete the existing reference(s) and purge the drawing
Of the 3, b sees to be the most desirable
-
don't have the time to test it right now, but try a
for each blkref in thisdwg.mspace
if blkref.name = "x" then
blkref.update
end if
next blkref
-
Hi,
Have a program that creates a block, add a table of attiributes and then inserts it, will all works spot on now (thanks to all who helped me before)...
...but if there is already a block reference of the same type in the drawing i want to redefine it with the new information that the user enters NOT add to it, which what it seems to do...
In the program, when the userform loads, it checks if the block exists and populates the userform with its attribute values, which works fine, and this allows the user to edit the information in the block and not start over each time, but when the user finishes the program and the block is inserted, its an almagamation of the existing and new information..
Any ideas?
Are the users simply changing attribute information or is the graphic itself changing?
Why redefine the block definition?
-
try this function before adding your data to the block
Function CleanoutBlock(currentBlock As AcadBlock)
Dim blkItem As AcadEntity
For Each blkItem In currentBlock
blkItem.Delete
Next blkItem
End Function
-
Hi,
I have tried this in my program so far....
(The SSetX is a SelectionSet it creates on UserForm loading, to check for existing blocks..
'Redefine current block info if chart exists..
Dim BlK As AcadBlockReference
Dim EntX As AcadEntity
If SSetX.Count > 0 Then
For Each BlK In SSetX
If BlK.Name = "Fixings_Chart" Then
For Each EntX In BlK
EntX.Delete
Next EntX
End If
Next BlK
End If
......it flags an error says object doesn't support this method, which obviously is refereing to the BlockRef, which if i want to access entities in it, should be a Block not a BlockRef....so where do i go from here?
I also, like Keith's Function:
Function CleanoutBlock(currentBlock As AcadBlock)
Dim blkItem As AcadEntity
For Each blkItem In currentBlock
blkItem.Delete
Next blkItem
End Function
.....but how do i call the function from the code just before i add the new data?
-
I don't know your exact situation, but your code has some potential issues that perhaps we can resolve.
Using the code you provided, you are evidently selecting all of the blocks in the drawing and then iterating through them all. If you want to edit the block references, you have to edit the block definition. If you edit the block definition, it wil automatically reflect in all of the block references, thereby negating the need to iterate through all of the block references in the drawing. Using the code you provided, if it worked, it would redefine the same block over and over again for each instance the block was inserted in the drawing. This is not necessary and is needless repetition of the same procedure.
Earlier you stated that you have code that puts items into the block, but you didn't have code to remove items from the block. The code I provided removes all items from the block you pass as an argument to the function .. but you have to pass the AcadBlock not the AcadBlockReference.
download the module I posted in the previous thread (http://www.theswamp.org/index.php?action=dlattach;topic=21818.0;attach=7260) and import it into your project (right click in the project explorer and click import file) then add this code to your form load event
Dim Blk As AcadBlock
If acBlock.BlockExists("Fixings_Chart").Exists = True Then
Set Blk = ThisDrawing.Blocks.Item("Fixings_Chart")
CleanoutBlock Blk '<-- call the CleanoutBlock function here
End If
'Add code here to put the new entities in the block
'Blk.Addxxx functions to add the entities as needed
Add this code to your form as a new function
Function CleanoutBlock(currentBlock As AcadBlock)
Dim blkItem As AcadEntity
For Each blkItem In currentBlock
blkItem.Delete
Next blkItem
End Function
You could provide a little more code and we can give you pointers about where you are going wrong.
-
Thanks Keith, for taking the time out for this (and to everyone else for that matter)..
I have done exactly as you said and the new instance it inserts looks exactly how it should, not a mix of the old elements and the new.....the only thing is that all existing block inserts haven't changed and still look as they did before running the program again..
-
Thanks Keith, for taking the time out for this (and to everyone else for that matter)..
I have done exactly as you said and the new instance it inserts looks exactly how it should, not a mix of the old elements and the new.....the only thing is that all existing block inserts haven't changed and still look as they did before running the program again..
Then you have something else going on ... have these perhaps been edited and saved as dynamic blocks? if so, they may not be updated properly ... or maybe you should regen all views
-
ah, if i regen then the graphical nature of the block is updated but not the attributes, if the user removes the number of attributes from the list then these still remain in the blocks, so that the table has the correct number of rows, but not the correct number of attributes (some overrun down past the extents of the table)..
I would post my full code but it exceeds the character limit for each post. Maybe, it would help anyway, post the code in sections on different posts..
-
attributes don't update.
It's easier to find each blockref and replace it with a new one, matching the properties first
-
But surely, using the function Keith supplied, which deletes all entities in the block, there wouldn't be any attributes that won't update, so the only the new attributes will be present and shown?
-
Ah .. now I more fully understand the nature of your request ...
To my knowledge, the only method to update the attributes if you change the number of the attributes, is to attsync the block references. You could alternatively insert the blocks with VBA and then grab the attributes and modify them.
In VBA you can only attach attributes to a block, modelspace or paperspace, there is no addattributereference method to add a reference to an attribute in the block.
Presuming you are adding the attributes back to the block with AddAttribute, you must then go through each AcadBlockReference, grab the origin, scale, rotation, layer etc that you want to keep the same, then insert a new block with the same information and then update the attributes as needed.
-
oh right, so even adding:
' Checks if table exists and redefines (clearsout) the block of all data..
Function CleanoutBlock(currentBlock As AcadBlock)
Dim blkItem As AcadEntity
[color=red]Dim blkAtt As AcadAttribute[/color]
For Each blkItem In currentBlock
blkItem.Delete
Next blkItem
[color=red] For Each blkAtt In currentBlock
blkAtt.Delete
Next blkAtt[/color]
End Function
...to your function won't work?
I tried it, but still nothing. All i want to do is delete the attributes (and all block entities) from the block, so its empty and then put back all the stuff the program does in the block, so if there any blocks the user has inserted anywhere, the blocks will reflect what the user chooses in the program..
Here's a brief lowdown an what the program does: It creates a fixings chart / table from user defined data (the user can also pick a fixing from an inserted block in a drawing and it will enter the block name in the textbox for that chosen fixing. There are 10 possible rows to create, each one selected / deselected by checkbox. When run, it adds two types of attribute for each row to the table / chart, one is the reference number for the item (a constant) (ie: FX1, FX2 etc), the second is the description (a normal) which the user can edit in the text boxes on the userform. When loaded (userform_Initialise), the program searches for any existing insert of the table and populates the userform with that data, so the user can edit / add to / delete from etc.. and when completed, it inserts the block (if new / no existing table was found) or just updates the existing..
Now with my code (and Keith's addition), it works 99% but just won't delete the existing normal attributes (it DOES however delete the constant attributes (the reference ones)..
I thought, as it deletes these constant attributes (all attributes in this program created by Block.AddAttribute by the way) it would also delete the normal ones too, but it doesn't. Is this because of the 'constant' property of the attribute?
-
You are not understanding ....
a) When you edit a block with VBA, you only edit the attributes in the block table. It does not affect the block references
b) If you use attsync after using your command, all of the attributes that don't exist in the block, but are attached to the block reference will be removed from the block reference and all attributes in the block, but not in the block reference will be added to the block reference.
c) VBA does not have a mechanism to do this with code, so, you have to create your own.
d) The code I posted earlier does in fact delete the attributes from the block, but not the block reference. There is no method to do that in VBA
You can do one of the following:
1) Execute attsync at the command line after running your program
Command: attsync
Enter block name or ? for list <select block>: Fixings_Chart
Command:
2) Delete all occurences of Fixings_Chart in the drawing and replace them with new block references
Dim OldBlkRef As AcadBlockReference
Dim NewBlkRef As AcadBlockReference
For Each OldBlkRef In ThisDrawing.ModelSpace
With OldBlkRef
If UCase(.Name) = "FIXINGS_CHART" Then
Set NewBlkRef = ThisDrawing.ModelSpace.InsertBlock(.InsertionPoint, .Name, .XScaleFactor, .YScaleFactor, .ZScaleFactor, .Rotation)
NewBlkRef.layer = .layer
NewBlkRef.Color = .Color
NewBlkRef.Linetype = .Linetype
NewBlkRef.LinetypeScale = .LinetypeScale
NewBlkRef.Lineweight = .Lineweight
NewBlkRef.Normal = .Normal
NewBlkRef.Visible = .Visible
' transfer all of the attribute tag values over in this area
' if you want to keep the existing values in the attributes
.Delete
End If
End With
Next OldBlkRef
Now the important thing to remember is that if you utilize the code to replace the existing block references, you will need to manually fill in all of the attributes unless you set the attribute value with a default value in the block.
-
Hey Keith,
Me again, lol..
I've added you code to mine and when i run the program, which first checks if the block exists, which works, then i edit the userform as i'm meant to, then hit go and it errors out on the For Each OldBlkRef In ThisDrawing.PaperSpace line, with a Type Mismatch error even though there are blatantly other blocks (of the same name) in paperspace - would could be wrong?
'If Insert Chart (and update existing ones) is chosen..
ElseIf want1OPT.Caption = " Insert Chart (and update existing ones).." Then
[color=red]For Each OldBlkRef In ThisDrawing.PaperSpace[/color]
With OldBlkRef
If .Name = "Fixings_Chart" Then
Set NewBlkRef = ThisDrawing.PaperSpace.InsertBlock(.InsertionPoint, .Name, .XScaleFactor, .YScaleFactor, .ZScaleFactor, .Rotation)
NewBlkRef.Layer = .Layer
NewBlkRef.color = .color
NewBlkRef.Linetype = .Linetype
NewBlkRef.LinetypeScale = .LinetypeScale
NewBlkRef.Lineweight = .Lineweight
NewBlkRef.Normal = .Normal
NewBlkRef.Visible = .Visible
.Delete
End If
End With
Next OldBlkRef
' Check if table exists and redefine (clearout) the block of all data before creating and inserting the new instance..
Dim Blk1 As AcadBlock
If acBlock.BlockExists("Fixings_Chart").Exists = True Then
Set Blk1 = ThisDrawing.Blocks.Item("Fixings_Chart")
CleanoutBlock Blk1 '<-- call the CleanoutBlock function here
End If
CREATEChart
INSERTChart
-
The problem is that there are more than block references in the drawing paperspace. You have to filter the object types to make it work.
Dim OldBlkRef As AcadEntity ' AcadBlockReference is implied, but we cannot specify if other types are present in the collection
Dim NewBlkRef As AcadBlockReference
For Each OldBlkRef In ThisDrawing.PaperSpace
With OldBlkRef
' filter for block references only
If OldBlkRef.ObjectName = "AcDbBlockReference" Then
If UCase(.Name) = "FIXINGS_CHART" Then
Set NewBlkRef = ThisDrawing.PaperSpace.InsertBlock(.InsertionPoint, .Name, .XScaleFactor, .YScaleFactor, .ZScaleFactor, .Rotation)
NewBlkRef.Layer = .Layer
NewBlkRef.color = .color
NewBlkRef.Linetype = .Linetype
NewBlkRef.LinetypeScale = .LinetypeScale
NewBlkRef.Lineweight = .Lineweight
NewBlkRef.Normal = .Normal
NewBlkRef.Visible = .Visible
' transfer all of the attribute tag values over in this area
' if you want to keep the existing values in the attributes
.Delete
End If
End If
End With
Next OldBlkRef
-
Hi Keith,
Done what you suggested and it doesn't error now on that bit, doesn't error at all. What it doesn't do either is update the blocks and attribute values, well not first time anyway. If i hit the Update Chart button to run the program once, it updates the blocks but not the attribute values, and if i hit the button again it seems to do the correct job and update the attributes aswell. Why would this be? And how can i get it to do it on first hit of the button?
Code snippet is below:
For Each OldBlkRef In ThisDrawing.PaperSpace
With OldBlkRef
If OldBlkRef.ObjectName = "AcDbBlockReference" Then
If .Name = "Fixings_Chart" Then
Set NewBlkRef = ThisDrawing.PaperSpace.InsertBlock(.InsertionPoint, .Name, .XScaleFactor, .YScaleFactor, .ZScaleFactor, .Rotation)
NewBlkRef.Layer = .Layer
NewBlkRef.color = .color
NewBlkRef.Linetype = .Linetype
NewBlkRef.LinetypeScale = .LinetypeScale
NewBlkRef.Lineweight = .Lineweight
NewBlkRef.Normal = .Normal
NewBlkRef.Visible = .Visible
'.Delete
' Check if table exists and redefine (clearout) the block of all data before creating and inserting the new instance..
If acBlock.BlockExists("Fixings_Chart").Exists = True Then
Set Blk1 = ThisDrawing.Blocks.Item("Fixings_Chart")
CleanoutBlock Blk1 '<-- call the CleanoutBlock function here
End If
End If 'If block is Fixings_Chart..
End If 'If block..
End With
CREATEChart
Next OldBlkRef
....the CleanoutBlock was the function you posted:
Function CleanoutBlock(currentBlock As AcadBlock)
Dim blkItem As AcadEntity
Dim blkAtt As AcadAttribute
For Each blkItem In currentBlock
blkItem.Delete
Next blkItem
For Each blkAtt In currentBlock
blkAtt.Delete
Next blkAtt
End Function
.....and the CREATEChart is my sub for creating the block and setting the attribute values..
Any ideas?
-
1) Update the block
2) Update the blockrefs
in that order
-
1) Update the block
2) Update the blockrefs
in that order
Indeed
-
Ok, tried that, won't work either, must be something in my code i am doing wrong. Could someone please take a look at moy code and run the program and let me know what might be wrong, would appreciate it muchly..
Oh, forgot to say, run it once to create and insert a chart to begin with, then run the program again and it should catch that there is already a chart(s) inserted..
-
Ok, sorry, changed the code about a bit more and it works perfectly..
Only thing now is if there NO INSERTED references BUT one in the collection, when you run the program it merges the two (the existing in the collection and the new updated one). Is there a way to purge out just that block (only if noreferences are INSERTED) before the program runs that part of the program?
When i purge out that block ref manually, and re-run the program it works, it just doesn't like any refs in the collection..
-
When I get some more time I'll look at it
-
Right, tested it (using the same code as the one i upload on my last post) and came up with the following problems:
- When first run, and the chart is inserted for the first time (NO inserted refs or ones in the blocks collection), everything runs perfectly, except that it insertes to 0,0,0 and not the coords in the X and Y textboxes..
- When first run, and the chart is inserted and there are NO other inserted BUT the block is in the block collection (ie: ran the program once, created the chart, deleted the inserted chart, ran the program again), it merged the block in the collection with the newly inserted one and its all a mess..
- When run with charts already inserted (the program catches this and loads the attribute info to the form), and the UPDATE EXISTING CHARTS ONLY option is chosen, the charts update as they should visually, but i noticed that instead of deleting the existing attributes, or updating them, it adds more (each time you run it), so it has multiple instances of the same attibute, so instead of maximum of 10, it has 20 or so, which can be seen if you check the properties of the chart..
- When run with charts already inserted and the INSERT CHART (AND UPDATE CHARTS ONES) option is chosen, the chart updates (but with same multiple attributes problem) but also the new chart is not inserted..
Sorry to be a PITA about all this Keith, but i can't get my head around it all and wanna get this one sorted..
Thanks for the help and for being patient :)
-
Ahhh, right on more tests (damn this thing, its really working my nips now!!)..
- If there are more than one charts on a layout, the child (copied) blocks have the multiple attribute problem but the main parent one doesn't and it seems to do multiply by however many instances are inserted on that layout. The second block will have twice as many attributes (copies of the originals) and the third will have 3 times as many, and so on....
- Also, it doesn't update other inserted references on OTHER layouts - well it does do the geometry, but not the attributes - so if there are any on another layout, then these will graphically (line etc) look right but they might have the attributes going out of the bottom of the chart or too few with empty spaces in the chart..
I would just do this with text in the block not attributes and be doen with it, but i won't be able to access the text and populate the form if the chart already exists - or will i? Can i use text instead of attributes and still have the same functionality of the program? Grrrrrrr
-
Hi,
I know this is an old one now, but can anyone take a look at this when they have time and point me home. Its 99ish% done and seems silly not to finish it..
Check out the last few threads for what the program is and isn't doing right and download the last posted dvb file..
Thanks in advance to anybody who cares, lol