Hello everyone,
So I've finally come up with a solution to my problem. It took a while to figure out a solution, but I did it, and it works beautifully (at least, for my purposes, anyway). And like I said I would do in my previous reply, here's the code that I came up with.
Disclaimer: I apologize in advance if my code is messy or inefficient - I'm just getting my feet wet in Inventor's VBA, so I'm learning a LOT of things every day on how to program efficiently.
What Does This Gibberish Do?
Like the instructions in the screenshot below shows, this tool will scan through and turn off the visibility for individual component occurrences in DrawingViews 1 - 5 on the shop drawing. It can also turn off all components that share the same "part number", which is the name that shows up in the Inventor drawing's Browser Window. On top of that, you can enter multiple part numbers into the Find & Hide Components textbox; just separate each name with a comma, and the sub-routines will find & hide each of the components that you've listed. Lastly, the Find & Hide Folders textbox will find & hide all of the contents of a specified Browser Folder.
..But Why?
Why not just do this all by hand? Well, when you're working with a shop drawing template, there can be multiple DrawingViews used to illustrate an assembly model's details (my company uses 5 views to illustrate our packing crates). When you swap out some unit assemblies that are contained within each crate assembly model, sometimes a lot of small components that you'd prefer to remain invisible become visible on the drawing. I got sick and tired of having to go into each DrawingView and manually hiding the same components over and over again. So now I won't have to, and it's frakkin' AWESOME.
Um, How You Do??
These sub-routines work in tandem with a couple simple User Parameters, iLogic rules & a simple form to perform their task. They're currently a part of a shop drawing template file that I've been refining, so everything is tied locally to a single .IDW file.
The .IDW file has two simple User Parameters: hide_this_component; and hide_this_folder. These text parameters simply hold the value of whatever the user types into the UI Form (see below). The iLogic rules that are tied to these User Parameters are simple, and look like the following:
find_and_hide_components_rule:
' This rule will seek out a specified component, and will run the FindAndHideComponents(sCompName) macro to hide it.
InventorVb.RunMacro("DocumentProject", "Module1", "FindAndHideComponents", hide_this_component)
find_and_hide_folders_rule:
SyntaxEditor Code Snippet
' This rule will run a few macros to locate a folder in the Browser window that has the same name as hide_this_folder.' It will then hide all of the components within the specified folder.
InventorVb.RunMacro("DocumentProject", "Module1", "FindAndHideFolders", hide_this_folder)
I threw together a simple User Interface Form for this "Find & Hide Components" tool, complete with instructions on how to enter the component names into the textboxes:

