In addition to common panels (N/T/Properties) and their sub-panels, to display the user interface elements while developing Blender add-ons you can also use pop-up panels appearing on the screen when a user presses a certain key combination or perform any action. The simplest example of such panels is the panel that appears when the f6 key is pressed immediately after adding an object (shift+a) to the scene.
Blender API provides developers the ability to create such panels for their add-ons. Let’s consider the creating of a pop-up panel as an example of the “Message box” window.
Unlike basic panels that have their own ancestor class bpy.types.Panel, the pop-up panel is essentially an operator accessing certain Blender window manager functions so it is inherited from the standard bpy.types.Operator class.
Let’s open the favorite code editor, create a basic body for the MessageBox class with the unique identifier “message.messagebox”, and also register this class in the Blender API.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
import bpy class MessageBox(bpy.types.Operator): bl_idname = "message.messagebox" bl_label = "" def register(): bpy.utils.register_class(MessageBox) def unregister(): bpy.utils.unregister_class(MessageBox) if __name__ == "__main__": register() |
To create a pop-up window we need to call the required function from the Blender window manager. Redefine the interactive function “invoke” of the operator to call the desired window manager function:
1 2 |
def invoke(self, context, event): return context.window_manager.invoke_props_dialog(self, width = 400) |
The function “invoke_props_dialog” creates the pop-up window what we need. In the function input parameters, we can specify the desired window sizes through the “width” and “height”. The first function parameter is a pointer to our current MessageBox (self) operator.
Depending on the type of the operator transferred to it, the function can return different values:
- RUNNING_MODAL – modal start
- CANCELED – cancel
- FINISHED – normal completion
- PASS_THROUGH – empty start (nothing done)
In general, FINISHED will be returned by clicking the “OK button and CANCELLED – by closing the window (pressing Esc or clicking outside window area).
If “invoke” returns FINISHED, our MessageBox operator runs the “execute” function. Redefine it to print the message to the status output and system console:
1 2 3 4 |
def execute(self, context): self.report({'INFO'}, self.message) print(self.message) return {'FINISHED'} |
The code of the MessageBox operator:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import bpy class MessageBox(bpy.types.Operator): bl_idname = "message.messagebox" bl_label = "" def execute(self, context): self.report({'INFO'}, self.message) print(self.message) return {'FINISHED'} def invoke(self, context, event): return context.window_manager.invoke_props_dialog(self, width = 400) def register(): bpy.utils.register_class(MessageBox) def unregister(): bpy.utils.unregister_class(MessageBox) if __name__ == "__main__": register() |
To test it, we can create a button (in the special part of the T-panel) executes our MessageBox operator, showing the “Sample Text” message:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
class panel1(bpy.types.Panel): bl_idname = "panel.panel1" bl_label = "Panel1" bl_space_type = "VIEW_3D" bl_region_type = "TOOLS" bl_category = "Panel1" def draw(self, context): self.layout.operator("message.messagebox", text = "message").message = 'Sample Text' def register(): bpy.utils.register_class(panel1) def unregister(): bpy.utils.unregister_class(panel1) if __name__ == "__main__": register() |
Just calling the “invoke_props_dialog” function, only the base window with an empty frame and the “OK” button displayed.
In order to place the necessary interface elements to it, we need to redefine the “draw” function of our operator. Elements placement is built through the common object “layout”.
Let’s place on the window the label element with the output message text:
1 2 3 |
def draw(self, context): self.layout.label(self.message) self.layout.label("") |
The second line with an empty label is needed only to make some gap between the message and the “OK” button.Define the “message” input parameter in our MessageBox operator to show its value in a pop-up window:
Define the “message” input parameter in the MessageBox operator to show its value in a pop-up window:
1 2 3 4 5 |
message = bpy.props.StringProperty( name = "message", description = "message", default = '' ) |
The complete code of the MessageBox operator:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
import bpy class MessageBox(bpy.types.Operator): bl_idname = "message.messagebox" bl_label = "" message = bpy.props.StringProperty( name = "message", description = "message", default = '' ) def execute(self, context): self.report({'INFO'}, self.message) print(self.message) return {'FINISHED'} def invoke(self, context, event): return context.window_manager.invoke_props_dialog(self, width = 400) def draw(self, context): self.layout.label(self.message) self.layout.label("") def register(): bpy.utils.register_class(MessageBox) def unregister(): bpy.utils.unregister_class(MessageBox) if __name__ == "__main__": register() |
This is the final code of the operator. When called, it will display a window with the text message sent.
In addition to text fields. any user interface elements – buttons, labels, checkboxes, input fields, etc. can be placed on such type of a window.
Mini-bonus:
This MessageBox class is fully functional for use in any Blender add-ons. It can be saved in a separate file and if the developed add-on requires the message output, you can import it and use its functionality.
1 2 3 4 5 6 |
# somewhere in the add-on code import messagebox msg = 'Message Text' bpy.ops.message.messagebox('INVOKE_DEFAULT', message = msg) |
thank you so much for your site it’s so awesome it’s really helping me build my add on up
file?
Just copy the “complete code of the MessageBox operator” to your file.
Hi mate,
Thanks for sharing knowledge. I am starting to learn Blender python and I appreciate every little bit. I’ve tried running this script in 2.79 but no message box appears. Any idea why?
Hello!
After running script do you execute bpy.ops.message.messagebox(‘INVOKE_DEFAULT’, message = ‘my text’) in the python console window?
That did the trick. So this is a messagebox only as test for adding the future addon parameters, right? Would it always be called by F6 or do you have to script that in too?
This class is the operator. By calling bpy.ops.message.messagebox() command you make this operator be executed. Of course, this is the simplest example. You can draw buttons, text fields, parameter fields etc. And of course, you can map calling command to F6 shortcut or to any other.
I understand now. Thanks for your time mate. I appreciate your prompt replies.
After calling the pop-up, if i want to remove the pop-up, either i need to press the “OK” button to execute my task, and to cancel i need to press ESC. But if i press “ENTER” key, then my blender close.
Can you please help me to find out the solution of this problem.
What the error Blender reports? If it closes, you can see the error message if you starts Blender from command line (see here: https://b3d.interplanety.org/en/how-to-check-errors-if-blender-closes-together-with-system-console-window/)
class dialog_back(bpy.types.Operator):
bl_idname = “xyz.dialog_back”
bl_label = “[QUESTION]”
def execute(self, context):
bpy.ops.wm.open_mainfile(filepath = “.save//0.blend”)
return {‘FINISHED’}
def invoke(self, context, event):
return context.window_manager.invoke_props_dialog(self)
def draw(self, context):
row = self.layout.row()
row.label(icon = “QUESTION”)
row.label(“QUESTION”)
It open the dialog box with “OK” button. When i click on “OK” button then it work fine, but when i Press “ENTER” on pop-up then it close the blender. If shows the error as “ERROR:EXCEPTION_ACCESS_VIOLATION”.
The issue is not in pop-up window, but in your effort to open another blend-file under yours.
Try that trick:
modify your “execute” function only to run your operator xyz.dialog_back in modal mode
def execute(self, context):
context.window_manager.modal_handler_add(self)
return {‘RUNNING_MODAL’}
and define a “modal” function that will open your blend-file
def modal(self, context, event):
bpy.ops.wm.open_mainfile(filepath = “.save//0.blend”)
return ‘{FINISHED}’
That may works.
Thanks a lot sir, finally it work. 🙂 🙂
fine )