How to pass a destination folder string to my file exporter button?

Hi, I’m an absolute Python beginner trying to make a one-click-fbx-export button for the tools menu.
Somehow I was able make a file browser button for my panel:

col.prop(context.scene, "file_path", text="")

This is where I define the exported file’s name and location in my export operator:

target_file = os.path.join(directory, 'exported_file.fbx')

Obviously I am now trying to pass my file_path string to this variable called “directory”.

I know it can’t be that hard, or at least it shouldn’t be.
But no progress at all after nine(!) straight hours of googling, that’s kind of rough.
So maybe one of you can help me with this. That would be fantastic.

Based on your code,

directory = bpy.context.scene.file_path

Oh this works. Thank you!
For some reason it has to say “context.scene” in the prop or it won’t appear in the tools menu. I never figured out why.
But I guess it makes sense that by navigating to “context.scene” in the directory, I am able to access the prop from inside the operator. I see.

By the way, is there any way to cancel my operator if the path is invalid?
That huge error pop-up is kind of annoying.
I tried this:

if not os.path.exists(directory):
          return

But it said “incompatible return value”. I just want to completely cancel the darn thing.

It has to say context.prop because that is the data that contains the property “file_path”.
https://docs.blender.org/api/blender_python_api_current/bpy.types.UILayout.html

Regarding the invalid path:


if not os.path.exists(directory):    
    self.report({'ERROR'}, 'Invalid path') # let's the the user there was an error 
    return {'CANCELLED'}

Thanks again. That self.report works like a charm. The script is doing a perfect job, or at least it did.
Now that I’m testing it on another machine, I’m suddenly getting this error:

‘Scene’ object has no attribute ‘file_path’

I have no clue why it would suddenly not be able to get the file_path.
The file browser layout element is also not showing up anymore.
So here’s the entire thing, because after a whole morning of trying to fix this, I’m all out of ideas:

import bpy   
import os

class ToolsPanel(bpy.types.Panel):
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'
    bl_category = "Tools"
    bl_label = "FBX Exporter"
    file_path = bpy.props.StringProperty(subtype='DIR_PATH')

    # draw the gui
    def draw(self, context):
        lay = self.layout
        col = lay.column(align=True)
        row = col.row(align=True)        
        col.prop(context.scene, "file_path", text="")
        col.operator('tool.exportfbx', icon='EXPORT')
        
def get_filename():    
    filename = bpy.path.basename(bpy.context.blend_data.filepath)
    basename = os.path.splitext(filename)[0]
    return basename                
  
class ExportFBX(bpy.types.Operator):
    bl_idname = 'tool.exportfbx'
    bl_description = 'Export entire scene as .fbx file'
    bl_label = 'Export scene as FBX'

    def execute(self, context):      
        directory = bpy.context.scene.file_path
        if not os.path.exists(directory):
            self.report({'ERROR'}, 'Invalid path') # let's the the user there was an error
            return {'CANCELLED'}
        target_file = os.path.join(directory, get_filename() + '.fbx')        
        bpy.ops.object.mode_set(mode = 'OBJECT')
        bpy.ops.object.select_all(action='DESELECT')
        #fbx export properties go here
        bpy.ops.object.select_all(action='DESELECT')
        return {'FINISHED'}
      
# Registration
def register():
    bpy.utils.register_module(__name__)        
def unregister():
    bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
    register()

Add your own file path property in the register.


import bpy   
import os
from bpy.props import StringProperty


class ToolsPanel(bpy.types.Panel):
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'
    bl_category = "Tools"
    bl_label = "FBX Exporter"


    # draw the gui
    def draw(self, context):
        lay = self.layout
        col = lay.column(align=True)
        row = col.row(align=True)        
        col.prop(context.scene, 'fbx_export_path', text="")
        col.operator('tool.exportfbx', icon='EXPORT')
        
def get_filename():    
    filename = bpy.path.basename(bpy.context.blend_data.filepath)
    basename = os.path.splitext(filename)[0]
    return basename                
  
class ExportFBX(bpy.types.Operator):
    bl_idname = 'tool.exportfbx'
    bl_description = 'Export entire scene as .fbx file'
    bl_label = 'Export scene as FBX'


    def execute(self, context):      
        directory = bpy.context.scene.file_path
        if not os.path.exists(directory):
            self.report({'ERROR'}, 'Invalid path') # let's the the user there was an error
            return {'CANCELLED'}
        target_file = os.path.join(directory, get_filename() + '.fbx')        
        bpy.ops.object.mode_set(mode = 'OBJECT')
        bpy.ops.object.select_all(action='DESELECT')
        #fbx export properties go here
        bpy.ops.object.select_all(action='DESELECT')
        return {'FINISHED'}
      
# Registration
def register():
    bpy.utils.register_module(__name__)
    bpy.types.Scene.fbx_export_path = StringProperty(name='FBX Exporter Path', subtype='DIR_PATH')
    print('it registered')    
def unregister():
    bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
    register()

1 Like

Thank you very much, it all works now.
I still haven’t figured out what registering and unregistering even does or how to use it correctly, and there seems to be no place on the internet where a beginner can learn about these things. (Or at least that place is extremely well hidden.) Hopefully Youtube has some tutorials to offer, and I’ll eventually be able understand what you have done. Fingers crossed.
Thanks again. Bye.

Registering is for adding things like classes to Blender so they are available like default functionality. In your script, the register function adds you ToolPanel and FBX Exporter classes, and I added a string property to the scene data, so once registered, it is available for you to add a value to it, i.e. you file path, and use this elsewhere in your script.