0
$\begingroup$

Is there such a thing as a generic custom data layer in Blender that holds Strings, Booleans, and Enums? I'm trying to create a text box in edit mode that holds a user input note on a given mesh. Unfortunately, it seems that the note doesn't stay with the given mesh. When another mesh is in edit mode, the same note from the previous mesh is there. Is there another way to do this other than a custom layer? Is this because the text is registered?

import bpy
from bpy.props import *
import bmesh

# ---
# String Properties
# ---

def initSceneProperties():

    bpy.types.Scene.StringType1 = StringProperty(
        name = "String1")

# ---
# Layout
# ---

class LayoutPanel(bpy.types.Panel):
    bl_label = "Test Text"
    bl_space_type = "VIEW_3D"
    bl_region_type = "TOOLS"
    bl_context = "mesh_edit"


    def draw(self, context):
        scn = bpy.context.scene
        layout = self.layout

        row = layout.row(align=True)
        col = row.column()
        col.prop(scn, 'StringType1', text="")

# ---
# Registers
# ---

def register():
    bpy.utils.register_module(__name__)


    initSceneProperties()


def unregister():

    bpy.utils.unregister_module(__name__)


if __name__ == "__main__":
    register()

D. Skarn, I came up with something like this as far as to how it should operate. If you start Blender fresh, run the script and add a cube (named "Cube"), then add text to the text box, it will hold that data. If you create a second item (Cube), put it into edit mode, the text box will be blank and text can be entered. You can switch between both items and each object will hold it's text data. I just don't know how to make it so that it is more elegant and doesn't require actually naming the object explicitly. So I guess somehow detecting a new object and instancing the property data? Will property groups do that?

import bpy
from bpy.props import *

# ---
# String Properties
# ---

def initSceneProperties():
    bpy.types.Scene.naming = StringProperty(name = "String1")
    bpy.types.Scene.naming1 = StringProperty(name = "String1")

# ---
# Layout
# ---

class LayoutPanel(bpy.types.Panel):
    bl_label = "Test Text"
    bl_space_type = "VIEW_3D"
    bl_region_type = "TOOLS"
    bl_context = "mesh_edit"

    def draw(self, context):            
        scn = bpy.context.scene
        layout = self.layout
        obj = bpy.context.edit_object
        objectOut = obj.name

        row = layout.row(align=True)
        col = row.column()
        if (objectOut == "Cube"):
            col.prop(scn, 'naming', text="")
            print(scn.naming)
        else:    
            col.prop(scn, 'naming1', text="")
            print(scn.naming1)
# ---
# Registers
# ---

def register():
    bpy.utils.register_module(__name__)

    initSceneProperties()

def unregister():

    bpy.utils.unregister_module(__name__)

if __name__ == "__main__":
    register()
$\endgroup$
3
  • 1
    $\begingroup$ Add the custom property to the object not the scene. Use context.active_object to get the text to display. $\endgroup$
    – sambler
    Feb 28, 2017 at 5:56
  • $\begingroup$ Hi Sambler, I'm sorry, were you referring to the original posted code? That displays fine. Or were you referring to D. Skarns code which I was having trouble displaying? $\endgroup$
    – ACopeLan
    Feb 28, 2017 at 12:24
  • 1
    $\begingroup$ The pieces of code you have here add a property to the scene - that is why you see the same text for every object. $\endgroup$
    – sambler
    Feb 28, 2017 at 18:07

2 Answers 2

1
$\begingroup$

Here is a little panel I took from my project. As far as I understood, that's what you need.

class WowWMOGroupPanel(bpy.types.Panel):
    bl_space_type = "PROPERTIES" # This defines where our panel should appear
    bl_region_type = "WINDOW"
    bl_context = "object" # This defines the mode in which it appears. In our case, it is object. However, could be "edit" or any other mode.and
    bl_label = "Wow WMO group" # Label and property ID name
    bl_options = {'DEFAULT_CLOSED'}

    def draw_header(self, context):
        layout = self.layout
        self.layout.prop(context.object.WowWMOGroup, "Enabled") # This makes the panel toggleable.

    def draw(self, context):
        layout = self.layout
        row = layout.row()
        self.layout.prop(context.object.WowWMOGroup, "GroupName") # This is our text input property

        layout.enabled = context.object.WowWMOGroup.Enabled # Enables everything in layout if checkbox is enabled

    @classmethod
    def poll(cls, context):
        # check if it is object and mesh
        return (context.object is not None and context.object.data is not None and isinstance(context.object.data,bpy.types.Mesh)) 



class WowWMOGroupPropertyGroup(bpy.types.PropertyGroup):
    Enabled = bpy.props.BoolProperty(name="", description="Enable wow WMO group properties")
    GroupName = bpy.props.StringProperty() # our string input!

