Using instantiate() to make a copy of a button makes the copy's signals not work anymore

Godot Version

4.6.1

Question

I have a button (its also a scene) that is placed at the top of a scroll list once and then the script it has makes it self duplicate for each different element that needs a button (imagine like for each thing you drew in a drawing program it makes button to go to that drawing in the main menu or smth) and while the duplication works fine if i set a signal in the button only the original will send it when clicked on.

`if dir.get_directories().size() > global.number:
	var itself = load("res://card_processor/select_card.tscn")
	var insta_self = itself.instantiate()
	$"..".add_child(insta_self)
else:
	global.number = 0`

^ how it gets duplicated

Is there a way i can detect a button being pressed within the button itself without the signal?

This doesn’t duplicate anything, it instantiates the scene, do you mean signals that you connected to a previous instantiated copy? They won’t be connected, they aren’t in the scene file

tbh the only reason im using instantiate() is cuz i looked up how to duplicate nodes and most info i found just told me to make it a scene and instantiate it instead but what that actually means im rly not sure, i know that when i click on the page that has the button a bunch of copy’s of the button happen now, i thought that meant there’s multiple of them, ergo duplication.

instantiate will instantiate a new instance of a given node. But it has nothing to do with already existing nodes on your scene. If you want to actually duplicate a node, you can use .duplicate().

yeah when i looked that up it was recommended not to cuz it doesnt port over script variables as well or smth? And i mean when i tried it and it didnt work and when i tried this it worked so they musta been on to smth. anyway back to the original question, can i make the button detect a press without the signal or mayb assign all the buttons a new signal after all the instances got created?

You are supposed to be responsible for signal connections per scene.
You should set up your signal connections either in the inspector if they’re specific to that scene, or you should have some kind of initialize function in your script that another script can call when it instantiates your node(s).

Generally it should go:

  • Instantiate node
  • Call it’s initialize function to set it up according to your needs (or just use ready if you don’t need anything special
  • Add it as a child to a node

Well yeah i did set it with the original button it just isnt set for the instance dupes it makes of itself cuz like you said, its a new instance. those instances don’t exist in the editor so i can hardly set it in there

Use connect() after instantiation to connect instance’s signals to whatever you need them connected.

but the instance doesnt have any signals to connect thats the intire problem

Instance is just a branch of nodes. The return value of instantiate() is a reference to the top node of that branch. I’m assuming that in your case it’s just a singular button node, so insta_self will be a reference to that button. It certainly has signals you can connect to.

It most likely has it, but since you used a generic “var” and didn’t specify the type, Godot doesn’t know what signals it should have. You should tell Godot what type your scene is, see type casting:

Right so i put this in the main scenes’s _process:

	for button in $ScrollContainer/VBoxContainer.get_children():
		button.pressed.connect(_on_select_card_pressed.bind(button))

and also added as button to the instatiating:

	if dir.get_directories().size() > global.number:
		var itself = load("res://card_processor/select_card.tscn")
		var insta_self = itself.instantiate() as Button
		$"..".add_child(insta_self)
	else:
		global.number = 0

and it still doesn’t work for anything but the original.

No. Put it right after instantiation.

..Is that not where it is already? putting it after the add_child just errors so i assume thats not what you meant

var itself = load("res://card_processor/select_card.tscn")
var insta_self: Button = itself.instantiate() as Button
insta_self.pressed.connect(...)
$"..".add_child(insta_self)
		var itself = load("res://card_processor/select_card.tscn")
		var insta_self: Button = itself.instantiate() as Button
		insta_self.pressed.connect(_on_select_card_pressed.bind($"../../.."))
		$"..".add_child(insta_self)

Also doesnt work, sorry if im being stupid

“Doesn’t work” means nothing. You need to describe in what way it doesn’t work.

It just still doesn’t do anything when clicking on the other buttons that arnt the original

Well you need to debug it. Put a print statement inside the signal handling function to see if it’s getting called at all.

What’s the bound argument supposed to represent?

Are there any errors reported by the engine at runtime?

a print statement is currently the only thing in the function already and no errors in runtime, dunno what you mean by the third thing