New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Individual mouse click callback for Node Editor grid & nodes #2289
Comments
https://dearpygui.readthedocs.io/en/latest/documentation/io-handlers-state.html |
if you are recommending me utilization of item hander like following, it generates binding error when it calls the dpg.bind_item_handler_registry(...) API, and then I couldn't figure it out.
as I described in the previous post, the item handler is working well with a node, but it doesn't work with "node editor".
|
Can you post the entire error message? There should be more diagnostic lines above that "Exception has occurred" line. |
What kind of IDE is this? Can you run your application from the command line? |
It definitely skips the diagnostics; theres should be either a console window in the IDE, or you can run it from command line and see full output there. |
VS Code typically opens a Terminal panel at the bottom of the window, which is identical to CLI (you can even type commands there). Not sure if it's turned off or somehow suppressed in your installation. Regarding the error, take a look at the "Message:" line. That's about it. For some reason the node editor does not support the "clicked" handler. Personally I don't know the reason. A typical way to circumvent it is like in this comment, use a global click handler (the one you have in Now let's check whether I understand your problem correctly:
|
current my environment & situation is like following :
there are 2 problem cases here : secondary, if I use "with dpg.popup(parent=self._previewImageTag):" for the individual nodes, the right click on individual node doesn't launch popup window and it calls only the global click handler. |
The latter works fine for me. I've just tried it on an image within a node, and the popup does show up. Except that first time it's shown in the top left corner of the window, which is probably caused by #1691. with dpg.node(label="Node 1", pos=(20, 20)):
with dpg.node_attribute(label="Attr", attribute_type=dpg.mvNode_Attr_Output) as attr1:
dpg.add_text("Text")
width, height, channels, fg_data = dpg.load_image(str(Path(__file__).parent / "_transparent.png"))
with dpg.texture_registry(show=False):
dpg.add_static_texture(width=width, height=height, default_value=fg_data, tag="fg_image")
img = dpg.add_image("fg_image")
with dpg.popup(img, min_size=(0, 0)):
dpg.add_menu_item(label="Hey there") |
for the latter one, actually it doesn't work if you combine it with a global click handler (dpg.handler_registry + dpg.add_mouse_click_handler). It just popup only the window for global handler and it doesn't show the popup for the nodes.
|
Well, since your global callback fires even if you click on the node, it shows the To handle that properly, you need to determine whether a node was clicked, and ignore the global click in this case. If you have relatively few nodes, you can just iterate over them and see if one of them is hovered: def on_click_global():
if dpg.is_item_hovered(editor):
for node in dpg.get_item_children(editor, slot=1):
if dpg.is_item_hovered(node):
print("Ignoring global click")
return
print("Editor clicked")
I agree that it would be nice to have an item_clicked handler on the node editor, but this doesn't necessarily means that clicks won't "fall through" to the node editor. There are no explicit rules in Dear ImGui and DPG on how to handle such situations, and implementation-wise it might be easier to make them fall through ( |
My workaround idea was also a way checking the nodes in the global handler, but I couldn't make sure that it can ignore the event & defer the mouse click event to node's event and how to do it. also, I didn't know about the API call dpg.get_item_children(editor, slot=1) can return the node instance to check the status ( actually, this is the key information than is_tem_hovered(...) API ). BTW, I still believe that the node editor should have the item_clicked handler because it is also an item which can be referred with dpg.is_item_hovered(editor) API. With the workaround, it can allow me to use right click handlers for node editor & nodes, that is great...thanks for your detail explanations and the workaround snippet code. Additionally, still there is a weird behavior and then I am trying to narrow down the case.
up to here it is an expected behavior
I think the problem is because a user reaction for the node editor popup was not done and the state-machine of the node editor popup is still waiting for user action. |
I think it's because your global click handler opens a popup even if it is already displayed, where as Since you know the popup ID of your node editor popup, you can try to check if it's visible and don't bring it again in this case: def on_click_global():
if dpg.is_item_hovered(editor) and not dpg.is_item_visible(popupTag): Give it a try and see. Depending on the exact sequence of events it might not work; in that case I can try to think out a better solution. |
I just tried and it is not helpful and couldn't solve the issue. |
Maybe I misunderstood your problem with popup menus. I've just re-read it and I don't really get it what the problem is in step 4. For me, popups work just fine: Here's the script I used: from pathlib import Path
import dearpygui.dearpygui as dpg
dpg.create_context()
with dpg.window(popup=True, show=False, min_size=(0, 0)) as popup_wnd:
dpg.add_text("Editor popup")
with dpg.window(label="Example Window") as main:
with dpg.node_editor() as editor:
with dpg.node(label="Node 1", pos=(100, 100)):
with dpg.node_attribute(label="Attr", attribute_type=dpg.mvNode_Attr_Output) as attr1:
width, height, channels, fg_data = dpg.load_image(str(Path(__file__).parent / "handshake.png"))
with dpg.texture_registry(show=False):
dpg.add_static_texture(width=width, height=height, default_value=fg_data, tag="fg_image")
img = dpg.add_image("fg_image")
with dpg.popup(img, min_size=(0, 0)):
dpg.add_menu_item(label="Node popup")
def on_click_global():
if dpg.is_item_hovered(editor):
for node in dpg.get_item_children(editor, slot=1):
if dpg.is_item_hovered(node):
print("Ignoring global click")
return
print("Editor clicked")
dpg.show_item(popup_wnd)
with dpg.handler_registry() as handlers:
dpg.add_mouse_click_handler(callback=on_click_global)
dpg.create_viewport(width=500, height=500)
dpg.setup_dearpygui()
dpg.set_primary_window(main, True)
dpg.show_viewport()
dpg.start_dearpygui()
dpg.destroy_context() |
After click on any place, regardless on the node or node editor, your animation is always doing another extra click to hide the popup, and then the dedicated proper popup is showing for next click and it shows only node editor popup for next clicks. could you right-click the node and directly right-click on node editor area and right-click once again on node ? My question was how I can replace the "extra click" with programmable way to show the right popups from the 3rd click. |
So you want it to work like this - correct?
|
Yes, in order to give user more intuitive operations for new node adding and configuration of node parameters with minimum clicking and then user can skip the actual selection for the popups. |
Something like this? from pathlib import Path
import dearpygui.dearpygui as dpg
dpg.create_context()
with dpg.window(popup=True, show=False, min_size=(0, 0)) as editor_popup:
dpg.add_text("Editor popup")
with dpg.window(popup=True, show=False, min_size=(0, 0)) as node_popup:
dpg.add_text("Node popup")
with dpg.window(label="Example Window") as main:
with dpg.node_editor() as editor:
with dpg.node(label="Node 1", pos=(100, 100)):
with dpg.node_attribute(label="Attr", attribute_type=dpg.mvNode_Attr_Output) as attr1:
width, height, channels, fg_data = dpg.load_image(str(Path(__file__).parent / "handshake.png"))
with dpg.texture_registry(show=False):
dpg.add_static_texture(width=width, height=height, default_value=fg_data, tag="fg_image")
img = dpg.add_image("fg_image")
def on_click_global():
# Note: could as well test for `dpg.get_active_window() in (editor_popup, node_popup)`
if dpg.get_item_configuration(dpg.get_active_window())['popup']:
# Let the popup close
dpg.split_frame()
if dpg.is_item_hovered(editor):
for node in dpg.get_item_children(editor, slot=1):
if dpg.is_item_hovered(node):
print("Node clicked")
dpg.show_item(node_popup)
return
print("Editor clicked")
dpg.show_item(editor_popup)
with dpg.handler_registry() as handlers:
dpg.add_mouse_click_handler(button=dpg.mvMouseButton_Right, callback=on_click_global)
dpg.create_viewport(width=500, height=500)
dpg.setup_dearpygui()
dpg.set_primary_window(main, True)
dpg.show_viewport()
dpg.start_dearpygui()
dpg.destroy_context() |
All clicks in the video are right-clicks. A left-click will simply close the popup without bringing up a new one. |
Ya, it is a very similar to desired behavior, but it is not perfectly matching to my looking point. The implementation should be different way instead of processing all of the operations within a global handler. With the the context, the example is good enough to show the global handler can treat either node editor and nodes, but it is not good enough to split the operations for each node and node editor. |
If you want to have individual handlers for nodes, you'll have to dispatch events to local handlers on your own. Here's the problem: a local |
The global handler receives all clicks and therefore is able to determine the moment when the popup closes and the click is on a node widget. |
I'd like to implement right mouse click callbacks for 2 purposes and launch different popup(window) for selections.
firstly, the "node editor" has the callback for the right mouse click :
secondary, the node has a dedicated callback for the right mouse click with popup:
the problem is that the right mouse click calls only the "node editor" callback.
if I change the mode callback with the item handler with following APIs, the right mouse callback happens for both.
the expected behavior is independent callbacks such as the right mouse click on node should call only the dedicated callback for node and the right mouse click on the "node editor" grid calls the callback for "node editor".
is there any way to register different callbacks for node & "node editor" with same mouse click ?
The text was updated successfully, but these errors were encountered: