How to implement user input into custom UI


(Blender_bari) #1

Hello!

I’m trying to make a little add-on for myself where I enter an integer and I receive a bunch of buttons that will assign vertex weights to selected vertices when the buttons are clicked from 0-1 in increments dependent on what number I input.

I can get the buttons working perfectly. What I can’t seem to do right is the user input. Please help!

Here’s my code:

import bpy




def main(context, denom):
    """The vertex weight is set based upon variable denom (like denominator in fractions/divisions) and then assigned to a vertex"""
    bpy.context.tool_settings.vertex_group_weight=denom
    bpy.ops.object.vertex_group_assign()




class SetNAssign(bpy.types.Operator):
    """Setting up my operation to use elsewhere"""
    bl_idname = "myops.set_n_assign"
    bl_label = "Set Vertex Weight and Assign to Vertex"


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


    def execute(self, context):
        main(context)
        return {'FINISHED'}




class vWeightIncPanel(bpy.types.Panel):
    """Creates a Panel in the data context of the properties editor  where a user may input a denominator for the creation of easy access incremental vertex weights"""
    bl_label = "Vertex Weight Increments"
    bl_idname = "DATA_vWeightInc"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "data"
    
    
    
    def draw(self, context):
        from bpy.props import (StringProperty)
        layout = self.layout
        scene = context.scene
        mytool = scene.my_tool
        layout.prop(mytool, 'my_string')    #this is where I'm trying to get the user's input but to no avail. mytool needs to be defined or something
        denom = 10                          #this where I'd like to store the user's input though I'm not really sure as to how
        my_string = StringProperty(
            name="Number of Verticies",
            description=":",
            default="",
            maxlen=1024,
        )                                   #this is how others import a string input
        
        
        row = layout.row()
        row.label(text="Vertex Weight Increments")
        
        split = layout.split(align=True)
        col = split.column()
        for num in range(denom+1):          #this creates a button for each vertex weight
            col.label(text = str(num))      #this was just to show me when the operator wasn't working
            col.operator("myops.set_n_assign()", text = str(num) + "/" + str(denom)) #this works however I don't know how to pass set_n_assign() denom so that it changes interactively
        
        #I will also need an go button somewhere around here to take the user input and do its thing
    




def register():
    bpy.utils.register_class(SetNAssign)
    bpy.utils.register_class(vWeightIncPanel)


def unregister():
    bpy.utils.unregister_class(SetNAssign)
    bpy.utils.unregister_class(vWeightIncPanel)




if __name__ == "__main__":
    register()


    # test call
    # bpy.ops.myops.set_n_assign()

(Blender_bari) #2

Well, I’ve made some progress and I got the user input to work, however, now it won’t run my operator in order to apply the vertex weight to the vertices. Any thoughts?

import bpy

from bpy.props import (StringProperty, PointerProperty)
from bpy.types import (Panel, PropertyGroup)


class MySettings(PropertyGroup):
    
    my_string = StringProperty(
        name="User Input",
        description=":",
        default="",
        maxlen=1024
    )




class SetNAssign(bpy.types.Operator): 
    """Setting up my operation to use elsewhere"""
    bl_idname = "myops.set_n_assign"
    bl_label = "Set Vertex Weight and Assign to Vertex"


    def execute(self, context):
        scene = context.scene
        mytool = scene.my_tool
        numb = mytool.my_string
        
        bpy.context.tool_settings.vertex_group_weight = mytool.my_string
        bpy.ops.object.vertex_group_assign()
        
        print("numb = ", mytool.my_string)
        
        return {"FINISHED"}




