1
$\begingroup$

How would I go about making a property box that contained all the materials in a scene (in a Toolshelf (T) panel for example) and is able to pass the material in the list to another operator that assigned the material that was selected in the property box?

$\endgroup$
1
1
$\begingroup$

Here is an example of how this can be achieved:

import bpy

def mat_update(self, context):
    ob = context.active_object
    mats = bpy.data.materials
    selected_mat = context.scene.mymats
    if selected_mat != 'None':
        if ob.data.materials:
            ob.data.materials[0] = mats[selected_mat]
        else:
            ob.data.materials.append(mats[selected_mat])

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

    @classmethod
    def poll(cls, context):
        return context.active_object is not None 

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

        obj = context.object
        row = layout.row()
        row.prop(context.scene, "mymats")

def register():
    def getsets(self, context):
        sets = []
        mats = bpy.data.materials
        for mat in mats:
            sets.append((mat.name, mat.name, mat.name))
        if not sets:
            sets = [('None', 'None', 'None')]
        return sets

    bpy.utils.register_module(__name__)
    bpy.types.Scene.mymats = bpy.props.EnumProperty(items=getsets, update=mat_update)

def unregister():
    bpy.utils.unregister_module(__name__)

if __name__ == "__main__":
    register()
$\endgroup$
1
  • 1
    $\begingroup$ Rewrote the code because I read the question wrong. $\endgroup$ – cmomoney Jan 29 '17 at 21:11
2
$\begingroup$

Use pointers.

EDIT, having a property to keep the name, and use in a property search has IMO been superseded by assigning a pointer property with a poll in later (circa late 2.79 and beyond).

Example, select from and assign a property to a material of all non grease pencil materials in blend :

Custom search data to UILayout.prop_search


Finding only the materials in the scene would be doable (make a set of all materials of all objects in scene) but is probably not necessary, instead suggest using bpy.data.materials the list of all materials in the file.

EDIT: However have done this here How to populate UIList with all material slot in scene? 2.8

A UILayout.prop_search can be used as a UI to assign a material's name to a string property.

import bpy
from bpy.props import StringProperty

class LayoutDemoPanel(bpy.types.Panel):
    bl_label = "Set Active Material"
    bl_idname = "OBJECT_PT_example"
    bl_space_type = 'VIEW_3D'
    bl_region_type = "TOOLS"
    bl_category = 'Materials'

    @classmethod
    def poll(cls, context):
        return len(bpy.data.materials) > 0

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

        scene = context.scene

        layout.prop_search(scene,
                           "selected_mat",
                           bpy.data,
                           "materials")

def register():
    bpy.types.Scene.selected_mat = StringProperty(default="None")    
    bpy.utils.register_class(LayoutDemoPanel)


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


if __name__ == "__main__":
    register()

enter image description here

In an operator can use the property like so.

scene = context.scene
material = bpy.data.materials.get(scene.selected_mat)
if material is None:
    # no material has it been renamed?
    return {'CANCELLED'}
# do something with material
$\endgroup$

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.