1

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?

Ray Mairlot
  • 29,192
  • 11
  • 103
  • 125
masterxeon1001
  • 311
  • 1
  • 10

2 Answers2

4

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
batFINGER
  • 84,216
  • 10
  • 108
  • 233
1

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()
cmomoney
  • 2,660
  • 12
  • 17