DearPyGui icon indicating copy to clipboard operation
DearPyGui copied to clipboard

Nodes with the first attribute "empty" expand infinitely in width

Open n3odym3 opened this issue 1 year ago • 4 comments

Version of Dear PyGui

Version: 2.0.0 Operating System: Windows 11

My Issue/Question

In DearPyGui 2.0, nodes exhibit unintended width expansion under the following conditions:

The node has an empty first attribute (either input/output/static) or the node contains an empty nested attribute (with no nested child, e.g., no text). This issue causes the node to expand slightly on each render.

This behavior is observed on DPG 2.0 but is not present in DPG 1.8.0, where nodes work as expected.

Bug occurs:

  1. Node with an empty input and an empty output attribute.
  2. Node with an empty input and a filled output attribute.

Works correctly:

  1. Node with a filled input and a filled output attribute.
  2. Node with a filled input and an empty output attribute.

The bug seems to come from the automatic sizing mechanism, which fails to determine the node's width correctly if the first child attribute is empty.

Adding a time.sleep(0.25) to slow the framerate confirms that the node extend progressively on each render instead of being created with an infinite width.

Adding an empty string to the first attribute can mitigate the issue, but this increases the node's height slightly.

To Reproduce

Steps to reproduce the behavior:

  1. Create a node_editor
  2. Add an empty node with either A. dpg.add_node() B. with dpg.node(): pass
  3. Or add a node with the FIRST attribute empty : A. with dpg.node(): dpg.add_node_attribute(attribute_type=dpg.mvNode_Attr_Output) B. with dpg.node(): with dpg.node_attribute(attribute_type=dpg.mvNode_Attr_Output) : pass

Expected behavior

The node should have a fixed width that scale to the size of the node label (if the node does not have children) or the largest attribute (if the node have one or more children).

Screenshot

BuggedNodeEditor

Standalone, minimal, complete and verifiable example

import dearpygui.dearpygui as dpg

dpg.create_context()
dpg.create_viewport(title="Expanding node bug", width=1280, height=720)

with dpg.window(label="Node Editor", width=1280, height=720):
    with dpg.node_editor(tag="node_editor", minimap=True, minimap_location=dpg.mvNodeMiniMap_Location_BottomRight):

        dpg.add_node(label="Bugged node 1", pos=[100, 0])

        with dpg.node(label="Bugged node 2", pos=[100, 50]):
            pass

        with dpg.node(label="Bugged node 3", pos=[100, 100]):
            dpg.add_node_attribute(label="Input", attribute_type=dpg.mvNode_Attr_Output)

        with dpg.node(label="Bugged node 4", pos=[100, 150]):
            with dpg.node_attribute(label="Test", attribute_type=dpg.mvNode_Attr_Output) :
                pass
        
        with dpg.node(label="Working node 1", pos=[100, 250]):
            with dpg.node_attribute(label="Test", attribute_type=dpg.mvNode_Attr_Output) :
                dpg.add_text("This is a working node if the attribute have a child")
        
        with dpg.node(label="Bugged node fixed with empty string", pos=[100, 325]):
            with dpg.node_attribute(label="Test", attribute_type=dpg.mvNode_Attr_Output) :
                dpg.add_text("")

        with dpg.node(label="Bugged node 5", pos=[100, 450]):
            dpg.add_node_attribute(label="Input", attribute_type=dpg.mvNode_Attr_Input)

            with dpg.node_attribute(label="Test", attribute_type=dpg.mvNode_Attr_Output) :
                dpg.add_text("If the first attribute is empty the node will be bugged")
        
        with dpg.node(label="Bugged node 5 fixed", pos=[100, 525]):
            with dpg.node_attribute(label="Test", attribute_type=dpg.mvNode_Attr_Output) :
                dpg.add_text("If the first attribute have a child the node will be working correctly")
            
            dpg.add_node_attribute(label="Input", attribute_type=dpg.mvNode_Attr_Input)

dpg.setup_dearpygui()
dpg.show_viewport()

import time

while dpg.is_dearpygui_running():
    dpg.render_dearpygui_frame()
    time.sleep(0.25)

dpg.destroy_context()

n3odym3 avatar Dec 08 '24 10:12 n3odym3

I also have this, 2025

loneicewolf avatar Jun 29 '25 14:06 loneicewolf

I believe this is yet another case of Dear ImGui issue ocornut/imgui#7543. Unfortunately it cannot be fixed on DPG level, we're waiting for a fix from Dear ImGui's author.

