3
$\begingroup$

I have a panel in 3D_View that shows the current file and allows the selection of a new file. When the file is selected, the panel needs to redraw. How do I force a redraw?

In Operator.py file

class OT_TestOpenFilebrowser(Operator, ImportHelper): 
    #https://sinestesia.co/blog/tutorials/using-blenders-filebrowser-with-python/
    bl_idname = "file.open_filebrowser" 
    bl_label = "Open the file browser (yay)" 
    filter_glob: StringProperty( default='*.xml', options={'HIDDEN'} )
    run=0
    def execute(self, context): 
        if not 'PMTfileName' in globals():
            global PMTfileName
            PMTfileName = "None2"        
            self.report({'INFO'}, PMTfileName+ " created in op") 
        PMTfileName, extension = os.path.splitext(self.filepath)
        head_tail = os.path.split(self.filepath) 
        PMTfileName = head_tail[1]
        print(PMTfileName)
        self.report({'INFO'}, PMTfileName)
        self.report({'INFO'}, extension)
        self.report({'INFO'}, self.filepath)
        context.area.tag_redraw()
        self.__class__.run += 1
        """Do something with the selected file(s).""" 
        return {'FINISHED'}
bpy.utils.register_class(OT_TestOpenFilebrowser)

If Panel file:

class PMT_PT_Pannel(Panel):
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_label = "PMT Builder"
    bl_category = "21Geo Builder"

    def draw(self, context):
        global PMTfileName
        layout = self.layout

        #2 Columns with Buttons
        box = layout.box()
        box.label(text="Open File: "+PMTfileName) 
        row = layout.row()
        row2 = layout.row()

        col3 = row.column()
        col3.operator("file.open_filebrowser", text="Select File" )


        col = row2.column()
        col.operator("object.apply_all_mods", text="Apply all")

        col2 = row2.column()
        col2.operator("export.some_data", text="Export")
$\endgroup$

2 Answers 2

4
$\begingroup$

I suggest start here: How to create a custom UI?


Blender will take care of (re-)drawing the layout properly without doing anything if you add a dedicated StringProperty for your filepath to the Scene, Object or whatever makes sense in your case eg. bpy.types.Scene.my_path = StringProperty(name="My Path") and assign self.filepath attribute from the ImportHelper class to your path property:

enter image description here

Code example based on the famous Operator File Import template that comes with Blender:

import bpy
import os

# ImportHelper is a helper class, defines filename and
# invoke() function which calls the file selector.
from bpy_extras.io_utils import ImportHelper
from bpy.props import StringProperty, BoolProperty, EnumProperty
from bpy.types import Operator, Panel


class ImportSomeData(Operator, ImportHelper):
    """This appears in the tooltip of the operator and in the generated docs"""
    bl_idname = "import_test.some_data"  # important since its how bpy.ops.import_test.some_data is constructed
    bl_label = "Import XML Data"

    # ImportHelper mixin class uses this
    filename_ext = ".xml"

    filter_glob: StringProperty(
        default="*.xml",
        options={'HIDDEN'},
        maxlen=255,  # Max internal buffer length, longer would be clamped.
    )

    # List of operator properties, the attributes will be assigned
    # to the class instance from the operator settings before calling.
    use_setting: BoolProperty(
        name="Example Boolean",
        description="Example Tooltip",
        default=True,
    )

    def execute(self, context):
        folder, file = os.path.split(self.filepath)
        context.scene.my_path = self.filepath
        print (folder, file)
        return {'FINISHED'}


class OBJECT_PT_CustomPanel(Panel):
    bl_label = "My Panel"
    bl_idname = "OBJECT_PT_custom_panel"
    bl_space_type = "VIEW_3D"   
    bl_region_type = "UI"
    bl_category = "Tools"
    bl_context = "objectmode"
    '''
    @classmethod
    def poll(self,context):
        return context.object is not None
    '''
    def draw(self, context):
        layout = self.layout
        scene = context.scene
        layout.prop(scene, "my_path", text="File")
        layout.operator(ImportSomeData.bl_idname)
        layout.separator()
        
def register():
    bpy.utils.register_class(ImportSomeData)
    bpy.utils.register_class(OBJECT_PT_CustomPanel)
    bpy.types.Scene.my_path = StringProperty(name="My Path")


def unregister():
    bpy.utils.unregister_class(OBJECT_PT_CustomPanel)
    bpy.utils.unregister_class(ImportSomeData)
    del bpy.types.Scene.my_path


if __name__ == "__main__":
    register()

    # test call
    #bpy.ops.import_test.some_data('INVOKE_DEFAULT')
$\endgroup$
3
  • $\begingroup$ When I do this I get this error: AttributeError: Writing to ID classes in this context is not allowed: Scene, Scene datablock, error setting Scene.my_path $\endgroup$
    – doby
    Commented Feb 20, 2021 at 2:54
  • $\begingroup$ Are you trying to re-write the property (assigning something to my_path) within the panel class...? If so, please study my demo code. OR What part of my demo code do you have changed to get this error? Tested on 2.91 but I don't see any reason why it should not work for versions pre 2.91 @doby Can not help much based on your comment, I suggest edit your question and add more detail about what you're doing exactly. $\endgroup$
    – brockmann
    Commented Feb 20, 2021 at 8:21
  • $\begingroup$ I got it working. I failed to see that you initialized the variable in the execute. It worked once I did that. Thank you! $\endgroup$
    – doby
    Commented Feb 21, 2021 at 16:15
1
$\begingroup$

bpy.data.screens['Layout'].areas[3].regions[3].tag_redraw()

works in v3.3.

More generally, you can figure out the area and region index you need by typing / iterating though

bpy.data.screens[<screen/tab name>].areas[x].type

bpy.data.screens[<screen/tab name>].areas[x].regions[y].type

in the interactive console since this displays the name of that area/region as they aren't keyed like the screens are.

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .