I am inurgent need of a macro. This macro needs to add a new bom then i have some other code to that will print this bom. Then i need the macro to delete the bom that was paced in the drawing, but not delete any other bom that was already in the drawing. Can anyone help me or point me in the right direction. I must say that i don't have a great deal of scripting ability. Cheers Damian.
Bom Macro.
Jul 20, 2007
19 Replies
Start by recording a macro while you do everything manually. This will build the skeletton of your macro. It probably won't play back, but it's a good start since it will contain many of the required API calls.
The big question then is : what changes between 2 runs of your macro, or between 2 drawings on which it will run ? Do you need to select items ? do you need to format bom columns differently ?
Programming the macro consists mostly in "generalizing" it, making it able to handle different cases on different documents. And this is generally the hard part.
Maybe you could post your recorded macro and answer the question above : what changes between your "temporary boms" on different drawings. Then we might give you some more help here.
Q1. I am export an advanced BOM in an XML format. The drawings typicly have a BOM that only has about 6 feilds, but my advanced BOM will have about 15-20. I need this BOM only as an export not to be on the drawing..
I tried to record, but there dosn't reaaly seem to be anything of use in the code. See below.
' ****************************************************************************** ' C:\DOCUME~1\DGILLE~1\LOCALS~1\Temp\swx1256\Macro1.swb - macro recorded on 07/23/07 by dgillespie ' ****************************************************************************** Dim swApp As Object Dim Part As Object Dim SelMgr As Object Dim boolstatus As Boolean Dim longstatus As Long, longwarnings As Long Dim Feature As Object Sub main()Set swApp = Application.SldWorks
Set Part = swApp.ActiveDoc Set SelMgr = Part.SelectionManager boolstatus = Part.Extension.SelectByID2("DetailItem147@Sheet2", "ANNOTATIONTABLES", -0.07991769230769, 0.08582843076923, 0, False, 0, Nothing, 0) Part.EditDelete End Sub
Anyway here is my code. '------------------------------------------------
'' Preconditions:
' (1) Drawing document is open.
' (2) Drawing contains at least one BOM.
' (3) In VBA, add a reference to Microsoft Scripting Runtime using
' Tools, References (C:\windows\system32\scrrun.dll)
'' Postconditions: XML file is saved to the same directory,
' overwriting any existing file of the same name.
'' NOTES:
' (1) XML tags are based on BOM column headings.
' (2) Invalid characters must be removed from the
' column headings.
' (3) Microsoft Scripting Runtime reference must be selected in VBA.
' (4) XML schema is:
' ' '' Sheet1
'' Bill Of Materials1
' '' 1
' 2004_Part
'' 2
' '' 2
' 2004_Part
'' 1
' '' 3
' 2004_Part
'' 1
' '' 4
' bead7
'' 1
' ' ' ' '' Sheet2
'' Bill Of Materials2
' '' 1
' Assem3
'' 1
' ' '' cylinder
'' 1
' ' '' cylinder
'' 1
' ' '' SimpleCube_A
'' 1
' ' '' JoinedCyl
'' 1
' ' ' '' Bill Of Materials3
' '' 8
' 2004_Part
'' 2
' ' ' '' 9
' 2004_Part
'' 1
' '' 10
' 2004_Part
'' 1
' ' ' '' 11
' bead7
'' 1
' ' ' '' Bill Of Materials4
'' BOM Table 2
'' 1
' cylinder
'' 1
' '' 2
' cylinder
'' 1
' ' '' BOM Table 2
'' 3
' SimpleCube_A
'' 1
' '' 4
' JoinedCyl
'' 1
' ' ' ' ' ' ''----------------------------------------------
Option Explicit
Public Enum swTableSplitDirection_e
swTableSplit_None = 0
swTableSplit_Horizontal = 1
swTableSplit_Vertical = 2
End Enum
Sub ProcessTableAnn(swApp As SldWorks.SldWorks, swModel As SldWorks.ModelDoc2, swTableAnn As SldWorks.TableAnnotation, XMLfile As Scripting.TextStream)
Dim nNumRow As Long
Dim nNumCol As Long
Dim nNumHeader As Long
Dim sHeaderText() As String
Dim i As Long
Dim j As Long
Dim k As Long
Dim nIndex As Long
Dim nCount As Long
Dim nStart As Long
Dim nEnd As Long
Dim nSplitDir As Long
nNumHeader = swTableAnn.GetHeaderCount: Debug.Assert nNumHeader >=
1nSplitDir = swTableAnn.GetSplitInformation(nIndex, nCount, nStart, nEnd)
If swTableSplit_None = nSplitDir Then
Debug.Assert 0 = nIndex
Debug.Assert 0 = nCount
Debug.Assert 0 = nStart
Debug.Assert 0 = nEnd
nNumRow = swTableAnn.RowCount
nNumCol = swTableAnn.ColumnCount
nStart = nNumHeader
nEnd = nNumRow - 1
Else
Debug.Assert swTableSplit_Horizontal = nSplitDir
Debug.Assert nIndex >= 0
Debug.Assert nCount >= 0
Debug.Assert nStart >= 0
Debug.Assert nEnd >= nStart
nNumCol = swTableAnn.ColumnCount
If 1 = nIndex Then
' Add header offset for first portion of table
nStart = nStart + nNumHeader
End If
End If
XMLfile.WriteLine " "
If swTableAnn.TitleVisible Then
XMLfile.WriteLine " " & swTableAnn.Title & ""
End If
ReDim sHeaderText(nNumCol - 1)
For j = 0 To nNumCol - 1
sHeaderText(j) = swTableAnn.GetColumnTitle(j)
' Replace invalid characters for XML tags
sHeaderText(j) = Replace(sHeaderText(j), ".", "")
sHeaderText(j) = Replace(sHeaderText(j), " ", "_") sHeaderText(j) = Replace(sHeaderText(j), "(", "_") sHeaderText(j) = Replace(sHeaderText(j), ")", "_")
Next j
For j = nStart To nEnd
XMLfile.WriteLine " "
For k = 0 To nNumCol - 1 XMLfile.WriteLine " " + "" + swTableAnn.Text(j, k) + ""
Next k
XMLfile.WriteLine " "
Next j
XMLfile.WriteLine " "
End Sub
Sub ProcessBomFeature(swApp As SldWorks.SldWorks, swModel As SldWorks.ModelDoc2, swBomFeat As SldWorks.BomFeature, XMLfile As Scripting.TextStream)
Dim swFeat As SldWorks.Feature
Dim vTableArr As Variant
Dim vTable As Variant
Dim swTable As SldWorks.TableAnnotation
Set swFeat = swBomFeat.GetFeature
XMLfile.WriteLine " "
XMLfile.WriteLine " " & swFeat.Name & ""
vTableArr = swBomFeat.GetTableAnnotations
For Each vTable In vTableArr
Set swTable = vTable
ProcessTableAnn swApp, swModel, swTable, XMLfile
Next vTable
XMLfile.WriteLine " "
End Sub
Sub main()
Dim MyAppID As Long
Dim swApp As SldWorks.SldWorks
Dim swModel As SldWorks.ModelDoc2
Dim swDraw As SldWorks.DrawingDoc
Dim swSheet As SldWorks.Sheet
Dim swFeat As SldWorks.Feature
Dim swBomFeat As SldWorks.BomFeature
Dim sPathName As String
Dim nNumSheet As Long
Dim nRetval As Long
Dim i As Long
Dim bIsFirstSheet As Boolean
Dim bRet As Boolean
Dim fso As Scripting.FileSystemObject
Dim XMLfile As Scripting.TextStream
'Dim swApp As Object Dim Part As Object
Set swApp = Application.SldWorks
Set swModel = swApp.ActiveDoc
Set swDraw = swModel
bIsFirstSheet = True
' Strip off SolidWorks file extension (sldxxx)
' and add XML extension (xml)
sPathName = swModel.GetPathName
sPathName = Left(sPathName, Len(sPathName) - 6)
sPathName = sPathName + "xml"
Set fso = CreateObject("Scripting.FileSystemObject")
Set XMLfile = fso.CreateTextFile(sPathName, True) XMLfile.WriteLine "" XMLfile.WriteLine ""
XMLfile.WriteLine ""
Set swFeat = swModel.FirstFeature
Do While Not swFeat Is Nothing
If "DrSheet" = swFeat.GetTypeName Then
XMLfile.WriteLine " "
XMLfile.WriteLine " " + swFeat.Name + ""
bIsFirstSheet = False
End If
If "BomFeat" = swFeat.GetTypeName Then
Set swBomFeat = swFeat.GetSpecificFeature2
ProcessBomFeature swApp, swModel, swBomFeat, XMLfile
End If
Set swFeat = swFeat.GetNextFeature
If Not swFeat Is Nothing Then
If "DrSheet" = swFeat.GetTypeName And Not bIsFirstSheet Then
XMLfile.WriteLine " "
End If
End If
Loop
XMLfile.WriteLine " "
XMLfile.WriteLine ""
XMLfile.Close 'MyAppID = Shell("I:\PROPERTIES\Catten Output\SW_Output_Catten.exe",
1)'AppActivate MyAppID
End Sub
'----------------------------------------------------
Cheers Damian
Oh your project is much more advanced than I expected from your first post. Well you're on the right track, you know how to program, XML and such things, so what do you still need ? Oh ! How to delete the temporary table you just created ?
'since you have Dim swBomFeat As SldWorks.BomFeature 'then swBomFeat.GetFeature.Select2(false,0) ' to select it in the feature tree swDraw.EditCut ' the quick and dirty way OR swDraw.Extension.DeleteSelection2(0)' the clean way, with options to delete feature children.
I wrote a macro similar to yours some time ago... 2 comments:
1) If you export to XML, you don't really need to create a table, you could build a bom "internally" by traversing the assembly, which gives you even more flexibility than the SW BOM. 2) check the MSXML4 module to read/write XML files. You'll find plenty of tutorials on the net. It's much more efficient than handling XML as text files, as XML is more tricky than you expect. For example, your macro might have trouble with my french =E9=E0 accents or even worse, quotes in part names and such things. Normally you have to parse all strings you store in XML to convert them in a clean format with " for quotes ... MSXML takes all this pain out.Regards
Thanks for the vote of cofidence But i have nor really done this program. I think i got most of this from some examples. So some help would be great Cheers Damian
Hello Damian,
Is the main goal to get a BOM out of SW? If so, I would look at this AssemblyBOM macro on Lenny's site
With any SW asm open, Run Macro. A window pops up, you select BOM columns (revision, configurations)...and then choose format to export.
formatting link
Macro: AssemblyBOM
-Blair
BTW, Lenny just did a real useful presentation on Macro's at our local Kansas City SWUG meeting. Thanks Lenny.
Thanks Bliar. I have been using Lenny's macro for a while now. But i need all this exporting to happen in the background from a drawing when i use another macro to print our drawings. At present i use a macro that prints out our drawing a pdf, a tiff and a DXF of our parts (with a rev attached to the file name.) I may make a video of what i am looking for and upload to a site so people can get an idea of what we do and of what we want. Cheers Damian
Here is a video of what i am trying to do. Keep in mind that i already have a bom in the drawing. And that i want to add a new Bom, write out the the file then delete the bom that i have just put in and keep the exsisting bom. Cheers Damian
formatting link
loop through each sheet on the drawing then if the assumption can be made that all views are the same then you can grab the first view and use the insert bill of material function where you can specify a BOM template containing the properties you desire. (If the assumption cannot be made than you will have to think about how to recognize the correct view, perhaps the view that already has the BOM connected to it.) Next, when you insert the BOM you get the pointer to the BOM Object and from there you can get access to the rows and columns where you can then walk through the rows and columns generating you xml information.
You need to explain to me how much help you need. Do you have only the solidworks macro editor or do you have vb.net? Do you know how to create an xml file using VB? Do you need sample code to loop through the drawing sheets?
Also, you say this is urgent. Am I too late to help? Is this a short term thing or do you need this program for use down the road also? Just trying to find out how much time we should spend on this.
Firstly its not to late, so help would be great.
1.The assumptions that you are talking about in the first paragraph are valid. My dealt view is in most cases is the one which has the BOM is attached. If this is not the case then I/we would rectify these as needed.- How much help do I need? Well, I have a limited understanding of code and with time (not much of that these days) I can usually fudge my way through, but I would like if someone could step me through. This has been the only way I have learnt in the past.
- I only have the macro editor but I can download the VB.net if this would be the better way to go. I would much prefer to start learning VB.net as I could then use these skills in other areas within my job.
Thank Bill for your time and I hope to here back from you soon. Cheers Damian
Well, I have been working on this for you this morning because I pretty much just "office space" it these days. I am almost done with it but I have to question your schema. First of all, I am not an expert on what a good schema is, I simply know how to create the xml file. So that said, are you sure this is the schema you want or are you open to some changes? If so, I will post back with some suggestions.
Another thing I need to know is when I insert the temporary BOM, what type do you want? Top Level Only, Parts Only, or Indented?
I will send you the complete program in VB.net and I will post the code here as well. It could be done with the macro editor but you would need to rewrite the xml creation stuff because mine uses vb.net libraries. Technically, you could write the xml file as a text document with a .xml extension. I do it with the libraries because it adds the formating for me automatically.
Bill
This is a good start for you I think, I am using the "Custom Property View" as the view for the BOM. All you should have to change is the path to the BOM Template. This is set to work if a drawing is already open in SolidWorks. CreateBom is the main routine to start with. This code will run in VB.net with references to system.io, system.xml, SolidWorks Type Library, and SolidWorks Constant Library. I made a slight adjustment for now in your schema. After we discuss my previous post, I will make any adjustments you want and I will send you the compiled program so you can run it and I will send the entire solution so that if you get vb.net 2005 you can edit it and make it your own. The only thing I ask is that anyone who reads and this and likes what they see, remember me when you hear about job openings and/ or someone needing a custom application written.
Bill
---------------------------- Module modBom
Dim swApp As SldWorks.SldWorks Dim swModelDoc As SldWorks.ModelDoc2 Dim swDrawDoc As SldWorks.DrawingDoc Const strBomTemplate As String = "D:\Program Files\Common Files \Solidworks Data 2007\SWBOM.sldbomtbt"
Dim MyXmlDoc As New XmlDocument Dim MyRoot As XmlNode
Sub CreateBom()
Try
' Get Active Model swModelDoc = GetActiveModelDoc() ' Verify Found If Not swModelDoc Is Nothing Then ' Verify is Drawing If swModelDoc.GetType = SwConst.swDocumentTypes_e.swDocDRAWING Then ' Get Drawing Doc swDrawDoc = swModelDoc
' Build Bom File Name Dim strFileName As String = Path.GetDirectoryName(swModelDoc.GetPathName) & "\" & Path.GetFileNameWithoutExtension(swModelDoc.GetPathName) & ".xml" ' Verify File does not exist and delete if file does exist If DeleteExistingFile(strFileName) = False Then MsgBox("Cannot overwrite existing file: " & strFileName, MsgBoxStyle.Critical, "Failed") Exit Sub End If
' Create Xml Writer Dim writer As New XmlTextWriter(strFileName, Nothing) 'Use indenting for readability. writer.Formatting = Formatting.Indented ' Write Start of Document" writer.WriteStartDocument(True) ' Create Root node MyRoot = MyXmlDoc.CreateElement("Boms")
' Read Drawing Bom ReadBom()
' Write Root node MyRoot.WriteTo(writer) ' Write End Document writer.WriteEndDocument() ' Flush Writer writer.Flush() ' Close Writer writer.Close()
End If End If
Catch ex As Exception
End Try
End Sub
#Region " SolidWorks Document Tools "
Function GetSolidWorks() As Boolean
Try
Dim MyReturn As Boolean = False
If swApp Is Nothing Then swApp = GetObject("", "SldWorks.Application") End If
If Not swApp Is Nothing Then MyReturn = True End If
Return MyReturn Catch ex As Exception Return False End Try
End Function
Function GetActiveModelDoc() As SldWorks.ModelDoc2
Try
' Get SolidWorks Object GetSolidWorks()
' Get Active ModelDoc Object Dim SwModel As SldWorks.ModelDoc2 = swApp.ActiveDoc
Return SwModel Catch ex As Exception Return Nothing End Try
End Function
#End Region
#Region " Bom "
Private Sub ReadBom()
Try
' Get List Of Sheet Names Dim strSheets() As String = swDrawDoc.GetSheetNames() ' Process All Sheets For i As Integer = 0 To swDrawDoc.GetSheetCount - 1
Dim MySheetNode As XmlNode MySheetNode = MyXmlDoc.CreateElement("Sheet")
Dim MyNode As XmlNode MyNode = MyXmlDoc.CreateElement("Name") MyNode.InnerText = strSheets(i) MySheetNode.AppendChild(MyNode) Dim MyBomNode As XmlNode = MyXmlDoc.CreateElement("BOM")
' Activate Sheet By Name swDrawDoc.ActivateSheet(strSheets(i)) ' Get BOM Drawing View Dim MyDrawView As SldWorks.View = swDrawDoc.GetFirstView ' Get Current Sheet Dim swSheet As SldWorks.Sheet = swDrawDoc.GetCurrentSheet ' Get Custom Property View Dim strView As String = swSheet.CustomPropertyView ' If the custom property view is the Default, Get the First View If strView = "Default" Then MyDrawView = swDrawDoc.GetFirstView MyDrawView = MyDrawView.GetNextView Else ' Find Matching View by Name MyDrawView = swDrawDoc.GetFirstView ' Loop Through Views While Not MyDrawView Is Nothing If MyDrawView.Name = strView Then Exit While End If ' Next View MyDrawView = MyDrawView.GetNextView End While End If
' Create Custom Xml Bom CreateXmlBom(MyDrawView, MyBomNode)
' Append To Sheet MySheetNode.AppendChild(MyBomNode) ' Append to Root MyRoot.AppendChild(MySheetNode)
Next
Catch ex As Exception
End Try
End Sub
Sub CreateXmlBom(ByVal MyDrawView As SldWorks.View, ByRef MyBomNode As XmlNode)
Try
' Insert and Get Bom Table Annotation Dim swBomTable As SldWorks.TableAnnotation = InsertBom(MyDrawView) ' Verify If Not swBomTable Is Nothing Then ' Process Bom ProcessBom(swBomTable, MyBomNode) ' Remove Bom Dim swAnnotation As SldWorks.Annotation = swBomTable.GetAnnotation swAnnotation.Select3(False, Nothing) swModelDoc.DeleteSelection(False) End If
Catch ex As Exception
End Try
End Sub
Sub ProcessBom(ByVal swBomTable As SldWorks.TableAnnotation, ByRef MyBomNode As XmlNode)
Try
' Ensure Header is at Top swBomTable.SetHeader(SwConst.swTableHeaderPosition_e.swTableHeader_Top,
1) ' Process each Row For r As Integer = 1 To swBomTable.RowCount - 1 ' Create Row Node Dim MyRowNode As XmlNode = MyXmlDoc.CreateElement("ROW") ' Process each Column For c As Integer = 0 To swBomTable.ColumnCount - 1 ' Get Cell Value Dim strValue As String = swBomTable.DisplayedText(r, c) ' Get Header (Replace Spaces with "_", also the title cannot contain characters that are not allowed in xml node names) Dim strHeader As String = swBomTable.GetColumnTitle(c).Replace(" ", "_") ' Create Item Node Dim MyItemNode As XmlNode = MyXmlDoc.CreateElement(strHeader) ' Add Value MyItemNode.InnerText = strValue ' Append To Row MyRowNode.AppendChild(MyItemNode) Next ' Append to Bom MyBomNode.AppendChild(MyRowNode) Next Catch ex As ExceptionEnd Try
End Sub
Function InsertBom(ByVal MyDrawView As SldWorks.View) As SldWorks.TableAnnotation
Try
Dim MyReturn As SldWorks.TableAnnotation = Nothing
' Insert Bom Dim swBom As SldWorks.BomTableAnnotation = MyDrawView.InsertBomTable2(True, 0, 0, SwConst.swBOMConfigurationAnchorType_e.swBOMConfigurationAnchor_BottomLeft, SwConst.swBomType_e.swBomType_TopLevelOnly, MyDrawView.ReferencedConfiguration, strBomTemplate)
' Verify Bom If Not swBom Is Nothing Then ' Get Bom Feature Dim swBomFeature As SldWorks.BomFeature = swBom.BomFeature ' Verify If Not swBomFeature Is Nothing Then Dim MyVisibleConfigs As Object = Nothing Dim strConfigNames() As String = swBomFeature.GetConfigurations(False, MyVisibleConfigs) For i As Integer = 0 To strConfigNames.Length - 1 If strConfigNames(i) = MyDrawView.ReferencedConfiguration Then MyVisibleConfigs(i) = True swBomFeature.SetConfigurations(True, MyVisibleConfigs, strConfigNames) Exit For End If Next ' Get Bom Table For Each swBomTable As SldWorks.TableAnnotation In swBomFeature.GetTableAnnotations MyReturn = swBomTable Exit For Next End If End If
Return MyReturn Catch ex As Exception Return Nothing End Try
End Function
Function DeleteExistingFile(ByVal strFileName As String) As Boolean
Try Dim MyReturn As Boolean = False
' Check if File Exists If File.Exists(strFileName) = True Then ' Delete File File.Delete(strFileName) End If
MyReturn = Not File.Exists(strFileName)
Return MyReturn Catch ex As Exception Return False End Try
End Function
#End Region
End Module
Where are you located?
WT
I am in Vassar, Michigan and you can see more info if you click on "view profile" by my name. Thanks for asking.
Thanks Bill. You have done a lot more than i thought anyone would do. Yes bill i am open to any ideas to make it better. Also idented assembly bom would be the best. It is Saturday arvo here so i will get back to this Monday morning my time.
Cheers Bill. Damian
PS Bill . Do you know of the ERP system M1. As my main goal is to link Solidworks Bom to a build in M1. Cheers Damian
No, sorry I do not know that system. You need to find out what import capabilities the erp system has and then we can build the export file or files accordingly. I would expect that the erp system would want individual files showing the top level only for each of the sub assemblies.
Hi Bill. I have to admit, i am not in a hurry to link it with the ERP system as yet. I downloaded VB 2005 Express. Is this the same as VB.NET. Cheers DAmian
As far as I know, VB 2005 Express is the latest free version of VB.net =========================================================================== Chris
Thanks for that . Now i will download at work and try and build the code with Bills code. Cheers Damian
Join the Discussion
Have something to add? Share your thoughts — no account required.
Didn't find your answer?
Ask the community — no account required