• 3D
  • How to remove focus from Control nodes?

Hi,

I'm working on a map editor for my game. I have small a UI that lets me select the brush size and strength for terrain sculpting using two sliders.

After I use one of the sliders to change a value, the focus remains on that slider. When I continue to edit the map, and press any key corresponding to 'ui_left' or 'ui_right' to move the camera, the last used slider changes value.

For now I have used an ugly hack. I created a dummy button node, set it to invisible and disabled, and any time there is an _unhandled_input in my map editor script, I call grab_focus() on that dummy button.

Is there a way to do this without using a dummy control node?

ˇDon't use those ui_ actions for the camera control first of all. They are supposed to be affecting items with focus, hence that name.

Second, figure out what your "default" control node should be. Create an action to clear focus with. Lets call it ui_clear_focus and assign escape to it. The idea is that when you press escape key, you check if focus is on anything other than the "default" node then make sure that when you press escape key while that "default" item isn't in focus that the focus gets set to it. If it is in focus then the escape key can be used for something else so you just return/pass.

Hi, thanks for your answer!

You're absolutely right about the ui_actions, I fixed that real quick.

About the "default" control node, I do not really have one, as in, there should be no UI elements reacting to keyboard input while the user is sculpting terrain. So the best "default" node would be the root control node for the UI I guess? For the ui_clear_focus action, having to press escape (or any other key for that matter) after every interaction with the ui seems kind of tedious. It is still nice to have, just not enough as the only option imo. So I added a script to the root control node (I had to change the nodes focus mode) :

extends Control

func _unhandled_input(event):
	grab_focus()

This way, every time there is input that is not meant for the UI, the root node takes away focus and no actions are passed to any of the ui elements. It seems to work fine for now, but I am not sure how 'safe' this is.

Any comments on this?

Does the slider fire an event after changing the value? If so, couldn't you just connect to the event and call release_focus() (assuming the slider is a Control)?

your_slider.release_focus()

Or change the solution you now have to using release_focus in combination with get_focus_owner?

extends Control

func _unhandled_input(event):
	var current_focus_control = get_focus_owner()
	if current_focus_control:
		current_focus_control.release_focus()

    When looking through the docs for a function like it I didn't notice release_focus() at all, good to know it exists. :)

    Yeah, when I first stumbled upon a problem concerning control focusing, it took me some time to find it as well! For some reason, it escapes notice... :)

    a year later

    hello i want to focus on next element how can i do that? i´ve tried to add the key i want to set the focus on the next element (enter) -> ui_focus_next but this has no effect...

    how can i do this by code or some other clever solution will be appreciated

    2 years later

    uaknight
    Thanks for the answer. I had a similar problem and they pointed me at this post.

    
    extends Control
    
    func _unhandled_input(event):
    	var current_focus_control = get_focus_owner()
    	if current_focus_control:
    		current_focus_control.release_focus()