class vWeightIncPanel(Panel):
    bl_label = "Vertex Weight Increments"
    bl_idname = "DATA_vWeightInc"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "data"
    
    @classmethod
    def poll(self, context):
        return context.active_object is not None
    
    def draw(self, context):
        layout = self.layout
        scene = context.scene
        mytool = scene.my_tool
        layout.prop(mytool, "my_string")
        denom = mytool.my_string
        #print(denom)
        
                
        
        row = layout.row()
        row.label(text="Vertex Weight Increments")
        row.prop(scene, "Text", slider = True)
        
        split = layout.split(align=True)
        col = split.column()
        for num in range(int(denom)+1):
            col.label(text = str(num))
            col.operator("myops.set_n_assign()", text = str(num) + "/" + str(denom))
    




def register():
    #bpy.utils.register_module(__name__)    
    bpy.utils.register_class(SetNAssign)
    bpy.utils.register_class(vWeightIncPanel)
    #bpy.types.Scene.my_tool = PointerProperty(type=MySettings)


def unregister():
    #bpy.utils.unregister_module(__name__)
    bpy.utils.unregister_class(SetNAssign)
    bpy.utils.unregister_class(vWeightIncPanel)
    #del bpy.types.Scene.my_tool




if __name__ == "__main__":
    register()


    # test call
    # bpy.ops.myops.set_n_assign()

(Blender_bari) #3

Okay, so I’ve made some great progress! The user input shows up (I copied this other guy’s code in how he did it. Sometimes it worked and sometimes it didn’t, but now it does every time…idk why lol), the buttons populate according to the user input. The problem now is that I need to pass set_n_assign (or SetNAssign) the for loop’s iteration count so that it will assign the correct weight to each button. I’ve done single line comments on the lines that are problematic. Any ideas anyone?

import bpy

from bpy.props import (StringProperty, PointerProperty)
from bpy.types import (Panel, PropertyGroup)


class MySettings(PropertyGroup):
    
    my_string = StringProperty(
        name="User Input",
        description=":",
        default="",
        maxlen=1024
    )
    




class SetNAssign(bpy.types.Operator): 
    """Setting up my operation to use elsewhere"""
    bl_idname = "myops.set_n_assign"
    bl_label = "Set Vertex Weight and Assign to Vertex"


    def execute(self, context):
        scene = context.scene
        mytool = scene.my_tool
        numb = 1 / int(mytool.my_string) # HERE! '1' needs to be a variable so that it changes each time with the for loop below but how can I pass that value to it?
        
        bpy.context.tool_settings.vertex_group_weight = float(numb)
        bpy.ops.object.vertex_group_assign()
        
        print("numb = ", mytool.my_string)
        
        return {"FINISHED"}




class vWeightIncPanel(Panel):
    bl_label = "Vertex Weight Increments"
    bl_idname = "DATA_vWeightInc"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "data"
    
    @classmethod
    def poll(self, context):
        return context.active_object is not None
    
    def draw(self, context):
        layout = self.layout
        scene = context.scene
        mytool = scene.my_tool
        layout.prop(mytool, "my_string")
        denom = mytool.my_string
        #print(denom)
        
                
        
        row = layout.row()
        row.label(text="Vertex Weight Increments")
        row.prop(scene, "Text", slider = True)
        
        split = layout.split(align=True)
        col = split.column()
        for num in range(int(denom)+1): # HERE! How can I give num to set_n_assign so that it can give each button the correct weight? 
            col.label(text = str(num))
            col.operator("myops.set_n_assign", text = str(num) + "/" + str(denom))
    




def register(): 
    bpy.utils.register_class(SetNAssign)
    bpy.utils.register_class(vWeightIncPanel)


def unregister():
    bpy.utils.unregister_class(SetNAssign)
    bpy.utils.unregister_class(vWeightIncPanel)




if __name__ == "__main__":
    register()
    
    # bpy.ops.myops.set_n_assign()

(Peter Rabbit) #4

Not sure if you’ve already found them, but I’m working on something similar and I found these two pages invaluable:

https://wiki.blender.org/index.php/Dev:Py/Scripts/Cookbook/Code_snippets/Interface
(this one in particular, have a look at the section on pop up dialogues)