Define the file name : collection or active object name

Hi,

I try to create this script but I’m newbie in python

image

The aim is to export a fbx in specific folder when you click Export button.
If the checkbox is True, then the filename get the name of collection. Conversely, if is uncheck the the filename get the active object.

Here is my own script but i get an error message which says name ‘filename’ is not defined.
Thanks for your help.

bl_info = {
    "name" : "MyTab", 
    "author" : "Mary Kita",
    "version" :(0, 1),
    "blender" : (2, 93, 6),
    "location":"View3D > Tool",
    "warning":"",
    "wiki_url":"",
    "category": "Custom" 
}    

import bpy
from bpy.props import BoolProperty

bpy.types.Scene.my_checkbox = BoolProperty(
    name="is Collection",
    description="is Collection ?",
    default = False)
        
class MyPanel_PT_Panel(bpy.types.Panel): 
    bl_label = "MyPanel" 
    bl_idname = "my_panel" #id name du premier panneau 
    bl_space_type = 'VIEW_3D' # le type d'espace c'est à dire espace 3D
    bl_region_type = 'UI'  # ca agit sur quoi ? sur l'UI
    bl_category = 'MyTab' # nom de l'outil qui sera affiché sur les onglets tools
    
    
    def draw(self, context):
        layout = self.layout
        
        
        row = layout.row()
        layout.prop(context.scene, "my_prop") 
        row = layout.row()
        row.operator("fbx.exporter",text="Export")
        
        if (bpy.types.Scene.my_checkbox == True):
            fileName = bpy.context.collection.name + '.fbx'
        else:
            fileName = bpy.context.active_object.name + '.fbx'
                     
      
class Fbx_Exporter(bpy.types.Operator):
    # export in a Substance Folder for Stone project     # Use this as a tooltip for menu items and buttons.
    bl_idname = "fbx.exporter"        # Unique identifier for buttons and menu items to reference.
    bl_label = "fbx_exporter"         # Display name in the interface.
    bl_options = {'REGISTER', 'UNDO'}  # Enable undo for the operator.

    def execute(self, context):        # execute() is called when running the operator.

        # Get the selected objects
        selectedObject = bpy.context.selected_objects

        # Get the name of selected object
        for obj in selectedObject:
            
            # to define folderPath
            # rajouter trjs \\ pour définir un chemin
            
            folderPath = 'C:\\Users\\MaryKita\\Desktop\\FbxFolder\\'
            
            # customfilePath will be used to filepath of FPX API operator
            customFilePath = folderPath + fileName

            # FBX API operator

            bpy.ops.export_scene.fbx(filepath= customFilePath, check_existing=True, filter_glob='*.fbx', use_selection=True, use_active_collection=False, global_scale=1.0, apply_unit_scale=True, apply_scale_options='FBX_SCALE_UNITS', bake_space_transform=False, object_types={'ARMATURE', 'CAMERA', 'EMPTY', 'LIGHT', 'MESH', 'OTHER'}, use_mesh_modifiers=True, use_mesh_modifiers_render=True, mesh_smooth_type='OFF', use_subsurf=False, use_mesh_edges=False, use_tspace=False, use_custom_props=False, add_leaf_bones=True, primary_bone_axis='Y', secondary_bone_axis='X', use_armature_deform_only=False, armature_nodetype='NULL', bake_anim=True, bake_anim_use_all_bones=True, bake_anim_use_nla_strips=True, bake_anim_use_all_actions=True, bake_anim_force_startend_keying=True, bake_anim_step=1.0, bake_anim_simplify_factor=1.0, path_mode='AUTO', embed_textures=False, batch_mode='OFF', use_batch_own_dir=True, use_metadata=True, axis_forward='-Z', axis_up='Y')

               
            

        return {'FINISHED'}            # Lets Blender know the operator finished successfully.  
    

    
def register():
    bpy.utils.register_class(MyPanel_PT_Panel)
    bpy.utils.register_class(Fbx_Exporter)
    
    
   
   

