Using Blender's filebrowser with Python

Every now and then an addon requires that the user selects a spe­cif­ic file or path. Sure, you could just give users a sim­ple string input and let them copy/paste into it but how much cool­er would it be to let them pick a file from the file­brows­er?

Luckily Blender pro­vides a handy class that does almost every­thing for us.

Meet ImportHelper

Importhelper is a mix-in class found in the bpy_extras sub­mod­ule. It includes an invoke() func­tion that calls the file­brows­er and a few helper func­tions used in Blender’s importer addons. To use it all we have to do is extend it in our oper­a­tor. Let’s start by import­ing both ImportHelper and Operator.

from bpy_extras.io_utils import ImportHelper
from bpy.types import Operator

Now we can go ahead and cre­ate the oper­a­tor:

class OT_TestOpenFilebrowser(Operator, ImportHelper):

    bl_idname = "test.open_filebrowser"
    bl_label = "Open the file browser (yay)"

    def execute(self, context):
        """Do something with the selected file(s)."""

        return {'FINISHED'}

Yup, that’s it. Our new oper­a­tor already has an invoke() func­tion that calls the file­brows­er and when a user selects a file, it stores the file’s path in self.filepath. Note that this is a reg­u­lar StringProperty inside ImportHelper that we inher­it­ed when we sub­classed it.


To fil­ter the types of files shown to the user we have to add a filter_glob prop­er­ty to our class. This is a StringProperty with the list of exten­sions we want to show. Each exten­sion is writ­ten in wild­card style and is sep­a­rat­ed by a semi-colon. Note that strings longer that 255 could be cut (since that’s the inter­nal buffer size).

filter_glob: StringProperty(
    default='*.jpg;*.jpeg;*.png;*.tif;*.tiff;*.bmp',
    options={'HIDDEN'}
)

Also keep in mind that users can dis­able fil­ter­ing in the UI and select any kind of file. You might want to reject a file or do some­thing dif­fer­ent depend­ing on the exten­sion you receive. You can take care of that with good old spli­text().

filename, extension = os.path.splitext(self.filepath)

And what about adding set­tings to the file­brows­er screen? All you have to do is add prop­er­ties to the oper­a­tor as usu­al and they will show up in the brows­er.

    some_boolean: BoolProperty(
            name='Do a thing',
            description='Do a thing with the file you\'ve selected',
            default=True,
            )

Final code

import bpy
import os

from bpy.props import StringProperty, BoolProperty
from bpy_extras.io_utils import ImportHelper
from bpy.types import Operator


class OT_TestOpenFilebrowser(Operator, ImportHelper):

    bl_idname = "test.open_filebrowser"
    bl_label = "Open the file browser (yay)"
    
    filter_glob: StringProperty(
        default='*.jpg;*.jpeg;*.png;*.tif;*.tiff;*.bmp',
        options={'HIDDEN'}
    )
    
    some_boolean: BoolProperty(
        name='Do a thing',
        description='Do a thing with the file you\'ve selected',
        default=True,
    )

    def execute(self, context):
        """Do something with the selected file(s)."""

        filename, extension = os.path.splitext(self.filepath)
        
        print('Selected file:', self.filepath)
        print('File name:', filename)
        print('File extension:', extension)
        print('Some Boolean:', self.some_boolean)
        
        return {'FINISHED'}


def register():
    bpy.utils.register_class(OT_TestOpenFilebrowser)


def unregister():
    bpy.utils.unregister_class(OT_TestOpenFilebrowser)


if __name__ == "__main__":
    register()

    # test call
    bpy.ops.test.open_filebrowser('INVOKE_DEFAULT')

There’s also an ExportHelper class that includes some util­i­ties to check for exist­ing files and set­ting a default unti­tled file­name in the brows­er.

Did I miss some­thing? Let me know in the com­ments!

Tutorials(Blender, Python)Last updated 03.04.2020
All the posts you can read

7 Comments

  1. Vnny(9 months ago)

    script worked fine, but I still cant build a blender script with a but­ton for import file and one for export file! I just cant seem to get but­tons to work for me to open any­thing oth­er than blenders inten­tions, like “render.render” ! 5 days now and still cant get my head around it, but this is by far the best site vis­it­ed, nice and clean look­ing easy to fol­low.

    1. Diego Gangl(9 months ago)

      Hi Vnny, thanks for the com­ments! If you want to cre­ate cus­tom but­tons; you need to cre­ate, and reg­is­ter, your own oper­a­tors and then add them to a pan­el as but­tons (I assume that’s what you mean by Blender’s inten­tions).

  2. David John Hawley(8 months ago)

    One thing I can’t fig­ure out is how to get the result of the file dia­log back.
    I want to get a file­name in order to do some­thing, let’s call it ActualOperation(myObject), where myObject is an ElementTree.
    The exam­ples all show the oper­a­tion using the filepath to do ActualOperation, but as argu­ments are passsed in as prop­er­ties, and only sim­ple types are allowed, that is not pos­si­ble.
    So I want to do the obvi­ous, which is get the filepath back from the file dia­log some­how.

  3. danig(3 weeks ago)

    Hi Diego,
    thanks for all the use­ful blog posts!

    I try to make the Load but­ton only avail­able when a spec­i­fy file type is select­ed like a .exe but could not find out how that works. Do you know if this is pos­si­ble? and if so could you share some insights?

    1. Diego Gangl(3 weeks ago)

      Hi! As far as I know you can’t affect the but­tons in the file­brows­er while it’s open. What you can do is to fil­ter the files so only the ones you want to allow are vis­i­ble. Check out the ‘filter_glob‘ prop­er­ty I men­tion in the post for this. Just replace ‘*.jpg;*.jpeg;*.png;*.tif;*.tiff;*.bmp’ for ‘*.exe;’, or the for­mats you want to enable.

      Cheers o/

  4. Harold(3 days ago)

    Hi Diego,
    Thanks for this tuto­r­i­al.

    I’m using the ExportHelper class to export 3D objects. The func­tion­al­i­ty works fine. However, I want to add an addi­tion­al fea­ture to the class. I want the file­name exten­sion, “filename_ext”, to change depend­ing on the user selec­tion. For exam­ple, if the user selects the item “Animation” from the EnumProperty, then the “filename_ext” is set to a dif­fer­ent exten­sion.

    Is this pos­si­ble? if so, how would you do it?

    Here is a code snip­pet for your ref­er­ence.

    # ExportHelper mix­in class uses this

    filename_ext = “.xml”

    filter_glob = StringProperty(
    default=”*.xml”,
    options={‘HIDDEN’},
    maxlen=255, # Max inter­nal buffer length, longer would be clamped.
    )

    dataTypeToExport = EnumProperty(
    name=“Export Type”,
    description=“Choose data to export”,
    items=((‘Mesh’, “Mesh Data Only”, “Export Mesh Data only”),
    (‘Animation’, “Animation Data Only”, “Export Animation Data only”),
    (‘NavMesh’, “Navigation Data”, “Export NavMesh Data only”)),
    default=‘Mesh’,
    )

    1. Diego Gangl(3 days ago)

      Hey Harold,

      I haven’t test­ed this, but it should be pos­si­ble to change these val­ues before show­ing the file brows­er. You would have to over­ride the invoke() func­tion and set those val­ues before ‘context.window_manager.fileselect_add(self)‘. Basically copy and paste the invoke func­tion in the ExportHelper class in [BLENDER DIR]/scripts/modules/bpy_extras/io_utils.py. Then you can change
      the prop­er­ties like ‘self.filename_ext = ‘.txt’‘.

Leave a Reply

Your email address will not be published.