How do I use _on_tab_clicked(tab) as a signal function?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Larck_Drakengold

The Problem:

I’ve been hunting around for documentation everywhere but cannot seem to find anything deeper than the basic node description.

I have a TabContainer with multiple Tabs within, and each tab is scripted to change its custom_style/panel stylebox texture resource on click. However, when I made the signal connection to the TabContainer, it gave me

func _on_tab_clicked(tab):

but then it also gave me an error about how the variable (tab) was not used, and to change it to (_tab). This doesn’t make it function at all. when I try to change the variable to an int based on what tab number it is, it yells at me again, saying

 "error(line number): Expected an identifier for an argument. "

The Question:

How am I supposed to access these tabs signals to actually have them function? Below is the script I have currently:

extends TabContainer

onready var red = load("res://source/art/red_styleboxflat.tres")
onready var orange = load("res://source/art/orange_styleboxflat.tres")
onready var yellow = load("res://source/art/yellow_styleboxflat.tres")
onready var green = load("res://source/art/green_styleboxflat.tres")
onready var blue = load("res://source/art/blue_styleboxflat.tres")
onready var purple = load("res://source/art/purple_styleboxflat.tres")
onready var rainbow = load("res://source/art/rainbow_Styleboxtexture.tres")
onready var panel = get_stylebox("panel","")

func _on_red_tab_clicked(_tab):
	panel.set_texture(red)

func _on_orange_tab_clicked(_tab):
	panel.set_texture(orange)

func _on_yellow_tab_clicked(_tab):
	panel.set_texture(yellow)

func _on_green_tab_clicked(_tab):
	panel.set_texture(green)

func _on_blue_tab_clicked(_tab):
	panel.set_texture(blue)

func _on_purple_tab_clicked(_tab):
	panel.set_texture(purple)

func _on_rainbow_tab_clicked(_tab):
	panel.set_texture(rainbow)

That “error” about an unused variable is actually just a warning and you can ignore it.

Eric Ellingson | 2020-03-19 16:41

:bust_in_silhouette: Reply From: njamster

it also gave me an error about how the variable (tab) was not used

A warning, not an error. This is an important difference! Unlike errors, one can ignore and even disable warnings (even though one probably shouldn’t… ;)). That specific warning exists to warn you about the fact that you defined a function expecting an argument but never actually use that argument inside. So either that requirement shouldn’t be there in the first place or you forgot to use the argument!

Now to your actual problem: TabContainer and Tabs are two distinct (!) ways to achieve tabs in your game. You don’t need one for the other! A TabContainer will render every Control-child as a Tab. So a tree like this will work as well:

- TabContainer
    - TextureRect
    - ColorRect
    - TextureRect

More so: it will work out of the box without the need to connect any signals. If you click on a tab, the Control-node associated with it will become visible. Simple as that! That being said, you can connect the TabContainers tab_selected-signal to enhance that default behavior. Check this out - there won’t be a warning this time:

func _on_TabContainer_tab_selected(tab):
    print("clicked on tab number ", tab)

So no matter which tab you select, it will always run the same callback. In order to get different behavior based on which tab was selected, you need to check the argument.

The most confusing part here is that using Tabs as children of a TabContainer will work - they are Control-nodes after all. However their tab_clicked-signal will be ignored, even if one connects it to a callback. Not a bug, but still very confusing.

so, what you are saying is, not to use the _on_tab_clicked() emitted from each individual tab to the TabContainer, but instead use _on_TabContainer_tab_selected(tab) and connect that to each tab?
I’ve been trying to play around with this and by using prints to check the signals, I got it somewhat reactive, but then it suddenly stopped working for some unknown reason. I’ve only managed to get a print statement to call out, and I have not been able to get the custom_styles/panel property to change to the stylebox resource I want when I send the signal.

would you be able to show me a working example of how I should go about using this function? I want to keep the TabContainer as it has the stylebox rect by default, and I simply wish to change that custom_style/panel property on each tab click, so red tab loads red, blue loads blue, and so on.

Larck_Drakengold | 2020-03-19 20:20

Your scene tree could look like this:

- "TabContainer" (type: TabContainer)
    - "Red" (type: Control)
    - "Green" (type: Control)

Then you would attach the following script to the TabContainer node:

extends TabContainer

func _on_TabContainer_tab_changed(tab):
	match tab:
		0:
			get_stylebox("panel").bg_color = "#FF0000"
		1:
			get_stylebox("panel").bg_color = "#00FF00"

And connect the TabContainer’s tab_changed-signal to the callback.

njamster | 2020-03-20 13:25

Alright, thanks! I now have a reliable connected signal response that isn’t breaking on me for any random reason! This answers one part of my problem, the second issue is related to this script but not the original posted Q, so I’ll have to see if I’ll need to post it as a second question regarding the actual accessing of “panel” property, since that still doesn’t react as it should.

Larck_Drakengold | 2020-03-20 15:12