def unregister ():
    bpy.utils.unregister_class(MyPanel_PT_Panel)
    bpy.utils.unregister_class(Fbx_Exporter)
    
    
    
if __name__== "__main__":
    register()

I found the answer.
Thanks !

I found that a better place for ask such questions is here

P.S. do not forget to add a tag “python”

Try this updated code:

bl_info = {
    "name" : "MyTab", 
    "author" : "Mary Kita",
    "version" :(0, 1),
    "blender" : (2, 93, 0),
    "location":"View3D > Tool",
    "description": "here your addon description", 
    "doc_url": "",
    "tracker_url": "",  
    "category": "Custom" 
}    

import bpy
from bpy.types import Operator, PropertyGroup, Panel


# Recursivly transverse layer_collection for a particular name
def recurLayerCollection(layerColl, collName):
    found = None
    if (layerColl.name == collName):
        return layerColl
    for layer in layerColl.children:
        found = recurLayerCollection(layer, collName)
        if found:
            return found
        
        
class MYPANEL_PT_panel(Panel): 
    bl_label = "MyPanel" 
#    bl_idname = "my_panel" #id name du premier panneau 
    bl_space_type = 'VIEW_3D' # le type d'espace c'est à dire espace 3D
    bl_region_type = 'UI'  # ca agit sur quoi ? sur l'UI
    bl_category = 'MyTab' # nom de l'outil qui sera affiché sur les onglets tools    
    
    def draw(self, context):
        mypanel_props = context.scene.MYPANEL_PG_props
        layout = self.layout        
        
        row = layout.row()
        row.prop(mypanel_props, "my_checkbox")
        row = layout.row()
        row.prop(mypanel_props, "my_folder")
        row = layout.row()
        row.operator("fbx.exporter",text="Export")
        
             