def RegisterWowWMOGroupProperties():
    bpy.types.Object.WowWMOGroup = bpy.props.PointerProperty(type=WowWMOGroupPropertyGroup)

def UnregisterWowWMOGroupProperties():
    bpy.types.Object.WowWMOGroup = None

# After doing this you can adress your property as bpy.context.scene.objects[some_id_or_name].WowWMOGroup.GroupName
$\endgroup$
6
  • 1
    $\begingroup$ Hi. Please edit your answer to give an explanation of what this code does and how it answers the question. Just providing a block of code does not, in itself, constitute an answer (at least, not a good one). $\endgroup$ Feb 26, 2017 at 12:17
  • $\begingroup$ Hi D. Skarn, can you give a functioning example in addition. I think I understand whats happening, but I want to be sure. $\endgroup$
    – ACopeLan
    Feb 26, 2017 at 18:37
  • $\begingroup$ What do you mean by functioning example? A picture? i.imgur.com/qPFH4kE.png Just a text input. I gave you a proper runnable code, so you try to run it and play around with it. There is also a bunch of other properties you can use. $\endgroup$
    – D. Skarn
    Feb 26, 2017 at 19:08
  • $\begingroup$ I ran the code and realized that it was missing import bpy. But afterwards, I still don't get a text box, is there something else I'm missing? $\endgroup$
    – ACopeLan
    Feb 26, 2017 at 22:11
  • $\begingroup$ probably bpy.props? Show what error it gives you. $\endgroup$
    – D. Skarn
    Feb 27, 2017 at 16:48
1
$\begingroup$

OK I think I got it with the help of D Skarn's direction. Simply adding Property Groups seems to do the trick of allowing object's properties to be set in edit mode, but for them to have different settings per each object. I came up with this working example. Let me know if this doesn't run for anyone...

import bpy
from bpy.props import *

# ---
# Group Properties that include Float, Integer, and String
# ---

class MyPropertyGroup(bpy.types.PropertyGroup):
    custom_1 = bpy.props.FloatProperty(name="My Float")
    custom_2 = bpy.props.IntProperty(name="My Int")
    custom_3 = bpy.props.StringProperty(name ="StringType1")

# ---
# Layout
# ---

class LayoutPanel(bpy.types.Panel):
    bl_label = "Test Text"
    bl_space_type = "VIEW_3D"
    bl_region_type = "TOOLS"
    bl_context = "mesh_edit"


    def draw(self, context):
        scn = bpy.context.object
        layout = self.layout

        row = layout.row(align=True)
        col = row.column()
        col.prop(scn.my_prop_grp, 'custom_3', text="")
        col.prop(scn.my_prop_grp, 'custom_2', text="")
        col.prop(scn.my_prop_grp, 'custom_1', text="")

# ---
# Registers
# ---

def register():
    bpy.utils.register_class(MyPropertyGroup)
    bpy.utils.register_class(LayoutPanel)
    bpy.types.Object.my_prop_grp = bpy.props.PointerProperty(type=MyPropertyGroup)

def unregister():

    bpy.utils.unregister_module(__name__)


if __name__ == "__main__":
    register()

So this is how it works according to: https://docs.blender.org/api/2.78b/bpy.types.PropertyGroup.html#bpy.types.PropertyGroup

We register the Property Group which contains any property that you want to set (int, float, string).

def register():
    bpy.utils.register_class(MyPropertyGroup) # Property Group to be set.
    bpy.utils.register_class(LayoutPanel)
    bpy.types.Object.my_prop_grp = bpy.props.PointerProperty(type=MyPropertyGroup)

We set the variables under that class (class MyPropertiesGroup / variable: custom_1, custom_2, custom_3)

class MyPropertyGroup(bpy.types.PropertyGroup): # Property Group to be set.
    custom_1 = bpy.props.FloatProperty(name="My Float") # variable custom_1
    custom_2 = bpy.props.IntProperty(name="My Int") # variable custom_2
    custom_3 = bpy.props.StringProperty(name ="StringType1") # variable custom_3

The Property Group is then pointed to an object for layout to use (my_prop_grp):

bpy.types.Object.my_prop_grp = bpy.props.PointerProperty(type=MyPropertyGroup)

And then the properties are implemented in layout:

    col.prop(scn.my_prop_grp, 'custom_3', text="") # String Text Box
    col.prop(scn.my_prop_grp, 'custom_2', text="") # Integer Box
    col.prop(scn.my_prop_grp, 'custom_1', text="") # Float Box

At least that's how I understand it in a basic way. Someone will have to fill in the blanks as far as to detailed operation...

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .