NodeGraphQt Documentation

repository·main·Indexed 23 days ago

https://github.com/jchanvfx/nodegraphqt

A node graph UI framework written in Python using the Qt library for creating and managing node-based workflows. It includes built-in widgets like NodesPaletteWidget, NodesTreeWidget, and PropertiesBinWidget, and supports custom node creation via BaseNode, custom widget integration, and flexible context menu configuration through Python or JSON.

Tokens
11K
Snippets
19
Records
50
Agent score
79%

What's inside NodeGraphQt

  1. Available Node object types in NodeGraphQt

    main

    The NodeGraphQt module provides several specialized node classes that you can use to build your node graph. Depending on your requirements, you can use standard nodes, nodes that act as backdrops, or nodes that represent groups or ports.

    Available node classes include:

    • NodeObject: The base node object.
    • BackdropNode: A node used to create background areas or visual groupings.
    • BaseNode: A fundamental node implementation.
    • GroupNode: A node designed to encapsulate or group other nodes.
    • PortNode: A node specifically related to port interactions.
  2. Use embedded node widgets in NodeGraphQt

    main

    Embedded node widgets are specialized UI components designed to be embedded into a NodeGraphQt.BaseNode and displayed within the node graph. These widgets allow users to interact with node parameters directly on the node itself.

    Available built-in widget classes include:

    • NodeGraphQt.NodeBaseWidget: The base class for all node widgets.
    • NodeGraphQt.widgets.node_widgets.NodeCheckBox: A checkbox widget for boolean parameters.
    • NodeGraphQt.widgets.node_widgets.NodeComboBox: A combo box widget for selecting from a list of options.
    • NodeGraphQt.widgets.node_widgets.NodeLineEdit: A line edit widget for text or numeric input.

    To create a custom widget, you should inherit from NodeBaseWidget.

  3. Use NodeGraphQt.SubGraph for hierarchical node organization

    main
    The NodeGraphQt.SubGraph class allows you to create sub-graphs within a larger node graph. This is useful for organizing complex node networks into manageable, hierarchical structures. You can use SubGraph to encapsulate a group of nodes and their connections, effectively creating a nested graph environment.
  4. Understand Port Nodes in SubGraphs

    main
    In NodeGraphQt, Port Nodes are specialized nodes used within an expanded SubGraph. They represent the individual input and output ports of a parent GroupNode object. When a GroupNode is expanded into a SubGraph, these port nodes act as the interface points for connecting data into or out of that group.
  5. Create custom nodes by subclassing BaseNode

    main

    To create a new node type, subclass NodeGraphQt.BaseNode. You must define a unique __identifier__ and a NODE_NAME. In the __init__ method, call super().__init__() and use add_input(name) and add_output(name) to define the node's ports.

    To use the node in a graph, first register the class using node_graph.register_node(MyNode), then instantiate it using node_graph.create_node('identifier.ClassName', name='node_name', pos=(x, y)).

    from Qt import QtWidgets
    from NodeGraphQt import BaseNode, NodeGraph
    
    class MyNode(BaseNode):
        __identifier__ = 'io.github.jchanvfx'
        NODE_NAME = 'my node'
    
        def __init__(self):
            super(MyNode, self).__init__()
            self.add_input('foo')
            self.add_output('bar')
    
    if __name__ == '__main__':
        app = QtWidgets.QApplication([])
        node_graph = NodeGraph()
        node_graph.register_node(MyNode)
        node_graph.widget.show()
    
        # Create node using the identifier and class name
        node_a = node_graph.create_node('io.github.jchanvfx.MyNode', name='node a')
        app.exec_()
  6. Set the pipe layout style in NodeGraphQt

    main

    The NodeGraph class supports three different pipe layout styles. You can change the visual style of the connections (pipes) between nodes using the set_pipe_style method. The available styles are defined in NodeGraphQt.constants.PipeLayoutEnum.

    If you have configured your node graph using set_context_menu_from_file with a standard hotkeys JSON, you can also access these layout styles via the "Pipes" menu in the UI.

    from NodeGraphQt import NodeGraph
    from NodeGraphQt.constants import PipeLayoutEnum
    
    graph = NodeGraph()
    graph.set_pipe_style(PipeLayoutEnum.ANGLE.value)
  7. Load context menus from JSON configuration files

    main

    Instead of manual Python setup, you can populate menus using NodeGraph.set_context_menu_from_file(file_path, menu='graph'|'nodes').

    This method expects a JSON array of menu/command definitions. Commands in the JSON can point to external Python files and specific function names, allowing for decoupled hotkey and menu management.

    from NodeGraphQt import NodeGraph
    
    node_graph = NodeGraph()
    node_graph.set_context_menu_from_file(
        '../path/to/a/hotkeys/graph_commands.json', menu='graph'
    )
    node_graph.set_context_menu_from_file(
        '../path/to/a/hotkeys/node_commands.json', menu='nodes'
    )
  8. Basic Setup: Create and connect nodes in NodeGraphQt

    main

    To use NodeGraphQt, you must define a custom node class by inheriting from BaseNode. You define a unique __identifier__ and a NODE_NAME. Inside the __init__ method, you use add_input and add_output to define the node's ports. Once the class is registered with a NodeGraph instance using register_node, you can instantiate nodes using create_node with their full identifier and connect them using set_output on the source node and input on the target node.

    from Qt import QtWidgets
    from NodeGraphQt import NodeGraph, BaseNode
    
    # 1. Define a custom node class
    class FooNode(BaseNode):
        __identifier__ = 'io.github.jchanvfx'
        NODE_NAME = 'Foo Node'
    
        def __init__(self):
            super(FooNode, self).__init__()
            # Create an input port
            self.add_input('in', color=(180, 80, 0))
            # Create an output port
            self.add_output('out')
    
    if __name__ == '__main__':
        app = QtWidgets.QApplication([])
    
        # 2. Initialize the graph controller
        graph = NodeGraph()
    
        # 3. Register the node class
        graph.register_node(FooNode)
    
        # 4. Show the widget
        graph_widget = graph.widget
        graph_widget.show()
    
        # 5. Create nodes (using the identifier: domain.ClassName)
        node_a = graph.create_node('io.github.jchanvfx.FooNode', name='node A')
        node_b = graph.create_node('io.github.jchanvfx.FooNode', name='node B', pos=(300, 50))
    
        # 6. Connect node_a to node_b
        # set_output(output_index, input_port_object)
        node_a.set_output(0, node_b.input(0))
    
        app.exec_()
  9. Register a NodeGraphQt widget as a panel in Nuke

    main

    To integrate NodeGraphQt into Foundry Nuke, you can register the NodeGraph.widget property as a Nuke panel.

    Because Nuke's panels.registerWidgetAsPanel often adds unwanted margins to the registered widget, it is recommended to wrap the graph.widget in a custom QtWidgets.QWidget and use a margin-resetting hack (via setContentsMargins(0, 0, 0, 0)) on the parent hierarchy when the widget is shown. This ensures the node graph fills the entire panel area.

    from nukescripts import panels
    from Qt import QtWidgets, QtCore
    from NodeGraphQt import NodeGraph, BaseNode
    
    # 1. Define your nodes
    class TestNode(BaseNode):
        __identifier__ = 'nodes.nuke'
        NODE_NAME = 'test node'
        def __init__(self):
            super(TestNode, self).__init__()
            self.add_input('in')
            self.add_output('out 1')
            self.add_output('out 2')
    
    # 2. Initialize the graph and register nodes
    graph = NodeGraph()
    graph.register_node(TestNode)
    
    # 3. Create a wrapper widget to handle Nuke-specific layout issues
    class CustomNodeGraph(QtWidgets.QWidget):
        def __init__(self, parent=None):
            super(CustomNodeGraph, self).__init__(parent)
            layout = QtWidgets.QVBoxLayout(self)
            layout.setContentsMargins(0, 0, 0, 0)
            layout.addWidget(graph.widget)
    
        def event(self, event):
            if event.type() == QtCore.QEvent.Type.Show:
                # Hack to remove margins from Nuke's panel container
                try:
                    parent_widget = self.parentWidget().parentWidget()
                    target_widgets = {parent_widget, parent_widget.parentWidget().parentWidget()}
                    for widget_layout in target_widgets:
                        widget_layout.layout().setContentsMargins(0, 0, 0, 0)
                except Exception:
                    pass
            return super(CustomNodeGraph, self).event(event)
    
    # 4. Register with Nuke
    panels.registerWidgetAsPanel(
        widget='CustomNodeGraph',
        name='Custom Node Graph',
        id='nodegraphqt.graph.CustomNodeGraph'
    )
  10. Customize the main graph context menu

    main

    You can add custom menus and commands to the main graph context menu using NodeGraph.get_context_menu('graph'). This allows you to create sub-menus and assign functions to specific commands, optionally including keyboard shortcuts.

    To add a command, use add_menu(label) to create a sub-menu and add_command(label, func, shortcut) to add an executable item to that menu.

    from NodeGraphQt import NodeGraph
    
    # test function.
    def my_test(graph):
        selected_nodes = graph.selected_nodes()
        print('Number of nodes selected: {}'.format(len(selected_nodes)))
    
    # create node graph.
    node_graph = NodeGraph()
    
    # get the main context menu.
    context_menu = node_graph.get_context_menu('graph')
    
    # add a menu called "Foo".
    foo_menu = context_menu.add_menu('Foo')
    
    # add "Bar" command to the "Foo" menu.
    # we also assign a short cut key "Shift+t" for this example.
    foo_menu.add_command('Bar', my_test, 'Shift+t')
  11. Navigate the NodeGraphQt interface

    main

    Use the following controls to navigate the node graph workspace:

    ActionControls
    Zoom In/OutAlt + MMB + Drag or Mouse Scroll Up/Down
    PanAlt + LMB + Drag or MMB + Drag
    Node SelectionUse the selection marquee with LMB + Drag
    Toggle Tab SearchTab key
    Slice ConnectionsAlt + Shift + LMB + Drag (Disconnects pipes)