Last, but certainly not least, here be my source code:
Sub FindAndHideFolders(sFolderName As String)
' This sub-routine will seek out and hide any components that are contained within a Browser Folder
' that's specified by the user.
' Set a reference to the drawing document.
Dim oDrawDoc As Inventor.DrawingDocument
Set oDrawDoc = ThisApplication.ActiveDocument
' Set a reference to the active sheet.
Dim oSheet As Inventor.sheet
Set oSheet = oDrawDoc.ActiveSheet
' Set a reference to the drawing view (defaults to VIEW1).
Dim oView As Inventor.DrawingView
Set oView = oSheet.DrawingViews.Item(1)
' Set a reference to all drawing views.
Dim oViews As DrawingViews
Set oViews = oSheet.DrawingViews
'-------------------------------------------------------------------------------------
' Set a reference to the FileManager Object.
Dim oFileManager As FileManager
Set oFileManager = ThisApplication.FileManager
' Set the full file name of the drawing document.
Dim sFullFileName As String
sFullFileName = oDrawDoc.FullDocumentName
' Set the name of the desired LOD representation.
Dim sLODName As String
sLODName = "iLogic"
' Get the full document name using the full file name & LOD name.
Dim sFullDocName As String
sFullDocName = oFileManager.GetFullDocumentName(sFullFileName, sLODName)
' Set a reference to the assembly document.
Dim oRefDoc As AssemblyDocument
Set oRefDoc = oView.ReferencedDocumentDescriptor.ReferencedDocument
' Set a reference to the assembly component definition.
Dim oSub1AssyCompDef As AssemblyComponentDefinition
Set oSub1AssyCompDef = oRefDoc.ComponentDefinition
' Set a reference to the component & sub-component occurrences.
Dim oSub1AssyCompOcc As ComponentOccurrence
Dim oSub2AssyCompOcc As ComponentOccurrence
' Set a reference to the Browser Pane.
Dim oPane As BrowserPane
Set oPane = oRefDoc.BrowserPanes.ActivePane
'-------------------------------------------------------------------------------------
' This variable will reference the collection of components in the assembly model's Browser window.
Dim oTopNodes As BrowserNodesEnumerator
Set oTopNodes = oPane.TopNode.BrowserNodes
' This variable will reference the BrowserFolder collection (if any) within each TopNode.
Dim oBrowserFolders As BrowserFoldersEnumerator
Dim oTopNode As BrowserNode
For Each oTopNode In oTopNodes
Set oBrowserFolders = oTopNode.BrowserFolders
' If there are any browser folders within the current TopNode object, then we'll scan through them
' to find a folder name that matches the user's input.
If oBrowserFolders.Count > 0 Then
Dim oBrowserFolder As BrowserFolder
For Each oBrowserFolder In oBrowserFolders
' If the current oBrowserFolder name is the same as the folder name provided by the user,
' then we'll proceed to turn off the visibility for every component within the current
' oBrowserFolder. We'll skip over any suppressed components to avoid any odd errors or such.
If oBrowserFolder.Name = sFolderName Then
' This variable will reference the collection of Browser Nodes in the current
' oBrowserFolder.
Dim oBrowserNodes As BrowserNodesEnumerator
Set oBrowserNodes = oBrowserFolder.BrowserNode.BrowserNodes
' This For-Each loop will iterate through each Browser Node in the current oBrowserFolder
' to find & extract the name of each component found within the user-specified folder.
Dim oBrowserNode As BrowserNode
For Each oBrowserNode In oBrowserNodes
' We want to ignore any components that are already suppressed, so this If-Then block
' will ensure that such is the case.
If oBrowserNode.NativeObject.Suppressed = False Then
' This variable will contain the FullPath of the current oBrowserNode. We'll
' split the FullPath into a string array and extract the part number & occurrence
' number from it.
Dim sNodeName As String
sNodeName = oBrowserNode.FullPath
Dim S() As String
' Produces S(0) thru S(5); S(4) has the component name that we want!
S() = Split(sNodeName, ":")
' Now we'll put the extracted part number & occurrence number back together with
' a colon separator, and then store it within this variable.
Dim sPartNumber As String
sPartNumber = S(4) & ":" & S(5)
' We'll use the FindAndHideComponents() sub-routine to handle the task of hiding
' the component that's associated with the current oBrowserNode.
Call FindAndHideComponents(sPartNumber)
End If
Next
End If
Next
End If
Next
MsgBox ("Find & Hide Folder Components Process Complete.")
End Sub
Sub FindAndHideComponents(sCompName As String)
' This sub-routine will seek out and hide any unit assembly components that are specified by the user.
' Set a reference to the drawing document.
Dim oDrawDoc As Inventor.DrawingDocument
Set oDrawDoc = ThisApplication.ActiveDocument
' Set a reference to the active sheet.
Dim oSheet As Inventor.sheet
Set oSheet = oDrawDoc.ActiveSheet
' This variable keeps track of which drawing view that this sub-routine is currently working on.
Dim lViewCounter As Long
lViewCounter = 1
' Set a reference to the drawing view (defaults to VIEW1).
Dim oView As Inventor.DrawingView
Set oView = oSheet.DrawingViews.Item(lViewCounter)
' Set a reference to all drawing views.
Dim oViews As DrawingViews
Set oViews = oSheet.DrawingViews
'-------------------------------------------------------------------------------------
' Set a reference to the FileManager Object.
Dim oFileManager As FileManager
Set oFileManager = ThisApplication.FileManager
' Set the full file name of the drawing document.
Dim sFullFileName As String
sFullFileName = oDrawDoc.FullDocumentName
' Set the name of the desired LOD representation.
Dim sLODName As String
sLODName = "iLogic"
' Get the full document name using the full file name & LOD name.
Dim sFullDocName As String
sFullDocName = oFileManager.GetFullDocumentName(sFullFileName, sLODName)
' Set a reference to the assembly document.
Dim oRefDoc As AssemblyDocument
Set oRefDoc = oView.ReferencedDocumentDescriptor.ReferencedDocument
' Set a reference to the assembly component's definition.
Dim oSub1AssyCompDef As AssemblyComponentDefinition
Set oSub1AssyCompDef = oRefDoc.ComponentDefinition
Dim oSub1AssyCompOcc As ComponentOccurrence
Dim oSub2AssyCompOcc As ComponentOccurrence
'-------------------------------------------------------------------------------------
' This string array will split up the value of sCompName so that multiple parts can be hidden at a time.
' The user will need to separate each component name up by placing a comma in between each component name.
Dim sCompNameArray() As String
sCompNameArray() = Split(sCompName, ",")
Dim vCurrentCompName As Variant
For Each vCurrentCompName In sCompNameArray()
' We reset our lViewCounter to 1.
lViewCounter = 1
' The following variable will determine whether or not vCurrentCompName contains a colon (":") in its
' string value.
' - If a colon is present, bIsCompName1Occ will be set to False.
' - If a colon is NOT present, bIsCompName1Occ will be set to True.
Dim bIsCompName1Occ As Boolean
If InStr(vCurrentCompName, ":") > 0 Then
bIsCompName1Occ = True
ElseIf InStr(vCurrentCompName, ":") = 0 Then
bIsCompName1Occ = False
Else
MsgBox ("ERROR: Invalid value for vCurrentCompName variable.")
End If
' This While-Wend loop will scan VIEW2 thru VIEW5 for the specified component, and then hide it if
' it's found.
While lViewCounter <= 5
Set oView = oSheet.DrawingViews.Item(lViewCounter)
' This variable will keep count of which assembly component item our specified component is
' located within.
Dim AssyOccItemNumber As Long
AssyOccItemNumber = 1
' We'll check every component under master assembly level to see if any of these components' names
' match the specified component.
For Each oSub1AssyCompOcc In oSub1AssyCompDef.Occurrences
' We check to ensure that we're not looking at a suppressed component, as that can cause errors
' to occur.
If oSub1AssyCompOcc.Suppressed = False Then
'====================================
' Single Component Hiding Block Begin
'====================================
' If a colon is present in sCompName's value, then we presume that we're only hiding a
' single occurrence of the specified component. We'll run this If-Then code block to find
' & hide the specified component.
If bIsCompName1Occ = True Then
If oSub1AssyCompOcc.Name = vCurrentCompName Then
If oView.GetVisibility(oSub1AssyCompOcc) = True Then
Call oView.SetVisibility(oSub1AssyCompOcc, False)
End If
End If
' If the current oSub1AssyCompOcc's name doesn't match the specified component, and it's
' an assembly component that is not suppressed, then we dive deeper to search the
' components within oSub1AssyCompOcc.
If oSub1AssyCompOcc.Definition.Type = kAssemblyComponentDefinitionObject Then
' This variable gets the assembly component definition of the current
' oSub1AssyCompOcc object.
Dim oSub2AssyCompDef As AssemblyComponentDefinition
Set oSub2AssyCompDef = oSub1AssyCompOcc.Definition
' This variable will keep count of which sub-assembly component item our specified
' component is located within.
Dim SubAssyOccItemNumber As Long
SubAssyOccItemNumber = 1
' Now we'll go down one level into the current sub-assembly component and check its
' sub-components for a matching component name.
For Each oSub2AssyCompOcc In oSub2AssyCompDef.Occurrences
If oSub2AssyCompOcc.Name = vCurrentCompName Then
' If the current oSub2AssyCompOcc's definition document type is that of an
' assembly document, we'll check its contents to ensure that it contains
' components that can actually be made invisible before proceeding. This is
' done to avoid the run-time error that we get when we attempt to hide a
' sub-assembly component that's simply an empty placeholder component.
' These placeholder components are in the assembly component solely to have
' its iProperties included on the B.O.M., so we're not to be concerned with
' hiding them.
If oSub2AssyCompOcc.DefinitionDocumentType = kAssemblyDocumentObject Then
Dim oSub3AssyCompDef As AssemblyComponentDefinition
Set oSub3AssyCompDef = oSub2AssyCompOcc.Definition
' We'll pass all of the necessary info on to our CheckAndHideSubAssyComps()
' sub-routine to recursively scan the rest of the sub-assembly layers to
' find & hide the user-specified component.
Call CheckAndHideSubAssyComps(oView, oSub3AssyCompDef, oSub1AssyCompDef, AssyOccItemNumber, SubAssyOccItemNumber)
' If the current oSub2AssyCompOcc is NOT an assembly document object, then we
' just hide it; it's likely just a part component.
ElseIf oSub2AssyCompOcc.DefinitionDocumentType <> kAssemblyDocumentObject Then
' We'll create a proxy of our component so that we can properly tell oView
' to hide it.
Dim oSubCompProxy As ComponentOccurrenceProxy
Set oSubCompProxy = oSub1AssyCompDef.Occurrences.Item(AssyOccItemNumber).SubOccurrences.Item(SubAssyOccItemNumber)
' Toggle visibility of components in subassembly.
If oView.GetVisibility(oSubCompProxy) = True Then
Call oView.SetVisibility(oSubCompProxy, False)
End If
End If
End If
SubAssyOccItemNumber = SubAssyOccItemNumber + 1
Next
End If
'==================================
' Single Component Hiding Block End
'==================================
'===================================
' Batch Component Hiding Block Begin
'===================================
' If a colon is NOT present in sCompName's value, then we run this ElseIf-Then code block to
' find & hide all occurrences of the specified component part number.
ElseIf bIsCompName1Occ = False Then
' First, we need to take the current oSub1AssyCompOcc's name and split it into an array.
' - sCompOccName(0) will contain the oSub1AssyCompOcc's part number.
' - sCompOccName(1) will contain the oSub1AssyCompOcc's occurrence number.
Dim sCompOccName() As String
sCompOccName() = Split(oSub1AssyCompOcc.Name, ":") ' sCompOccName(0) = "1003UA30055-WT"; sCompOccName(1) = "1"
' If the current oSub1AssyCompOcc's part number matches the user-specified component,
' then we proceed as normal and hide the current oSub1AssyCompOcc.
If sCompOccName(0) = vCurrentCompName Then ' Returns True
If oView.GetVisibility(oSub1AssyCompOcc) = True Then
Call oView.SetVisibility(oSub1AssyCompOcc, False)
End If
End If
' If the current oSub1AssyCompOcc's name doesn't match the user-specified component AND
' it's an assembly component that is not suppressed, then we dive deeper to search the
' components within oSub1AssyCompOcc.
If oSub1AssyCompOcc.Definition.Type = kAssemblyComponentDefinitionObject Then
' This variable gets the assembly component definition of the current oSub1AssyCompOcc
' object.
Set oSub2AssyCompDef = oSub1AssyCompOcc.Definition
' This variable will keep count of which sub-assembly component item our specified
' component is located within.
SubAssyOccItemNumber = 1
For Each oSub2AssyCompOcc In oSub2AssyCompDef.Occurrences
Dim sSubCompOccName() As String
sSubCompOccName() = Split(oSub2AssyCompOcc.Name, ":") ' sSubCompOccName(0) = "1003EG031"; sSubCompOccName(1) = "1"
If sSubCompOccName(0) = vCurrentCompName Then
' If the current oSub2AssyCompOcc's definition document type is that of an
' assembly document, we'll check its contents to ensure that it contains
' components that can actually be made invisible before proceeding. This is
' done to avoid the run-time error that we get when we attempt to hide a
' sub-assembly component that's simply an empty placeholder component.
' These placeholder components are in the assembly component solely to have
' its iProperties included on the B.O.M., so we're not to be concerned with
' hiding them.
If oSub2AssyCompOcc.DefinitionDocumentType = kAssemblyDocumentObject Then
Set oSub3AssyCompDef = oSub2AssyCompOcc.Definition
' We'll pass all of the necessary info on to our CheckAndHideSubAssyComps()
' sub-routine to recursively scan the rest of the sub-assembly layers to
' find & hide the user-specified component.
Call CheckAndHideSubAssyComps(oView, oSub3AssyCompDef, oSub1AssyCompDef, AssyOccItemNumber, SubAssyOccItemNumber)
' If the current oSub2AssyCompOcc is NOT an assembly document object, then we
' just hide it; it's likely just a part component.
ElseIf oSub2AssyCompOcc.DefinitionDocumentType <> kAssemblyDocumentObject Then
' We'll create a proxy of our component so that we can properly tell oView
' to hide it.
Set oSubCompProxy = oSub1AssyCompDef.Occurrences.Item(AssyOccItemNumber).SubOccurrences.Item(SubAssyOccItemNumber)
' Toggle visibility of components in subassembly.
If oView.GetVisibility(oSubCompProxy) = True Then
Call oView.SetVisibility(oSubCompProxy, False)
End If
End If
End If
SubAssyOccItemNumber = SubAssyOccItemNumber + 1
Next
End If
Else
MsgBox ("ERROR: Invalid value for bIsCompName1Occ variable.")
End If
'=================================
' Batch Component Hiding Block End
'=================================
End If
AssyOccItemNumber = AssyOccItemNumber + 1
Next
lViewCounter = lViewCounter + 1
Wend
Next
End Sub
Public Sub CheckAndHideSubAssyComps(oView, oCurrentSubAssyCompDef, oSub1AssyCompDef, AssyOccItemNumber, SubAssyOccItemNumber)
' This sub-routine will handle the sometimes recursive activity of hiding a sub-assembly by checking each of its
' components for SurfaceBodies to hide. Attempting to hide a sub-component that doesn't have any SurfaceBodies
' (i.e. trying to hide the empty placeholder sub-components that are used only for their iProperties) causes an
' error to occur, so in such a scenario it's easier to cherry-pick through a sub-assembly's components in order
' to hide the components with actual 3D models in them.
' This sub-routine takes in a number of variables and checks if the given sub-assembly's components have
' SurfaceBodies. If they do, they get hidden. If another sub-sub-assembly is found within the given sub-assembly,
' this sub-routine will call upon itself again and pass along the sub-sub-assembly for processing.
Dim oCurrentSubAssyCompOcc As ComponentOccurrence
For Each oCurrentSubAssyCompOcc In oCurrentSubAssyCompDef.Occurrences
If oCurrentSubAssyCompOcc.SurfaceBodies.Count > 0 Then
' We'll create a proxy of our component so that we can properly tell oView to hide it.
Dim oCurrentSubAssyCompProxy As ComponentOccurrenceProxy
Set oCurrentSubAssyCompProxy = oSub1AssyCompDef.Occurrences.Item(AssyOccItemNumber).SubOccurrences.Item(SubAssyOccItemNumber)
' Toggle visibility of components in subassembly.
If oView.GetVisibility(oCurrentSubAssyCompProxy) = True Then
Call oView.SetVisibility(oCurrentSubAssyCompProxy, False)
End If
' If it turns out that the current sub-assembly component is ALSO an kAssemblyDocumentObject, then we create a new AssemblyComponentDefinition
' and recursively call upon this sub-routine to check the current sub-assembly component's sub-components.
ElseIf oCurrentSubAssyCompOcc.DefinitionDocumentType = kAssemblyDocumentObject Then
' This variable will be the AssemblyComponentDefinition that gets passed on to CheckAndHideSubAssyComps().
Dim oInternalSubAssyCompDef As AssemblyComponentDefinition
Set oInternalSubAssyCompDef = oCurrentSubAssyCompOcc.Definition
Call CheckAndHideSubAssyComps(oView, oInternalSubAssyCompDef, oSub1AssyCompDef, AssyOccItemNumber, SubAssyOccItemNumber)
End If
Next
End Sub
There's a couple of interesting things that I've learned while figuring out this tool. First, Inventor gets angry and throws errors at you if you attempt to hide a component that doesn't contain any 3D models. The engineering team at my company sometimes create these empty placeholder components in their assembly models solely to make some additional unmodeled components appear on the assembly's B.O.M. I found that checking each sub-component's SurfaceBodies property helped to determine if it was something that's safe to hide.
Another interesting thing that I've learned was that the BrowserNodes in the Browser Window don't seem to have any direct connection to their counterparts within the assembly document. My need for a tool that could hide a specified folder in each DrawingView required that I dig through the BrowserNodes to find the components listed within a BrowserFolder. But since there's no BrowserNode property that directly links it to its component counterpart within the assembly model, I had to create a work-around method to solve my problem.
To solve my problem, I went about grabbing each BrowserNodes' FullPath property, Split()ing them up into a Variant array, and then extracting the part numbers & occurrence numbers of each component from the Variant array's last two elements. I then used my FindAndHideComponents() sub-routine to seek out & hide all applicable components whose Name property matched the extracted part numbers & occurrence numbers.
I can bet that this really long-winded post might be about a topic that a lot of you may have already figured out a loooooooong time ago. But with all of the google & forum-searching that I've done, none of them really had the solution to this problem that I was looking for. I'd be happy to let this post collect a lot of dust digitally in the back of a server hard drive somewhere for the rest of human existence for one single reason - that some other beginner like me may come along looking for this same exact answer, and will rejoice in finding all of this info in a single spot on the internet.
So I'll just make this post, pat myself on the back, and give myself a Kudo for solving my problem and sharing with everyone else. Enjoy!
- Vinny