2
$\begingroup$

I recently became interested in creating an addon in Blender, and I want to know how to make a dropdown menu like this: Blender dropdown menu

or this: other Blender dropdown menu

I've searched the internet for some code and stumbled across this on a site called elfnor:

import bpy    

class DropDownExample(bpy.types.Operator) : 
    bl_idname = "mesh.dropdownexample"  
    bl_label = "Drop Downs"  
    bl_options = {"REGISTER", "UNDO"} 

    fixed_items = bpy.props.EnumProperty(items= (('0', 'A', 'The zeroth item'),    
                                                 ('1', 'B', 'The first item'),    
                                                 ('2', 'C', 'The second item'),    
                                                 ('3', 'D', 'The third item')),
                                                 name = "fixed list")      
    def execute(self, context) :  
        print("fixed item", self.fixed_items)  
        return {"FINISHED"} 

def add_to_menu(self, context) :  
    self.layout.operator("mesh.dropdownexample", icon = "PLUGIN")  

def register() :  
    bpy.utils.register_module(__name__)       
    bpy.types.VIEW3D_MT_object.append(add_to_menu)  

def unregister() :  
    bpy.utils.unregister_module(__name__)   
    bpy.types.VIEW3D_MT_object.remove(add_to_menu)  

if __name__ == "__main__" :  
    register() 

And I added the code to my custom script here:

#----------------------------------------------------------
# File swatches.py
#----------------------------------------------------------
import os
import bpy
import bpy.utils.previews

#   Layout panel
class LayoutPanel(bpy.types.Panel):
    bl_label = "Panel"
    bl_space_type = "VIEW_3D"
    bl_region_type = "TOOLS"
    bl_category = "Custom addon"

    def draw(self, context):
        layout = self.layout
        self.layout.operator("hello.hello", icon_value=custom_icons["custom_icon"].icon_id)
        global custom_icons

        layout.label("Addon Options")
        row = layout.row(align=True)
        row.alignment = 'EXPAND'
        row.operator("my.button", text="Button1", icon_value=custom_icons3["custom_icon3"].icon_id).number=1
        row.operator("my.button", text="Button2", icon_value=custom_icons["custom_icon"].icon_id).number=2
        row.operator("my.button", text="Button3", icon_value=custom_icons2["custom_icon2"].icon_id).number=3


        layout.label("Advanced Options", icon_value=custom_icons["custom_icon"].icon_id)
        row = layout.row()
        box = row.box()

        box.operator_menu_enum("mesh.dropdownexample","type")


#   Button
class OBJECT_OT_Button(bpy.types.Operator):
    bl_idname = "my.button"
    bl_label = "Button"
    number = bpy.props.IntProperty()
    row = bpy.props.IntProperty()
    loc = bpy.props.StringProperty()

    def execute(self, context):
        if self.loc:
            words = self.loc.split()
            self.row = int(words[0])
            self.number = int(words[1])
        print("Row %d button %d" % (self.row, self.number))
        return{'FINISHED'}    



    def draw(self, context):
        global custom_icons


# global variable to store icons in
custom_icons = None

def register():
    global custom_icons
    custom_icons = bpy.utils.previews.new()
    script_path = os.path.dirname("C:/Users/No pass necessary/Documents/Icon.png")
    icons_dir = os.path.join(os.path.dirname(script_path), "icons")
    custom_icons.load("custom_icon", os.path.join(icons_dir, "icon.png"), 'IMAGE')
    bpy.utils.register_module(__name__)

def unregister():
    global custom_icons
    bpy.utils.previews.remove(custom_icons)
    bpy.utils.unregister_module(__name__)

if __name__ == "__main__":
    register()

#   Button2
class OBJECT_OT_Button(bpy.types.Operator):
    bl_idname = "my.button2"
    bl_label = "Button2"
    number = bpy.props.IntProperty()
    row = bpy.props.IntProperty()
    loc = bpy.props.StringProperty()

    def execute(self, context):
        if self.loc:
            words = self.loc.split()
            self.row = int(words[0])
            self.number = int(words[1])
        print("Row %d button %d" % (self.row, self.number))
        return{'FINISHED'}    



    def draw(self, context):
        global custom_icons2


# global variable to store icons in
custom_icons2 = None

