Get list of selected Nodes

Is there any way to get list of selected nodes in active editor?

Within operator the “context.active_node” returns the active node in active editor.
but I did not found some thins like “context.selected_node” to return the list of nodes has selected.

Other types hase “selected” method too
…context.active_object, context.selected_objects
…context.active_bone, context.selected_bones
…context.selected_sequences

Python list aggregation might be the quickest way here:

sel = [x for x in context.node_tree.nodes if x.select]

2 Likes

Great

This sel = [x for x in context.scene.node_tree.nodes if x.select] worked.

But works only for Composite Node editor. each editor has different area type such as ‘material’, ‘world’, ‘texture’, and …

Thank you :blush:

So use the proper node_tree then.

Just use context.selected_nodes :stuck_out_tongue:

1 Like

Ha Ha " context.selected_nodes" was the first thing I tested and did not worked on 2.80, but now it`s working on the last build. :smile:

1 Like

Does it though? Am I stupid or why doesn’t this work for me?
2020-02-13 21_29_51-Blender

Hi,
If you type the “bpy.context.selected_node” in console you will face the error but if you call that inside node view it will work.

class Node_OT_test(Operator):
    bl_idname = "node.test"
    bl_label  = "Test"
    def execute(self, context):
	selection = context.selected_nodes
        print(selection)
	return {'FINISHED'}
1 Like

Sorry for bringing this old topic back up, but I’m writing an addon and I’m having a hard time getting the selected nodes.

Basically I want my script to find the active node editor (if no is active, maybe it can find it anyway) and then read values from selected nodes. The nodes can be both material nodes and world nodes.

What I don’t understand is the context. In the following example the context is always PROPERTIES, so I guess I need to override that somehow so that context.selected_nodes will work? Is that the recommended approach?

bl_info = {
    "name": "tmp_addon",
    "version": (0, 1),
    "blender": (2, 80, 0),
}

import bpy

class TmpPanel(bpy.types.Panel):

    bl_label = "Tmp panel"
    bl_idname = "TMP_PT_panel"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "output"

    def draw(self, context) :
        col = self.layout.column(align = True)
        col.operator("tmp.tool", text = "Tmp tool")


class TmpTool(bpy.types.Operator) :
    bl_idname = "tmp.tool"
    bl_label = "Tmp"
    bl_options = {"UNDO"}

    def execute(self, context):
        scene = bpy.context.scene

        # Get visible (first) node editor.
        # Get selected nodes.
        # This errors as the context is wrong.
        #context.selected_nodes

        print("Get node values and create new nodes")

        return {"FINISHED"}

classes = (TmpPanel, TmpTool)

register, unregister = bpy.utils.register_classes_factory(classes)

if __name__ == "__main__" :
    register()

In the line you wrote “scene = bpy.context.scene” you need to remove “bpy.”.
you have the right context in “def execute(self, context):”, bpy.context call a different area`s context.

Sorry the scene variable was just a leftover.

In this example, the context is PROPERTIES (I guess since it’s called from a button?). Becuse of that there is no method called selected_nodes.

You need to run your operator from within a node editor to have the context variable carry a selected_nodes property. The way you do it now, running it from the properties editor, causes the problem.

This piece of code will switch the context area to the area you want to work in:

bpy.context.area.type = "NODE_EDITOR"

As an example, what I don’t understand is why you want a menu that deals with nodes in the “PROPERTIES” area, surely the UI should be in the Node Editor…

Context.area.type must be an enumerator as detailed here.

Cheers, Clock.

1 Like

Thank you for the replies!

I was thinking that the code could loop over bpy.context.screen.areas and when it finds a NODE_EDITOR (both object and world) it would for example create a node in that editor.

It seems that it would work to set bpy.context.area.type = "NODE_EDITOR" and then reset afterwards, but that doesn’t seem to work with world nodes, only object nodes right?

I’m starting to realize that this might be bad design for the addon (still new Blender), but it would still be great if one could switch context within the operator. Or should I just abandon this idea and make a button in the Node Editor instead of properties?

which node tree are you targeting anyways? The compositor nodes can be reached via bpy.context.scene.node_tree.nodes for instance. Getting all selected nodes would be as easy as [x for x in bpy.context.scene.node_tree.nodes if x.select]. Material node trees are more difficult to get, but you could apply similar logic there

1 Like

Hi, I guess the first one it finds that is currently open. So if I’m in the Layout tab with no node editor it would return none. If I’m in the Shading tab it would return selected nodes of either material nodes or world nodes.

That’s both a user interaction nightmare as well as a coding one. Imagine a user has more than one node tree open, how would he be able to predict what happens in case he pushes a button of your user interface?

For exactly this reason, the Blender interface design has been constructed around the idea of a context, which carries whatever is relevant to the area underneath the mouse pointer currently. It makes what you retrieve from the code side more predictable, and the user has a clear idea of where his actions will have an effect. Consider changing the location of your Add-on panel to this:

class TmpPanel(bpy.types.Panel):

    bl_label = "Tmp panel"
    bl_idname = "TMP_PT_panel"
    bl_space_type = 'NODE_EDITOR'
    bl_region_type = 'UI'
    bl_context = "output"

As soon as you do that, your original code, context.selected_nodes, will work.

1 Like

Thanks @RainerTrummer for educating me, that makes more sense. The tool I’m making is all grouped in one panel in other apps so I guess I expected it to work the same in Blender. But I think this will work well :).

1 Like