Godot: Button signals do not work after reparenting node at runtime

Created on 11 Jun 2019  路  5Comments  路  Source: godotengine/godot

Godot version:
Godot 3.1.1

OS/device including version:
ArchLinux

Issue description:
When I try to reparent a button with

var AnotherParent = get_node("path/to/another/parent")
get_parent().remove_child(self)
AnotherParent.add_child(self)

my signals stop working.

For example, if I reparent the button when it is clicked (button_down signal), then I won't receive button_up signal after releasing the mouse. However I can click again, and receive button_down again.

Steps to reproduce:

  1. Add a button to a scene
  2. Attach a script to that button
  3. Connect button_down and button_up signals to itself
  4. When button_down signal is called, reparent the button.

Minimal reproduction project:
signals_when_reparenting.zip

archived bug discussion gui

All 5 comments

The callbacks still exist if you reparent.

I'm not sure if this is a bug or intended. The signals are probably thrown away when you remove the object.
The problem is the button_up signal doesn't get a chance to execute the callback before the object is removed. Alternatively, you would remove the object after you receive the signal and perform the callbacks.

Well I'm just gonna share a workaround that I used to solve this problem.

Instead of using the signal button_up I used the _input() method.

var clicked = false

func button_down():
    clicked = true
    # reparent stuff

func _input(event):
    if event is InputEventMouseButton:
        if clicked and not event.pressed:
            clicked = false
            # reparent stuff

Currently all UI elements seem to treat removed and invisible controls as losing focus. Do you have use cases where controls are moved in the tree? If it's general enough this behaviour could be changed.

Details: signals have nothing to do with this. It's caused by the viewport resetting the currently focused element on child removal.

https://github.com/godotengine/godot/blob/2c6daf73f3a1077dfae0ca88117a3f4b583eb7e6/scene/main/viewport.cpp#L2477-L2482

The button resets its state as well.

https://github.com/godotengine/godot/blob/2c6daf73f3a1077dfae0ca88117a3f4b583eb7e6/scene/gui/base_button.cpp#L121-L129

Do you have use cases where controls are moved in the tree? If it's general enough this behaviour could be changed.

Yeah. I was making an inventory system, where all items are in a scroll container, but when you pick an item up, and drag it somewhere, the picked up items would disappear if you dragged them outside of the scrollContainer bounds. So then I decided to move all picked up items to another container, and when they're released somewhere, move them back to the scrollContainer.

I tried the project and I don't actually see any bug. The button_down signal is received correctly. The button_up doesn't arrive, because _it's never emitted_. The button is unpressed, however no via input, but due to being removed from the tree, so it doesn't emit the signal. Case closed.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

EdwardAngeles picture EdwardAngeles  路  3Comments

gonzo191 picture gonzo191  路  3Comments

RayKoopa picture RayKoopa  路  3Comments

bojidar-bg picture bojidar-bg  路  3Comments

SleepProgger picture SleepProgger  路  3Comments