class MYPANEL_OT_operator(Operator):
    # export in a Substance Folder for Stone project     # Use this as a tooltip for menu items and buttons.
    bl_idname = "fbx.exporter"        # Unique identifier for buttons and menu items to reference.
    bl_label = "fbx_exporter"         # Display name in the interface.
    bl_options = {'REGISTER', 'UNDO'}  # Enable undo for the operator.
    
    def execute(self, context):        # execute() is called when running the operator.
        
        mypanel_props = context.scene.MYPANEL_PG_props  
        
        # Get the selected objects
        selectedObject = context.selected_objects
        
        # Get the active object
        activeObject = context.view_layer.objects.active

        # Get the name of selected object
        for obj in selectedObject:
            
            # to define folderPath
            # rajouter trjs \\ pour définir un chemin            
            folderPath = mypanel_props.my_folder
            
            if mypanel_props.my_checkbox == True:              

                #Switching active Collection to active Object selected
                ucol = context.object.users_collection
                for i in ucol:
                    layer_collection = bpy.context.view_layer.layer_collection
                    layerColl = recurLayerCollection(layer_collection, i.name)
                    bpy.context.view_layer.active_layer_collection = layerColl
                
                fileNameCol = bpy.context.collection.name + '_collection.fbx'
                
                # customfilePath will be used to filepath of FPX API operator
                customFilePath = folderPath + fileNameCol
            
                # FBX API operator
                bpy.ops.export_scene.fbx(
                    filepath= customFilePath,
                    check_existing=True,
                    filter_glob='*.fbx',
                    use_selection=True,
                    use_active_collection=False,
                    global_scale=1.0,
                    apply_unit_scale=True,
                    apply_scale_options='FBX_SCALE_UNITS',
                    bake_space_transform=False,
                    object_types={'ARMATURE', 'CAMERA', 'EMPTY', 'LIGHT', 'MESH', 'OTHER'},
                    use_mesh_modifiers=True,
                    use_mesh_modifiers_render=True,
                    mesh_smooth_type='OFF',
                    use_subsurf=False,
                    use_mesh_edges=False,
                    use_tspace=False,
                    use_custom_props=False,
                    add_leaf_bones=True,
                    primary_bone_axis='Y',
                    secondary_bone_axis='X',
                    use_armature_deform_only=False,
                    armature_nodetype='NULL',
                    bake_anim=True,
                    bake_anim_use_all_bones=True,
                    bake_anim_use_nla_strips=True,
                    bake_anim_use_all_actions=True,
                    bake_anim_force_startend_keying=True,
                    bake_anim_step=1.0,
                    bake_anim_simplify_factor=1.0,
                    path_mode='AUTO',
                    embed_textures=False,
                    batch_mode='OFF',
                    use_batch_own_dir=True,
                    use_metadata=True,
                    axis_forward='-Z',
                    axis_up='Y'
                    )

            if mypanel_props.my_checkbox == False:
                # deselecting all and make each previously selected objects by one selected and active
                bpy.ops.object.select_all(action='DESELECT')
                bpy.context.view_layer.objects.active = obj
                obj.select_set(True)
                
                fileNameObj = bpy.context.active_object.name + '.fbx'
                
                # customfilePath will be used to filepath of FPX API operator
                customFilePath = folderPath + fileNameObj
            
                # FBX API operator
                bpy.ops.export_scene.fbx(
                    filepath= customFilePath,
                    check_existing=True,
                    filter_glob='*.fbx',
                    use_selection=True,
                    use_active_collection=False,
                    global_scale=1.0,
                    apply_unit_scale=True,
                    apply_scale_options='FBX_SCALE_UNITS',
                    bake_space_transform=False,
                    object_types={'ARMATURE', 'CAMERA', 'EMPTY', 'LIGHT', 'MESH', 'OTHER'},
                    use_mesh_modifiers=True,
                    use_mesh_modifiers_render=True,
                    mesh_smooth_type='OFF',
                    use_subsurf=False,
                    use_mesh_edges=False,
                    use_tspace=False,
                    use_custom_props=False,
                    add_leaf_bones=True,
                    primary_bone_axis='Y',
                    secondary_bone_axis='X',
                    use_armature_deform_only=False,
                    armature_nodetype='NULL',
                    bake_anim=True,
                    bake_anim_use_all_bones=True,
                    bake_anim_use_nla_strips=True,
                    bake_anim_use_all_actions=True,
                    bake_anim_force_startend_keying=True,
                    bake_anim_step=1.0,
                    bake_anim_simplify_factor=1.0,
                    path_mode='AUTO',
                    embed_textures=False,
                    batch_mode='OFF',
                    use_batch_own_dir=True,
                    use_metadata=True,
                    axis_forward='-Z',
                    axis_up='Y'
                    )

        # restoring original selection
        for obj in selectedObject:
            obj.select_set(True)
        # restoring original active object
        bpy.context.view_layer.objects.active = activeObject
            
        # Lets Blender know the operator finished successfully.    
        return {'FINISHED'}  
    

class MYPANEL_PG_props(PropertyGroup):

    my_checkbox: bpy.props.BoolProperty(
        name="is Collection",
        description="is Collection ?",
        default = False
        )
        
    my_folder: bpy.props.StringProperty(
        name = "Path",
        description = "Path to the folder containing the files to import",
        default = "C:\\Users\\MaryKita\\Desktop\\FbxFolder\\",
        subtype = 'DIR_PATH'
        )
        
        
classes = (
    MYPANEL_PT_panel,    
    MYPANEL_OT_operator,
    MYPANEL_PG_props,    
)

register, unregister = bpy.utils.register_classes_factory(classes)

def register():    
    for c in classes:
        bpy.utils.register_class(c)

    bpy.types.Scene.MYPANEL_PG_props = bpy.props.PointerProperty(type = MYPANEL_PG_props)

def unregister():
    for c in classes:
        bpy.utils.unregister_class(c)
    
    del bpy.types.Scene.MYPANEL_PG_props
    
if __name__ == "__main__":
    register()

Note:

  • if “is Collection” not active, it creates *.fbx file for each object selected.
  • if “is Collection” is active, it creates *_collection.fbx file for selected objects and name it with collection name where active selected object is located.
  • added a “Path” option where you can specify a destination folder.
