Help, building a ui for my code breaks it!

Hi folks, I’m trying to learn python, and along the way I thought it would be useful to try to create a UI for the tools I’ve been writing. However when attempting to insert working code into a button, I can get the button to work , but the original code (which worked on its own ) breaks…

Heres the code that works, it is a function (genEmpties) in which is a FOR loop; The for loop generates and names 2 empties at the location of all selected objects.


import bpy
def genEmpties():
    #count how many items are selected and create variable called "iterations"
    iterations = len (bpy.context.selected_objects)
    #output value (bugcheck)
    #print (iterations)
    #create list variable called "objList" populated by currently selected objects
    objList = bpy.context.selected_objects
    print (objList)
    
    # i represents the current item in the list.
    for i in objList: 
        # ReName i (to match emptyies iterations and avoid later complications)
        i.name = 'object'
        # assign item location to variables
        genX = i.location.x
        genY = i.location.y
        genZ = i.location.z
        print (genX, genY, genZ)
        ###########################
        #create empty here
        bpy.ops.object.add(type='EMPTY', view_align=False, enter_editmode=False, location=(genX, genY, genZ), rotation=(0, 0, 0), layers=(False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False))
        # Name empty
        bpy.context.active_object.name = 'StaticEmpty'
        # print confirmation of naming
        print(bpy.context.active_object.name + " created successfully")
        ##########################
        #create empty here
        bpy.ops.object.add(type='EMPTY', view_align=False, enter_editmode=False, location=(genX, genY, genZ), rotation=(45, 45, 0), layers=(False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False))
        # Name empty
        bpy.context.active_object.name = 'triggerEmpty'
        # print confirmation of naming
        print(bpy.context.active_object.name + " created successfully")
        ##########################
        #create single vertex object here(i.location.x,i.location.y,i.location.z )
        #bpy.ops.mesh.primitive_cube_add(view_align=False, enter_editmode=False, location=(genX, genY, genZ), rotation=(0.0, 0.0, 0.0), layers=(False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False))
        #bpy.context.active_object.name = 'trigger_obj'
        
        


genEmpties()

And here is my attempt to create a UI with the same code. I’ve experimented loads but dont really understand whats happening.

The Code below creates a tool bar button that runs an operator(SimpleOperator), which calls the function (genEmpties) in which is a FOR loop; The for loop generates and names 2 empties at the location of all selected objects.

import bpy

def genEmpties():
    #count how many items are selected and create variable called "iterations"
    iterations = len (bpy.context.selected_objects)
    #output value (bugcheck)
    print (iterations)
    #create list variable called "objList" populated by currently selected objects
    objList = bpy.context.selected_objects
    print (objList)
    
    # i represents the current item in the list.
    for i in objList: 
        # ReName i (to match emptyies iterations and avoid later complications)
        i.name = 'object'
       
        # assign item location to variables
        genX = i.location.x
        genY = i.location.y
        genZ = i.location.z
        print (genX, genY, genZ)
        ###########################
        #create empty here
        bpy.ops.object.add(type='EMPTY', view_align=False, enter_editmode=False, location=(genX, genY, genZ), rotation=(0, 0, 0), layers=(False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False))
        # Name empty
        print (bpy.context.selected_objects + " current selection after static empty generated")
        #bpy.context.active_object.name = 'StaticEmpty'
        # confirmation of naming
        #print(bpy.context.active_object.name + " created successfully")
        ##########################
        #create empty here
        bpy.ops.object.add(type='EMPTY', view_align=False, enter_editmode=False, location=(genX, genY, genZ), rotation=(45, 45, 0), layers=(False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False))
        # Name empty
        #bpy.context.active_object.name = 'triggerEmpty'
        # print confirmation of naming
        #print(bpy.context.active_object.name + " created successfully")
        ##########################
        #create single vertex object here(i.location.x,i.location.y,i.location.z )
        #bpy.ops.mesh.primitive_cube_add(view_align=False, enter_editmode=False, location=(genX, genY, genZ), rotation=(0.0, 0.0, 0.0), layers=(False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False))
        #bpy.context.active_object.name = 'trigger_obj'


class SimpleOperator(bpy.types.Operator):
    """Tooltip"""
    bl_idname = "object.simple_operator"
    bl_label = "Simple Object Operator"
# comment out poll area and it works up to the first empty... POlling errors?  or relative absolute address issue? 
   # @classmethod
    #def poll(cls, context):
     #   return context.active_object is not None


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




    # test call
    #bpy.ops.object.simple_operator()        


class generateEmptyPanel(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "generateEmptyPanel"
    # panel will only appear in when in object mode
    bl_context = "objectmode"
    # panel will appear in 3d view
    bl_space_type = 'VIEW_3D'
    # panel will appear in tool palette
    bl_region_type = 'TOOLS'
    
    def draw(self, context):
        self.layout.operator("object.simple_operator", text='GENERATE')
 # get text input panel from hello world panel sample.


def register():


    bpy.utils.register_class(generateEmptyPanel)
    bpy.utils.register_class(SimpleOperator)


def unregister():
   
    bpy.utils.unregister_class(generateEmptyPanel)
    bpy.utils.unregister_class(SimpleOperator)




if __name__ == "__main__":
    register()



I’d really appreciate someone pointing out what I’m doing wrong. Thanks in advance.

@unitedfilmdom,
First thing you should do when something like this happens, is look at the console window for what error is being thrown. If you don’t know what the console window is, google “Open blender console window for insert-your-operating-system”. That’s the first step to seeing why your script isn’t working.

When I run your script, I see this in the console.


Traceback (most recent call last):
  File "\Text", line 54, in execute
  File "\Text", line 26, in genEmpties
TypeError: can only concatenate list (not "str") to list
location: <unknown location>:-1
location: <unknown location>:-1

So the error is happening on line 26. Your working code has this

print(bpy.context.active_object.name + " created successfully")

What’s not working has this code instead which is causing this error: “TypeError: can only concatenate list (not “str”) to list”.

print (bpy.context.selected_objects + " current selection after static empty generated")

So what works is a single object, what doesn’t work is a list of objects. Specifically this “can only concatenate list (not “str”) to list”. You might start investigating that to see why it’s not working. :slight_smile:

Hi Crazycourier, and thanks for your reply. I have of course been using the console , and already attempted to debug, in a number of ways. I haven’t posted everything I tried here , as it may obfuscate the real issue.

With regards to it saying it can’t concatenate a string to the list , What i don’t understand is why it works in the first example (not in an operator) But doesn’t work in the second example (function called by an operator/button etc. )

I have a suspicion that its to do with context, but having searched and searched on google I cant find an Answer.

I believe I have solved it… using a different approach, I used

<i>def invoke(self, context, event): </i>

rather than execute, and instead of calling a function I put the code directly under invoke… Also I made sure that the Return for the invoke is at the correct Indent level.
and to rename stuff I used

<i>currentObj = bpy.context.scene.objects.active
</i><i>currentObj.name = 'NewName' 

Theres a bit more to it than that and I’m still in progress but I thought i should post this whilst I remember to, so that anyone who stumbles this way looking for answers doesnt come up empty handed…