13

I have a button in my menu named "New File" as shown:

enter image description here

and I want when I click on the "New File" button to imitate what the Blender File->New does, where a check message box appear first confirming that you want to reload the Start-up File and if pressed then the startup file is loaded as shown below.

enter image description here

This is my script, when I press on new it opens the startup file without checking:

class NewFile(bpy.types.Operator):
    """New File"""
    bl_idname = "wm.newfile"  
    bl_label = "New File"
    bl_options = {'REGISTER', 'UNDO'}

    def execute(self, context):
        bpy.ops.wm.read_homefile()
        return {"FINISHED"} 
p2or
  • 15,860
  • 10
  • 83
  • 143
Tak
  • 6,293
  • 7
  • 43
  • 85
  • My Python isn't the greatest, but this seems to work with wm.open_mainfile and wm.read_homefile. I tested with the ui panel template though, I hadn't seen your edit. – Timaroberts Feb 09 '17 at 05:54
  • @Timaroberts no it doesn't show the checking message – Tak Feb 09 '17 at 12:08
  • 1
    @poor thank you so much my friend, very detailed and beneficial (Y) :) – Tak Feb 13 '17 at 22:51

1 Answers1

43

When calling an operator via bpy.ops.* without any execution context the execute() method of the respective operator runs by default. If the operator provides any kind of 'user interaction' like a 'confirmation dialog' in this case, then you can pass 'INVOKE_DEFAULT' as execution context when calling the operator which will also run its invoke() method:

bpy.ops.wm.read_homefile('INVOKE_DEFAULT')

enter image description here

In order to display the operator as a button and also 'enable' its user interaction, you have to set the operator_context in the 'layout' before calling the operator:

enter image description here

Blender 2.7x

import bpy

class HelloWorldPanel(bpy.types.Panel): """Creates a Panel in the Object properties window""" bl_idname = "CUSTOM_my_panel" bl_label = "My Panel" bl_space_type = "VIEW_3D" bl_region_type = "TOOLS" bl_category = "Tools"

def draw(self, context):
    layout = self.layout
    layout.operator_context = 'INVOKE_DEFAULT' #'INVOKE_AREA'
    layout.operator("wm.read_homefile", text="New", icon='NEW')

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

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

if name == "main": register()

Blender 2.8x and beyond