def register():
    global custom_icons2
    custom_icons2 = bpy.utils.previews.new()
    script_path = os.path.dirname("C:/Users/No pass necessary/Documents/icon1.png")
    icons_dir = os.path.join(os.path.dirname(script_path), "icons")
    custom_icons2.load("custom_icon2", os.path.join(icons_dir, "icon1.png"), 'IMAGE')
    bpy.utils.register_module(__name__)

def unregister():
    global custom_icons2
    bpy.utils.previews.remove(custom_icons2)
    bpy.utils.unregister_module(__name__)

if __name__ == "__main__":
    register()


#   Button3
class OBJECT_OT_Button(bpy.types.Operator):
    bl_idname = "my.button3"
    bl_label = "Button3"
    number = bpy.props.IntProperty()
    row = bpy.props.IntProperty()
    loc = bpy.props.StringProperty()

    def execute(self, context):
        if self.loc:
            words = self.loc.split()
            self.row = int(words[0])
            self.number = int(words[1])
        print("Row %d button %d" % (self.row, self.number))
        return{'FINISHED'}    



    def draw(self, context):
        global custom_icons3


# global variable to store icons in
custom_icons3 = None

def register():
    global custom_icons3
    custom_icons3 = bpy.utils.previews.new()
    script_path = os.path.dirname("C:/Users/No pass necessary/Documents/icon2.png")
    icons_dir = os.path.join(os.path.dirname(script_path), "icons")
    custom_icons3.load("custom_icon3", os.path.join(icons_dir, "icon2.png"), 'IMAGE')
    bpy.utils.register_module(__name__)

def unregister():
    global custom_icons3
    bpy.utils.previews.remove(custom_icons3)
    bpy.utils.unregister_module(__name__)

if __name__ == "__main__":
    register()




#    Registration
bpy.utils.register_module(__name__)



import bpy    

class DropDownExample(bpy.types.Operator) : 
    bl_idname = "mesh.dropdownexample"  
    bl_label = "Drop Downs"  
    bl_options = {"REGISTER", "UNDO"} 

    fixed_items = bpy.props.EnumProperty(items= [('0', 'A', 'The zeroth item', '0'),    
                                                 ('1', 'B', 'The first item'),    
                                                 ('2', 'C', 'The second item'),    
                                                 ('3', 'D', 'The third item')],
                                                 name = "fixed list")   
    def execute(self, context) :  
        print("fixed item", self.fixed_items)  
        return {"FINISHED"} 

def add_to_menu(self, context) :  
    self.layout.operator("mesh.dropdownexample", icon = "PLUGIN")  

def register() :  
    bpy.utils.register_module(__name__)       
    bpy.types.VIEW3D_MT_object.append(add_to_menu)  

def unregister() :  
    bpy.utils.unregister_module(__name__)   
    bpy.types.VIEW3D_MT_object.remove(add_to_menu)  

if __name__ == "__main__" :  
    register() 

But I can't get the items to show. I really want to figure out how to get this dropdown menu to work.

$\endgroup$
1
$\begingroup$

It will mostly depend on what you want to display in the menu. The example you show is adding one item to an existing menu that will run the custom operator.

To create a custom menu that shows items that you want, where each item is expected to be an operator to perform a task you can create a custom menu as a subclass of bpy.types.Menu and have it's draw() method define which operators are listed. There is an example of this available in blender's text editor from Templates->Python->ui_menu.py. Running the template script from the text editors run script button will show the menu straight away. To have the menu in your own panel you then add row.menu('MenuName') to your panels draw() method. The MenuName that you use to display a menu is the bl_idname that is defined in the menu class.

To show a menu that lists available values for a property, you need to define the property using bpy.props.enumProperty, define a list containing the accepted values and use row.prop_menu_enum() to show it in your panel.

You can find a sample addon here that displays the following layout with three different menus. The first is a custom menu that is subclassed from bpy.types.menu, the second is a standard blender menu and the third is an enum_property list.

enter image description here

$\endgroup$
  • $\begingroup$ Thanks so much! This helps a bunch. I'd spent weeks trying to figure this out (Python newbie). You were very helpful! $\endgroup$ – Dassie Feb 9 '16 at 16:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.