Skip to content

Instantly share code, notes, and snippets.

@niuniulla
Created May 7, 2024 19:42
Show Gist options
  • Save niuniulla/85cbd84eb58e3bd44996d658f8617357 to your computer and use it in GitHub Desktop.
Save niuniulla/85cbd84eb58e3bd44996d658f8617357 to your computer and use it in GitHub Desktop.
A minimal example to show the usage of dearpygui to construct an nodes app.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
This is a minimal example to show the usage of dearpygui
to construct an app of nodes manipulations.
The basic functions includ:
* drag a button to create a node
* change node theme
* show some message based on the selected node
* connect and disconnect nodes
"""
import dearpygui.dearpygui as dpg
dpg.create_context()
dpg.configure_app(docking=True)
# some global variables
layer_data = {} # list of available layers
connection_data = [] # list of connections from layer to layer
LinkList = []
current_layer = []
selected_nodes = set()
nodes = []
def show_layer_info(sender):
for selected_node in dpg.get_selected_nodes("NodeEditor"):
item_name = "Layer Attributes_" + str(selected_node)
if (selected_node not in nodes):
dpg.hide_item(item_name)
else:
dpg.show_item(item_name)
# Delete selected node
def callback_delete_item(sender):
for selected_node in dpg.get_selected_nodes("NodeEditor"):
# Deleting node and attached links
## Extract all children of the deleted node
selected_node_children = dpg.get_item_children(selected_node)[1]
## Extract all existing links in the Node Editor
nodeEditor_links = dpg.get_item_children("NodeEditor")[0]
## Iterate through NodeEditor elements and delete attached links
for link in nodeEditor_links:
if dpg.get_item_configuration(link)["attr_1"] in selected_node_children or dpg.get_item_configuration(link)["attr_2"] in selected_node_children:
dpg.delete_item(link)
## Iterate trough LinkList and remove attached links
for item in LinkList:
for sub_item in item:
if dpg.get_item_alias(selected_node) in sub_item:
LinkList.remove(item)
# Deleting node
dpg.delete_item(selected_node)
del model_data[selected_node]
# callback runs when user attempts to connect attributes
def link_callback(sender, app_data):
# app_data -> (link_id1, link_id2)
data = ()
if type(app_data) == tuple:
dpg.add_node_link(app_data[0], app_data[1], parent=sender)
data = (dpg.get_item_alias(app_data[0]), dpg.get_item_alias(app_data[1]))
LinkList.append(data)
# callback runs when user attempts to disconnect attributes
def delink_callback(sender, app_data):
# app_data -> link_id
dpg.delete_item(app_data)
def input_callback(sender, app_data):
# get parent node
parent = dpg.get_item_parent(sender)
parent = dpg.get_item_parent(parent)
label = dpg.get_item_label(sender)
print("input callback: ", app_data, "parent: ", parent, "label: ", label)
model_data[parent]["parameters"][0]["value"] = dpg.get_value(sender)
print(model_data)
def on_drop(sender, app_data, user_data):
pos = dpg.get_mouse_pos(local=False)
layer_info = app_data
node_id = dpg.generate_uuid()
nodes.append(node_id)
with dpg.node(label="node_"+str(node_id), tag=node_id, parent="NodeEditor", pos=pos):
with dpg.node_attribute():
dpg.add_input_int(label="input", callback=input_callback, width=100)
with dpg.node_attribute(attribute_type=dpg.mvNode_Attr_Output):
dpg.add_input_int(label="output", callback=input_callback, width=100)
# create group for display on window "layer_info"
group_lable = "Layer Attributes_" + str(node_id)
with dpg.group(label=group_lable, tag=group_lable, parent="window_info", show=False):
dpg.add_text("some info")
dpg.add_text("some more info")
# get selected nodes when dragging mouse
def on_drag(sender, app_data):
selected_nodes.clear()
for selected_node in dpg.get_selected_nodes("NodeEditor"):
selected_nodes.add(selected_node)
#
def get_selected_nodes_callback(sender, app_data):
if len(selected_nodes) == 0:
selected_nodes.clear()
return
print("selected nodes: ", selected_nodes)
with dpg.theme() as item_theme:
with dpg.theme_component(dpg.mvNode):
link_theme_color = dpg.add_theme_color(dpg.mvNodeCol_TitleBar, (0, 255, 0), category=dpg.mvThemeCat_Nodes)
# create window context
with dpg.window(label="Tutorial", width=1200, height=800):
# create node editor
with dpg.group(tag="nodes", drop_callback=on_drop, user_data="test"):
with dpg.node_editor(tag="NodeEditor", callback=link_callback, delink_callback=delink_callback):
with dpg.node(label="Input") as node_test:
with dpg.node_attribute(label="Node A1", attribute_type=dpg.mvNode_Attr_Static):
#dpg.add_input_float(label="F1", width=150)
pass
with dpg.node_attribute(label="Node A2", attribute_type=dpg.mvNode_Attr_Output):
dpg.add_input_int(label="F1", width=100)
dpg.add_input_int(label="F2", width=100)
dpg.bind_item_theme(node_test, item_theme)
# create button window
with dpg.window(label="buttons", pos=(200, 100)):
def add_button(name):
dpg.add_button(label=name, tag=name)
with dpg.drag_payload(parent=name):
dpg.add_text(name)
with dpg.group(tag="buttons"):
for i in range(5):
add_button(f"button{i}")
dpg.add_separator()
# window to show layer properties
with dpg.window(label="Info Window", tag="window_info", pos=(400, 100)):
dpg.add_text("Information", show=True)
dpg.add_separator(show=True)
# create menubar
with dpg.viewport_menu_bar():
with dpg.menu(label="File"):
dpg.add_menu_item(label="save")
# input handlers
with dpg.handler_registry():
dpg.add_key_release_handler(key=dpg.mvKey_Delete, callback=callback_delete_item)
dpg.add_mouse_click_handler(callback=show_layer_info)
dpg.add_mouse_drag_handler(callback=on_drag)
dpg.add_mouse_release_handler(callback=get_selected_nodes_callback)
dpg.create_viewport(title='Custom Title', width=1200, height=800)
dpg.setup_dearpygui()
dpg.show_viewport()
dpg.start_dearpygui()
dpg.destroy_context()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment