2
$\begingroup$

I have a question about blender's python script. I would like to share variables among more than two operations, however I don't know how to.

If I use global variable, it's easy to solve this problem.

selected_faces = []
class SelectFace(bpy.types.Operator):
    bl_label = "Select Face"
    def execute(self, context):
        global selected_faces
        selected_faces = ...   # get selected faces.
        .....
class OperationAboutSelectedFaces(bpy.types.Operator):
    bl_label = "Operation About selected Face"
    def execute(self, context):
        global selected_faces
        # some operation to "selected_faces"

However, I want to avoid using global variable. So, I would like to rewrite this code as follows...

class SelectFace(bpy.types.Operator):
    bl_label = "Select Face"
    def execute(self, context):
        selected_faces = ... # get selected faces.
        .....
class OperationAboutSelectedFaces(bpy.types.Operator):
    bl_label = "Operation About selected Face"
    def execute(self, context):
        # some operation to "selected_faces"

Assuming operation sequence are as follows.

  1. "Select Face"
  2. "Operation About selected faces"

Thanks!

$\endgroup$
  • $\begingroup$ see this question, this answer and this $\endgroup$ – Chebhou Mar 22 '15 at 13:30
  • $\begingroup$ I tried this one. However this solution makes error AttributeError: 'NoneType' object has no attribute 'operator' because class is derived from bpy.types.Operator. Is there any solutions passed variables between bpy.types.Operator? $\endgroup$ – nutti Mar 24 '15 at 5:19
  • $\begingroup$ Both of your classes are global, you can store arbitrary data on them if you really have to: SelectFace.your_global = 123 $\endgroup$ – CoDEmanX Mar 24 '15 at 22:36
  • $\begingroup$ Can't you pass your selected faces into the constructor of your derived class? Create a constructor (__init__) and pass your selected_faces into it. It would be something like this (check syntax): def __init__(self, selectedFaces): $\endgroup$ – Chris Dunaway Mar 25 '15 at 20:59
  • $\begingroup$ @nutti is this your answer it is just a comment ? $\endgroup$ – Chebhou Mar 27 '15 at 15:50
2
$\begingroup$

I could solve this problem.

Solution is shown below.

  • Create user defined class which has properties you want.
  • Register class to bpy.types.Scene.XXXXX when add-on is started
  • Get data from bpy.context.scene.XXXXX
  • Unregister class to bpy.types.Scene.XXXXX when add-on is stopped
class SelectFaceProp():
    selected_faces = None

class SelectFace(bpy.types.Operator):
    bl_label = "Select Face"
    def execute(self, context):
        props = bpy.context.scene.sf_props
        props.selected_faces = ... # get selected faces.
        .....
class OperationAboutSelectedFaces(bpy.types.Operator):
    bl_label = "Operation About selected Face"
    def execute(self, context):
        props = bpy.context.scene.sf_props
        # some operation to "props.selected_faces"

def register():
    bpy.types.Scene.sf_props = SelectFaceProp()

def unregister():
    del bpy.types.Scene.sf_props

Thank you!!!

$\endgroup$
1
$\begingroup$

Finally, I solved this problem using static variable.

class SelectFace(bpy.types.Operator):
    bl_label = "Select Face"
    selected_faces = None
    def __init__(self):
        SelectFace.selected_faces = None
    def execute(self, context):
        SelectFace.selected_faces = ... # get selected faces.
        .....
class OperationAboutSelectedFaces(bpy.types.Operator):
    bl_label = "Operation About selected Face"
    def __init__(self):
        selected_faces = SelectFace.selected_faces
    def execute(self, context):
        # some operation to "selected_faces"

Thanks for your advice.

$\endgroup$
1
$\begingroup$

You should not use global or static variables, the proper concept to use is Blender's context. Note that this is not a Python mechanism, but something provided by Blender.

The context keeps track of the state of Blender in things such as 'what is the selected scene? what is the active object? what is the current selection?'. This information can then be used by all of Blender's operators, not just your own. Operators, in turn, also affect the context, by for example, modifying the current selection. If you bypass the context, there will be some inconsistencies, such as operators working on your previous selection, because you never changed it in the context.

How to set that a given face is selected:

face.selected = True

Hot to get all selected faces in a mesh:

selected_faces = [face for face in mesh.faces if face.select]

The mesh can be obtained from the context that is passed as an argument to the operator's execute.

$\endgroup$
  • $\begingroup$ Yeah, I don't want to use global and static variable too. However, there is no way to pass variable between bpy.types.Operators. However I tried to store bpy.types.Scene.XXX, It doesn't work... $\endgroup$ – nutti Apr 24 '15 at 16:39
  • $\begingroup$ You can store new properties in anything that is an ID. Scene should indeed work, as would an operator, but it really needs to be a new Blender property, not just a python variable. See bpy.props $\endgroup$ – brita_ Apr 24 '15 at 17:59
  • $\begingroup$ OK. By the way, is there any way to share PointerProperty? I can share IntProperty/FloatProperty, but I can't share PointerProperty. $\endgroup$ – nutti Apr 25 '15 at 0:30

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.