class OBJECT_PT_CustomPanel(bpy.types.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"
def draw(self, context):
    layout = self.layout
    layout.operator_context = 'INVOKE_DEFAULT' #'INVOKE_AREA'
    layout.operator("wm.read_homefile", text="New", icon='FILE_NEW')

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

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

if name == "main": register()


Custom Confirm Dialog

For a custom conformation dialog you can wrap the operator into another one and invoke invoke_confirm(operator, event) classmethod of the window-manager to confirm the execution by the user.

enter image description here

Blender 2.7x

import bpy

class SimpleConfirmOperator(bpy.types.Operator): """Really?""" bl_idname = "my_category.custom_confirm_dialog" bl_label = "Do you really want to do that?" bl_options = {'REGISTER', 'INTERNAL'}

@classmethod
def poll(cls, context):
    return True

def execute(self, context):
    self.report({'INFO'}, "YES!")
    return {'FINISHED'}

def invoke(self, context, event):
    return context.window_manager.invoke_confirm(self, event)

class HelloWorldPanel(bpy.types.Panel): """Creates a Panel in the Object properties window""" bl_idname = "CUSTOM_my_panel" bl_label = "My Panel" bl_space_type = "VIEW_3D" bl_region_type = "TOOLS" bl_category = "Tools"

def draw(self, context):
    layout = self.layout
    layout.operator(SimpleConfirmOperator.bl_idname)

def register(): bpy.utils.register_class(SimpleConfirmOperator) bpy.utils.register_class(HelloWorldPanel)

def unregister(): bpy.utils.unregister_class(HelloWorldPanel) bpy.utils.unregister_class(SimpleConfirmOperator)

if name == "main": register()

Blender 2.8x and beyond

import bpy

class SimpleConfirmOperator(bpy.types.Operator): """Really?""" bl_idname = "my_category.custom_confirm_dialog" bl_label = "Do you really want to do that?" bl_options = {'REGISTER', 'INTERNAL'}

@classmethod
def poll(cls, context):
    return True

def execute(self, context):
    self.report({'INFO'}, "YES!")
    return {'FINISHED'}

def invoke(self, context, event):
    return context.window_manager.invoke_confirm(self, event)


class OBJECT_PT_CustomPanel(bpy.types.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"

def draw(self, context):
    layout = self.layout
    layout.operator(SimpleConfirmOperator.bl_idname)

def register(): bpy.utils.register_class(OBJECT_PT_CustomPanel) bpy.utils.register_class(SimpleConfirmOperator)

def unregister(): bpy.utils.unregister_class(SimpleConfirmOperator) bpy.utils.unregister_class(OBJECT_PT_CustomPanel)

if name == "main": register()


Property Confirm

In order to display a popup, some properties and an OK 'button' you can return wm.invoke_props_dialog(self) instead:

enter image description here

Blender 2.7x

import bpy

class SimplePropConfirmOperator(bpy.types.Operator): """Really?""" bl_idname = "my_category.custom_confirm_dialog" bl_label = "Do you really want to do that?" bl_options = {'REGISTER', 'INTERNAL'}

prop1 = bpy.props.BoolProperty()
prop2 = bpy.props.BoolProperty()

@classmethod
def poll(cls, context):
    return True

def execute(self, context):
    self.report({'INFO'}, "YES!")
    return {'FINISHED'}

def invoke(self, context, event):
    return context.window_manager.invoke_props_dialog(self)

def draw(self, context):
    row = self.layout
    row.prop(self, "prop1", text="Property A")
    row.prop(self, "prop2", text="Property B")


class HelloWorldPanel(bpy.types.Panel): """Creates a Panel in the Object properties window""" bl_idname = "CUSTOM_my_panel" bl_label = "My Panel" bl_space_type = "VIEW_3D" bl_region_type = "TOOLS" bl_category = "Tools"

def draw(self, context):
    layout = self.layout
    layout.operator(SimplePropConfirmOperator.bl_idname)

def register(): bpy.utils.register_class(SimplePropConfirmOperator) bpy.utils.register_class(HelloWorldPanel)

def unregister(): bpy.utils.unregister_class(HelloWorldPanel) bpy.utils.unregister_class(SimplePropConfirmOperator)

if name == "main": register()

Blender 2.8x and beyond

import bpy

class SimplePropConfirmOperator(bpy.types.Operator): """Really?""" bl_idname = "my_category.custom_confirm_dialog" bl_label = "Do you really want to do that?" bl_options = {'REGISTER', 'INTERNAL'}

prop1: bpy.props.BoolProperty()
prop2: bpy.props.BoolProperty()

@classmethod
def poll(cls, context):
    return True

def execute(self, context):
    self.report({'INFO'}, "YES!")
    return {'FINISHED'}

def invoke(self, context, event):
    return context.window_manager.invoke_props_dialog(self)

def draw(self, context):
    row = self.layout
    row.prop(self, "prop1", text="Property A")
    row.prop(self, "prop2", text="Property B")


class OBJECT_PT_CustomPanel(bpy.types.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"

def draw(self, context):
    layout = self.layout
    layout.operator(SimplePropConfirmOperator.bl_idname)

def register(): bpy.utils.register_class(OBJECT_PT_CustomPanel) bpy.utils.register_class(SimplePropConfirmOperator)

def unregister(): bpy.utils.unregister_class(SimplePropConfirmOperator) bpy.utils.unregister_class(OBJECT_PT_CustomPanel)

if name == "main": register()


Simple Popup

For the sake of completeness, you can also display a popup without any OK button by using wm.invoke_popup(self):

import bpy

class SimplePopUpOperator(bpy.types.Operator):
    """Really?"""
    bl_idname = "my_category.custom_popup_dialog"
    bl_label = "Do you really want to do that?"
    bl_options = {'REGISTER', 'INTERNAL'}

    prop1: bpy.props.BoolProperty()
    prop2: bpy.props.BoolProperty()

    @classmethod
    def poll(cls, context):
        return True

    def execute(self, context):
        self.report({'INFO'}, "YES!")
        return {'FINISHED'}

    def invoke(self, context, event):
        return context.window_manager.invoke_popup(self)

    def draw(self, context):
        row = self.layout
        row.label(text="Do you really want to do that?")
        row.prop(self, "prop1", text="Property A")
        row.prop(self, "prop2", text="Property B")


class OBJECT_PT_CustomPanel(bpy.types.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"

    def draw(self, context):
        layout = self.layout
        layout.operator(SimplePopUpOperator.bl_idname)

def register():
    bpy.utils.register_class(OBJECT_PT_CustomPanel)
    bpy.utils.register_class(SimplePopUpOperator)

def unregister():
    bpy.utils.unregister_class(SimplePropConfirmOperator)
    bpy.utils.unregister_class(SimplePopUpOperator)

if __name__ == "__main__":
    register()

Note: bl_options of both examples are set to 'INTERNAL' which excludes the operators from search results, remove it if you'd like to run the operator via space bar/F3.

Marty Fouts
  • 33,070
  • 10
  • 35
  • 79
p2or
  • 15,860
  • 10
  • 83
  • 143
  • Is it possible to create a dialog working similar to this, but in the style of the 2.80 save prompt from Python? – Ray Mar 05 '20 at 20:30
  • invoke_props_dialog, see the last example or all draw methods here. file dialog is written in C @Ray – p2or Mar 06 '20 at 13:51