Concatenating variable names at runtime

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

I have a GUI screen with 100+ elements that will have different values based on user selections, very spreadsheet like. I am trying to find a way to concatenate the control names at runtime to assign values. I tried the method below, and it worked for creating variable names, but I couldn’t get the displayed control value to update with the addition of the ‘.text’. Any thoughts out there on how to do this? I am aware of this project, but it won’t work for what I am trying to do.

# mapping control to a variable  
onready var test12_button = $ComponentDisplay/Component12Button;

# setting control value
var id = 12
set("test" + str(id) + "_button.text", "1,000")

** the displayed text value of the GUI control would now be "1,000"
:bust_in_silhouette: Reply From: jgodfrey

I don’t think concatenation is a good approach here. However, regardless of the solution, you’ll have to have some way of connecting a control’s “ID” to the value it should be displaying. I’m not sure how you’re doing that today.

For example, in your above code, how do you know (in your code) that control 12 needs to have the value of 1,000? Assuming you already have that handled, I think a far better solution (than concatenation) would be to simply store the control references in an appropriate collection (Array or Dictionary) with your internal reference as a key to the item.

So, in your above example, that could be something like:

var control_collection = {12: $ComponentDisplay/Component12Button}

Then, you could simply do something like this:

control_collection[12].text = "1,000"

To drill down a little more. Underlying all this is a SQLite database that is providing the controls a lot of the data. I have an optionbutton the user selects a value from, then next to that an lineedit box for writing the number of optionbutton items they want. Then after that there are 8 other different lineitem boxes, in a row, that will hold calculated values in different categories based on the user selection in the first two controls. There are 20 rows of controls following that format. So a total of 200 different controls in this section. Below is how I’m doing it now, but I would like to understand your idea better:

# function call   
component_cost_check(1,component1_option_button.text,funct.flprep(component1_quantity_building.text))
        
func component_cost_check(array_xposition, component_title, quantity, type=" "):
      if (quantity <= 0 or component_title == 'None'):
            return
        
       # code under here computing all values of the other 8 boxes and saving results to an array
        
       # eventually hits a line like this for each of the 8 calculated boxes
       set_component_costs(array_xposition,1,"MetalCost")


func set_component_costs(array_xposition, array_cost_position,cost_type):
      # setting values back to controls
      var node_name = ''
      if (array_xposition < 31):
            # 'other' component
           node_name = ("OtherComponentCosts/Component" + str(array_xposition) +
        			"Costs/" + cost_type + "Value")
        
           # getting the node name
          var temp_node = get_node(node_name)
        
        # setting node value	
        temp_node.text = funct.test_stepify(cost_array[array_xposition][array_cost_position])

What it boils down to is using ‘get_node(node_name)’ to set the control name.

grymjack | 2022-11-29 20:32

So your suggestion of:

var control_collection = {12: $ComponentDisplay/Component12Button}

is interesting, but how would I easily initialize the whole control_collection of over 200 different controls? A for loop? something like below?

var control_collection
var control_name
var cost_name = ['Metal', 'blah', 'blah']  # 8 different costs
for width in range(0, 10):
	for depth in range(0, 20):
		control_name = "$Component" + str(depth) + "Display/Component" + str(depth) + cost_name[width] + "Button"
		control_collection = {width: control_name}

grymjack | 2022-11-29 20:47

I feel the way I am doing it now is clunky and inelegant, but it has the positive of working :frowning:

grymjack | 2022-11-29 20:50

It’s difficult to provide a detailed response based on the above (and, I didn’t completely follow everything in your response).

Really though, ignoring the details, the point is that you can get a reference to all of the controls and store them for easy future access. Whether you do that via a loop similar to what you have above, or via a get_children() call, or via groups and a get_nodes_in_group() call, or something else entirely… While the specifics will depend on your game’s structure and your goals, I’m just suggesting that you should get those references and store them in whatever structure lends itself to easy retrieval downstream.

No matter how you go about doing that, it’s a far better solution (IMO) than trying to fabricate those references after-the-fact, which is difficult, brittle, and prone to error.

jgodfrey | 2022-11-30 17:01