1 Like

Thank you Apec.

An another guy already helped me in an another Forum but it’s interesting for me to read an another code so thank you.
Here the code corrected by this person :

bl_info = {
    "name" : "MyTab",  
    "author" : "",
    "version" :(0, 1),
    "blender" : (2, 93, 6),
    "location":"View3D > Tool",
    "warning":"",
    "wiki_url":"",
    "category": "Custom"  ### use "Tool" here if Panel should be in View3D > Tool ; no existing category = new tab
}    

import bpy
from bpy.props import BoolProperty

bpy.types.Scene.my_checkbox = BoolProperty(
    name="is Collection",
    description="is Collection ?",
    default = False)   

    
class MyPanel_PT_Panel(bpy.types.Panel): 
    bl_label = "MyPanel" 
    bl_idname = "MY_PT_PANEL"  ### avoid PT warning    #id name du premier panneau  
    bl_space_type = 'VIEW_3D' # le type d'espace c'est à dire espace 3D
    bl_region_type = 'UI'  # ca agit sur quoi ? sur l'UI
    bl_category = 'MyTab' # nom de l'outil qui sera affiché sur les onglets tools
    
    def draw(self, context):
        layout = self.layout
        row = layout.row()

        layout.prop(context.scene, "my_checkbox") ### use prop identifier , "scene.my_prop" is not registered
        row = layout.row()
        row.operator("fbx.exporter",text="Export")
        
#        if (bpy.types.Scene.my_checkbox == True):              ### moved to operator, cause export op needs fileName
#            fileName = bpy.context.collection.name + '.fbx'
#        else:
#            fileName = bpy.context.active_object.name + '.fbx'
                     
      
class Fbx_Exporter(bpy.types.Operator):
    # export in a Substance Folder for Stone project     # Use this as a tooltip for menu items and buttons.
    bl_idname = "fbx.exporter"        # Unique identifier for buttons and menu items to reference.
    bl_label = "fbx_exporter"         # Display name in the interface.
    bl_options = {'REGISTER', 'UNDO'}  # Enable undo for the operator.   ### undo export ???

    def execute(self, context):        # execute() is called when running the operator.

#       if (bpy.types.Scene.my_checkbox == True):    ### this calls the rna_property not the value
        if context.scene.my_checkbox == True:        ### prop 'my_checkbox' is registered in scene 
            fileName = bpy.context.collection.name + '.fbx'    ### returns 'Master Collection.fbx' if active collection is 'Scene Collection' 
        else:
            fileName = bpy.context.active_object.name + '.fbx' ### returns '[active obj].fbx' , e.g 'Cube.fbx'


        # Get the selected objects
#       selectedObject = bpy.context.selected_objects  ### no need cause by default bpy.ops.export_scene.fbx(use_selection = True)
        
        # Get the name of selected object   
#       for obj in selectedObject:    ### no, this gets each obj in list ; if names: for obj.name in selectedObject:  ... but
        ### ... you export the same object several times, according to the number of selected objects            

            # to define folderPath
            # rajouter trjs \\ pour définir un chemin
            
        folderPath = 'C:\\Users\\Username\\Desktop\\FbxFolder\\'  ### unindent next lines to execute once 
          
        # customfilePath will be used to filepath of FPX API operator
        customFilePath = folderPath + fileName
        

        # FBX API operator
        ### no need to call default options again if not changed, see blue ones in API bpy.ops.export_scene.fbx()
        bpy.ops.export_scene.fbx(filepath= customFilePath, use_selection=True, use_active_collection=False, apply_scale_options='FBX_SCALE_UNITS')

        return {'FINISHED'}            # Lets Blender know the operator finished successfully.  
    

def register():
    bpy.utils.register_class(MyPanel_PT_Panel)
    bpy.utils.register_class(Fbx_Exporter)

def unregister ():
    bpy.utils.unregister_class(MyPanel_PT_Panel)
    bpy.utils.unregister_class(Fbx_Exporter)

    
if __name__== "__main__":
    register()