How to set a property based on an ImportHelper dialog?

Hello!

I’m working on a little plugin that imports some external data and also creates some Blender objects based on that data. I want to call up the import dialog (with ImportHelper in order to filter by file extension) and save the filepath returned by the import dialog as a property, to be used by other functions. Other functions would parse the filename, and look up some stuff in a little database I have, maybe move some things around that are already in the scene (or not), and also import that file. Alright.

The problem I’m having is that I can’t save the filepath anywhere, and I’m not sure where I should be saving it since I don’t want it attached to a mesh, etc. For example, here’s a snippet:


class SimSceneSettings(bpy.types.PropertyGroup) :
    
    ps_filepath = bpy.props.StringProperty (
        name = "File path for the ps mesh", 
        maxlen = 1024,
        default = ""
    )
# end SimSceneSettings


class PSDialog(Operator, ImportHelper):
    
    bl_idname = "sim_tools.imp_ps"
    bl_label = "PS"
    
    filename_ext = ".x3d"
    
    filter_glob = bpy.props.StringProperty (
        default = "*.x3d",
        options = {'HIDDEN'}
    )
 
    filepath = bpy.props.StringProperty (
        name = "File Path", 
        maxlen = 1024,
        default = ""
    )
    
 
    def execute(self, context) :
        context.scene.sim_tools.ps_filepath = self.properties.filepath
        print("inside execute: ", self.properties.filepath)
        return {'FINISHED'}

This prints the stuff preceded by “inside execute”, but context.scene.sim_tools.ps_filepath is empty after the dialog box returns. I need this property to stay put.

To call up the dialog box, I do Shift+A to call up my toolkit (function add_to_menu referenced below) , which puts one object on the scene at the start. It also draws a panel in the Tool Shelf which has a button which calls up PSDialog. The PropertyGroup is registered under scene, but I’m not sure if that’s correct.


def register() :
    bpy.utils.register_module(__name__)
    bpy.types.Scene.sim_tools = bpy.props.PointerProperty(type = SimSceneSettings)
    bpy.types.INFO_MT_add.prepend(add_to_menu)
# end register

def unregister() :
    del bpy.types.Scene.sim_tools
    bpy.utils.unregister_module(__name__)
    bpy.types.INFO_MT_add.remove(add_to_menu)
# end unregister

I hope this makes sense. I just want to save the filepath from the import dialog somewhere permanent, or at least, somewhere that lives as long as my Tool Shelf panel. Thank you!

This works fine for me. I’m assuming your add_to_menu is something similar to


def add_to_menu(self, context):
    self.layout.operator("sim_tools.imp_ps")


inside execute:  F:\blender
odes.crash.x3d


>>> C.scene.sim_tools.ps_filepath
'F:\\blender\
odes.crash.x3d'

Not exactly. Here’s some more code - I tried to explain it in words before to be more concise, but maybe it wasn’t clear.

add_to_menu doesn’t reference the file import dialog itself. It adds at least one mesh, as well as a panel in the Tool Shelf to modify that object, which has a button which you press to get the file import dialog. The idea is that, once I have the filename, the plugin will import the x3d file, but it’ll also adjust the size of the one mesh. That’s why I need to get the filename inside the “main” program. Leaving the mesh aside, here’s the relevant code:


class SimToolsStage(bpy.types.Operator) :
    bl_idname = "sim_tools.stage"
    bl_label = "Simulation Tools"
    bl_options = {'REGISTER', 'UNDO'}

    def draw(self, context) :
        layout = self.layout
        layout.operator("sim_tools.imp_ps")
        #this^ is the button that calls up the file import dialog
        #other stuff cut
    #end draw

    def main(self, context) :
        
        if context.scene.sim_tools.ps_filepath == ""  :
            print("FP Empty")
        else :
            print(context.scene.sim_tools.ps_filepath)

       #other stuff cut, incl. calls to another module to draw the mesh
        return {'FINISHED'}
    # end main
    

    def invoke(self, context, event) :
        self.main(context)
        return {'FINISHED'}
    # end invoke
    
    def execute(self, context) :
        self.main(context)
        return {'FINISHED'}
    # end execute
# end SimToolsStage

def add_to_menu(self, context) :
    self.layout.operator("sim_tools.stage", icon = 'PLUGIN')
# end add_to_menu

The problem is that the if statement in the main function always prints “FP Empty”, and if I check the value of context.scene.sim_tools.ps_filepath through the console, it also always says that it’s empty. Thank you.

The ImportHelper invokes a the filebrowser. If you don’t use the ImportHelper you need to add this to your invoke of the import op.


context.window_manager.fileselect_add(self)

I’m not sure if this is compatible with the register / undo operator in the op tool panel, and is my guess why your set up isn’t working. You may be able to use a StringProperty(subtype=‘FILE_PATH’) , but that doesn’t allow you to glob files.

Thank you for your help! I don’t know why it wasn’t working before, but it works now. I was fiddling around and checked the value of context.scene.sim_tools.ps_filepath through the console, and this time, it wasn’t empty! So, I just added an update function to ps_filepath property, and now it’s all good. Thanks again!