2
$\begingroup$

Hi i'm thying threading with bpy this is my code:

import bpy
import threading


class Cubes(threading.Thread):

    def __init__(self):
        threading.Thread.__init__(self)


    def run(self):

        scale = 0.2
        space = 0.2
        max_range = 6


        for i in range(0, max_range):

            bpy.ops.mesh.primitive_cube_add(radius = 1, location=(0, 0, 1))
            bpy.ops.object.origin_set( type="ORIGIN_CURSOR" )

            bpy.context.active_object.scale.x = scale
            bpy.context.active_object.scale.y = scale
            bpy.context.active_object.scale.z = 5

            bpy.ops.object.transform_apply(location = False, rotation = False, scale = True)
            bpy.context.active_object.location = (((i*scale*2)+(i*space))-(((max_range*scale*2)+(max_range*space)))/2,0,0) 

        return

t = Cubes()
t.start()

but when i run this the console give me this error:

Exception in thread Thread-1:
Traceback (most recent call last):
  File "C:\Program Files\Blender Foundation\Blender\2.75\python\lib\threading.py", line 921, in _bootstrap_inner
    self.run()
  File "C:\Users\Davide\Desktop\Sound_Visualizer.blend\Sound_Visualizer_Circular.py", line 40, in run
AttributeError: 'Context' object has no attribute 'active_object'

Can someone help me?

$\endgroup$
  • $\begingroup$ You might find threading and blender don't play well together... especially operators which may toggle the mesh to / from EDIT mode, and running threading code can confuse the blender UI, between OBJECT and EDIT mode. $\endgroup$ – batFINGER Jul 13 '16 at 19:42
3
$\begingroup$

It will not fully answer your question, but it might point you the right direction. The context which you are grabbing during script execution is not necessarily the 3D View context, which you get for instance when you call it from the Python console. Blenders context changes depending on the situation, that's why it was given that name I guess :)

So, if you change your FOR loop to this, the script at least executes:

    for i in range(0, max_range):

        bpy.ops.mesh.primitive_cube_add(radius = 1, location=(0, 0, 1))
        bpy.ops.object.origin_set( type="ORIGIN_CURSOR" )

        # check what attributes the current context offers
        print(dir(bpy.context))

        # now grab a reference to the active object
        ao=bpy.context.scene.objects.active

        ao.scale.x = scale
        ao.scale.y = scale
        ao.scale.z = 5

        bpy.ops.object.transform_apply(location = False, rotation = False, scale = True)
        ao.location = (((i*scale*2)+(i*space))-(((max_range*scale*2)+(max_range*space)))/2,0,0) 

I've added this line on purpose:

    print(dir(bpy.context))

console output:

['__doc__', '__module__', '__slots__', 'area', 'bl_rna', 
'blend_data', 'copy', 'mode', 'region', 'region_data',  
'rna_type', 'scene', 'screen', 'space_data', 'tool_settings', 
'user_preferences', 'window', 'window_manager']

in the console you can this way see what attributes you can access, and one of them is the current scene. so by calling the active object from there, I can access it:

    ao=bpy.context.scene.objects.active

The problem is not solved however. On my machine I get 5 Objects, but only one of them contains a mesh. I can only guess what's happening, I think it is a racing condition. Since each thread calls the active object, and each one creates a new active object, one thread might 'steal' it from the other, thus affecting its location and even object data.

Consider creating the objects you need directly in bpy.data and link them to the scene manually, this way you get a unique reference to the object directly. You'll find guides on how to do this here on this site. Good luck!

$\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.