v-ein avatar Jun 29 '25 16:06 v-ein

For anyone encountering this issue, the nodes grow proportional to the amount of horizontal padding each frame so it's possible to prevent the issue by setting the horizontal padding to 0. This leads to a rather squished look of course, but you can counteract that by adding spaces to the labels. For example:

import dearpygui.dearpygui as dpg

dpg.create_context()
dpg.create_viewport(width=1280, height=720)

with dpg.theme() as theme:
    with dpg.theme_component():
        dpg.add_theme_style(dpg.mvNodeStyleVar_NodePadding, 0, 8, category=dpg.mvThemeCat_Nodes)

with dpg.window(label="Node Editor", width=1280, height=720):
    with dpg.node_editor(tag="node_editor"):
        n1 = dpg.add_node(label="node", pos=[100, 100])

        n2 = dpg.add_node(label="node", pos=[100, 200])
        dpg.bind_item_theme(n2, theme)

        n3 = dpg.add_node(label=" node ", pos=[100, 300])
        dpg.bind_item_theme(n3, theme)


dpg.setup_dearpygui()
dpg.show_viewport()
dpg.start_dearpygui()
dpg.destroy_context()

Image

dav0dea avatar Jul 23 '25 14:07 dav0dea

It's possible someone mentioned this before, but this issue exists in both the menu bar and context popup, which prevents me from adding icons to menu items.

Unexpectedly, I found that this issue does not occur when the menu item is not the last component within a group. As a workaround, users can avoid triggering the issue by adding a transparent image or blank text after the menu item inside the group.

Testing confirmed that this workaround successfully prevents the issue in both window menus and context popup.

It is currently uncertain whether it will be effective for imgui, see issue comment by @v-ein.

https://github.com/user-attachments/assets/a7b04a73-06d0-474f-be7d-8bb8bcf0f6f2

# DearPyGui version: 2.0.1, Windows 11
import dearpygui.dearpygui as dpg


def print_me(sender):
    print(f"Menu Item: {sender}")


dpg.create_context()
dpg.create_viewport(title="menu icon", width=600, height=500)

# register icon texture
with dpg.texture_registry():
    dpg.add_static_texture(1, 1, [1, 1, 0, 1], tag="__icon")
with dpg.texture_registry():
    dpg.add_static_texture(1, 1, [0, 0, 0, 0], tag="__transparent")

with dpg.window(tag="Primary Window"):
    with dpg.menu_bar():
        with dpg.menu(label="File"):
            with dpg.group(horizontal=True):
                dpg.add_image(texture_tag="__icon", width=15, height=15)
                dpg.add_menu_item(label="Save", callback=print_me)
                dpg.add_image(texture_tag="__transparent", show=True)  # Must be shown

            with dpg.group(horizontal=True):
                dpg.add_image(texture_tag="__icon", width=15, height=15)
                dpg.add_menu_item(label="Save As", callback=print_me)
                dpg.add_text("", show=True)  # Must be shown

            with dpg.group(horizontal=True):
                dpg.add_image(texture_tag="__icon", width=15, height=15)
                with dpg.menu(label="Settings"):
                    dpg.add_menu_item(label="Setting 1", callback=print_me, check=True)
                    dpg.add_menu_item(label="Setting 2", callback=print_me)
                    with dpg.group(horizontal=True):
                        dpg.add_image(texture_tag="__icon", width=15, height=15)
                        dpg.add_menu_item(label="Setting 3", callback=print_me)
                        dpg.add_text(".")
                dpg.add_image(texture_tag="__transparent", show=True)

        dpg.add_menu_item(label="Help", callback=print_me)

        with dpg.menu(label="Widget Items"):
            dpg.add_checkbox(label="Pick Me", callback=print_me)
            dpg.add_button(label="Press Me", callback=print_me)
            dpg.add_color_picker(label="Color Me", callback=print_me)

    text_tag = dpg.add_text("Hello, world")
    with dpg.popup(text_tag):
        with dpg.group(horizontal=True):
            dpg.add_image(texture_tag="__icon", width=15, height=15)
            dpg.add_menu_item(label="Save As", callback=print_me)
            dpg.add_text("")

dpg.setup_dearpygui()
dpg.show_viewport()
dpg.set_primary_window("Primary Window", True)
dpg.start_dearpygui()
dpg.destroy_context()

wuyao1997 avatar Aug 30 '25 02:08 wuyao1997