Dynamic variable names?

[code]local buttons = 3
local buttonImage = { “btn1.png”, “btn2.png”, btn3.png" }
local buttonTable = display.newGroup()

for i=1, buttons do
button = display.newImage(buttonimage[i]) --button[1] = display.newImage()
buttonTable:insert(button)
end[/code]

I understand that this is the most common way to iterate and make objects. But what I’m wondering is if there is a way to declare dynamic variable names instead, like:

for i=1, buttons do local "button"..i = display.newImage() -- button1 = display.newImage() end

My hunch is that it just can’t be done, but my corona skill level is still short of a level-up. :slight_smile: [import]uid: 41884 topic_id: 15029 reply_id: 315029[/import]

Was searching for the exact same thing (something like this[] in flash), but than I actually forget why to use that, since there are always better workarounds.

Why would you want to do that?
Why not putting those into the group directly and/or into a table?
You could also give those Images other “attributes”
i.e.

[lua]for i=1, buttons, 1 do
local button = display.newImage(…)
button.name = i
buttonGroup:insert(button)
– or even table.insert(buttonTable,button)
end[/lua]

Chris [import]uid: 13097 topic_id: 15029 reply_id: 55587[/import]

Why not just use a table/array:

local buttons = 3  
local buttonImage = { "btn1.png", "btn2.png", "btn3.png" }  
local buttonTable = display.newGroup()  
local button = {}  
   
for i=1, buttons do  
 button[i] = display.newImage(buttonimage[i])  
 buttonTable:insert(button[i])  
end  

[import]uid: 19626 topic_id: 15029 reply_id: 55597[/import]

There are ways to do it if you *really* want to. Though I think the table of buttons is better, I’ll post this as an example of how it could be done.

Globals are easy:

for i=1, 10 do  
\_G["button"..i] = i  
end  
  
print( button1 ) -- here the global button1 is equal to 1  

locals are a bit different:

local \_local = {}  
\_local.\_\_index = \_local  
setmetatable(\_G, \_local)  
for i=1, 10 do  
\_local["button"..i] = i  
end  
  
print( button1 ) -- here the local variable button1 is equal to 1  

The main difference here is that the locals you declare this way will all have the same scope as the _local table.

And there are other reasons why this isn’t a good idea, but it is possible.

-Angelo [import]uid: 12822 topic_id: 15029 reply_id: 55603[/import]

@ Yobonja

Is there actually a benefit of doing it that way?
I really haven’t come across a good reason to make it - but I love to learn new stuff :slight_smile: [import]uid: 13097 topic_id: 15029 reply_id: 55607[/import]

xxxfanta: The “why” is simply because if you don’t know the number of buttons, you can’t declare the variables. (I won’t know if I need button2 until I know the variable, right?)

Building out a table works too (hence my original code), but it just seemed like a simple, elemental thing to do would be able to make variable names out of variables. Also, none of the table.function calls work in a displayGroup which can complicate things.

robmiracle: Looks like your code is identical to my original sample except:

  1. You didn’t miss the " I did. :wink:
  2. You’re inserting all of the buttons into button{} and then inserting button{} into buttonTable. Not really sure why? [import]uid: 41884 topic_id: 15029 reply_id: 55608[/import]

Yobonja: Well…uh…I’ve never even heard of _local or __index before, so I can see why it’s less desirable.Heck, I think I can finish coding the function before I can figure out exactly what’s going on there. But thanks for the demo :slight_smile: [import]uid: 41884 topic_id: 15029 reply_id: 55609[/import]

You’re original example wasn’t using an array:

button = display.newImage(buttonimage[i])

Each time you iterate through the loop, you keep reusing the variable “button” but it keeps reallocating memory. This is a prime example of a memory leak since you loose access to the previous buttons.

My code keeps unique references:

button[i] = display.newImage(buttonimage[i])

There was something commented out at the end of the line where it looks like you tried to use an array. You also needed to create the array before the loop:

button = {}

Hope that helps.
[import]uid: 19626 topic_id: 15029 reply_id: 55620[/import]

@richard9

the example by @robmiracle works, but i think that storing buttons in both a regular table and a display group is overkill - as they’re both tables so can both be used for storage.

the example by @yobonja is giving you the ability to do name look up as you asked for, but i don’t think it’s what you want. as they say, “be careful what you ask for because you might get it.” :slight_smile: one of the issues with this solution is that it requires having a deeper understanding of the Lua language. second issue is that in practice you’d never need to do this nor can i think of a reason why you would want to. :stuck_out_tongue:

i think an important question that you need to ask/answer is: “What are you *doing* with the buttons ?”
What do you want to happen when you click one ? why do you need to have a way to find them after they are created ? Do they need to act as a unit, a la Display Group ?
your answer to that will guide you to determine whether to use a Lua table or Corona Group. also, the key you use to retrieve them from the storage will play a factor as well.

the display group and the regular lua table can both be used as storage - they both have insert/remove/get functionality on them. (though the methods are different). however, i’d say that the one you choose depends on what you have intended for your buttons.
for example, putting display objects into a display group implies that the objects are going to act as a unit. if you change x,y position on the group, you change the location for all contained objects. if you change alpha on the group, you change for all contained objects.
the regular Lua table doesn’t do any of that. if you use it, it’s really just a raw Lua-based container for things, like your buttons or anything else you want. plus, you have A LOT more flexibility in how to index / lookup your values - see below.
so without knowing more about what you’re trying to achieve, i’d say that combining both examples from @robmiracle and @xxxfanta is the way to go. choose either display group or table, taking the above into consideration.
[lua]local buttons = 3

local buttonTable = display.newGroup()
– local buttonTable = {} – use this if just need a container object

for i=1, buttons do
local button = display.newImage( “btn” … i … “.png” )

button.name = i
buttonGroup:insert( button )
– or even table.insert( buttonTable, button )
end[/lua]
notice i took out the need to have a list of the button images. i noted from your example that you have already indexed the images on the file system, so you can take advantage of that in the loop as well. all you need to do is change the variable ‘buttons’ to control the amount of buttons which are created.
cheers,
dmc
just to add to the discussion, when using a regular Lua table for storage, the keys can be anything:

[lua]local buttonTable = {}
local b

– index by integer
buttonTable[1] = display.newRect( 160, 100, 100, 100 )
buttonTable[1].alpha = 0.5

– index by string, and use name directly as attribute
buttonTable[“button” … 1] = display.newRect( 160, 200, 100, 100 )
– these are the same
buttonTable.button1.alpha = 0.75
buttonTable[“button1”].alpha = 0.75

– index using object itself !
b = display.newRect( 160, 300, 100, 100 )
buttonTable[b] = b
buttonTable[b].alpha = 0.25
–[[ remove this to play with the group attributes
local buttonGroup = display.newGroup()

buttonGroup:insert( buttonTable[1] )
buttonGroup:insert( buttonTable.button1 )
buttonGroup:insert( buttonTable[b] )

buttonGroup.alpha = 0.5
buttonGroup.x = 200
–]][/lua]
[import]uid: 74908 topic_id: 15029 reply_id: 55644[/import]

Welll, first off, truly, thanks to all for responding. I thought it was a simple mechanical question but there has been a ton of variety in these well thought out responses. :slight_smile:

The original goal of this was simply because my designer brain immediately thought “hey, I can just use … to make dynamic variables on the fly! This is easy!” (*cough*) Basically, jayantv’s link is dead on with my thinking.

As a relative “noob”, tables flip between easy and intimidating for me. So to dmccuskey, I say, I know what I need, but sometimes it’s hard to glean how a particular approach does that for me without maximum understanding of that approach - understanding that doesn’t come without trial-and-error.

Now, as to what I’m *actually* trying to make…is the iPad bottom tab bar. I know there’s an existing template, but it’s not extensible and I’d pretty much have to go in and re-write half of the thing. For learning reasons I’d rather just make my own - that way I have some sturdy to share here and to use for myself on two radically different projects.

(And really, I like to try and respond to other guys posts too. :P)

edit: I do see how you removed the image table…but not so useful in a function where you’d arguably want to be able to state the needed images ahead of time. :slight_smile: [import]uid: 41884 topic_id: 15029 reply_id: 55646[/import]

@richard9,

yeah, there are some quirky aspects of Lua which can be confusing, and tables is one of them. for example, the fact that Lua uses the same base data structure for different situations and that structure can act a little differently depending on how you use it can cause issues. so, as you say, you will have to learn by trial-and-error, but i think once you’re familiar and comfortable with the idiosyncrasies, like jayantv says, “it’s a lot of fun”. in any event, it seems like you’re making great progress with Corona and Lua.

since you’re tackling the bottom tab bar, i’ll mention that i’ve done that too and added that code to a re-usable, extensible library i’ve started to put together. the lib uses object oriented programming exclusively (OOP is also part of the lib) so you can tweak it as much as you like, but you’d have to know about OOP and perhaps a little more about Lua. i have written docs and examples, so if you want to check it out: http://developer.anscamobile.com/code/dmc-corona-library

but i also understand the desire to Build It Yourself and be able to learn from that experience. i’m sure we’ve all been there. :slight_smile:

good luck with the project !

cheers,
dmc

[import]uid: 74908 topic_id: 15029 reply_id: 55660[/import]

@xxxfanta
I haven’t found any good reason to do it :slight_smile: just that it’s possible. it’s essentially the exact same thing though, you’re just adding the variable to a table.

@richard9
He puts it in the table so you can reference button1 by writing button[1].
Also, I’ve found that you can dump a display group into a table, then call the table function you want on that table.

-Angelo [import]uid: 12822 topic_id: 15029 reply_id: 55611[/import]

“the example by @robmiracle works, but i think that storing buttons in both a regular table and a display group is overkill - as they’re both tables so can both be used for storage.”

**SCRATCH THAT**

First, the OP created the table. And in this case, the display group is only holding buttons, so you could use it to reference the other buttons.

But I still think that using a specific buttons[] array is clearer and easier to understand whats going on.
[import]uid: 19626 topic_id: 15029 reply_id: 55724[/import]

@richard, have a read of the tutorial here

and to answer your question, as to why the button={} and buttonTable:insert

if you have a little idea about coronaSDK, you will see that buttonTable is declared as display.newGroup(), this is the group that @robmiracle has created to hold the buttons. This is a display object, nothing to do with arrays.

so after creating the button object, he is using the buttonTable:insert(button[i]) to place the display object into the display group. This line can be avoided by altering the code as
for i=1, buttons do button[i] = display.newImage(buttonTable, buttonimage[i])end[/code]and the buttons is the array where he has been holding all of the elements and what he is adding using button[i] is the item i not the array.and if you want to understand more about tables and arrays, you can read another tutorial here hope you have fun while learning lua, coz once you do, when you start *real* app development, you will really enjoy yourself.cheers,?:) [import]uid: 3826 topic_id: 15029 reply_id: 55640[/import]

I guess there are several ways to skin a cat…

No particular way is better than the other, the one which makes you feel comfortable is the best. Sometimes what happens is that in a given context, some things work best and some don’t where as in a different context things might be different.

I guess everyone that pitched in had good reasoning and code samples for the issue at hand, I avoid a lot of advance stuff in my tutorial and code as *I believe* that a beginner needs to understand how things work more importantly than understanding memory leaks at this stage. Once they get beyond the stage of basic syntax and operations, then they can bother about optimisations etc.

Just my two bits

cheers,

?:slight_smile: [import]uid: 3826 topic_id: 15029 reply_id: 55727[/import]

Yeah, I totally understand the memory leaks issue but my brain just can’t handle going back to recode everything to avoid require and globals yet. Gotta make something first and then make it reliable after. (Considering how badly I managed to break widget.newTableView…)

wait, what, I can insert display.newImage directly into a group right away? Nice.

Alright, more mindless jabber from me later. But I do appreciate the help - just looking at the examples in this thread has given me a good idea out of how to rope in the other bits. [import]uid: 41884 topic_id: 15029 reply_id: 55775[/import]

So, I hate to drag this out but I’ve sort of run into the exact wall I was afraid of by using tables.

I was hoping to do two things by referring to tables/groups inside of other tables/groups, like:

[code]function tabBar() – some code
return tabGroup – this is a master group containing buttons and over states.
end

myTab = tabBar()

myTab.buttonsGroup.button[1]:addEventHandler(“touch”, press) --theoretically would apply the handler only to button 1.
[/code]

or

tabBar.buttonsGroup.button[1].isVisible = false --to hide or reveal the over-state of a button

Neither method works, as far as I can tell, so I’m clearly approaching subtables wrong? [import]uid: 41884 topic_id: 15029 reply_id: 55826[/import]

do you have a group called tabGroup?
that has another group added to it called buttonsGroup?
which has an array added to it called buttons?
and each element in this buttons Array is a display object that can be made visible or invisible.

if you have YES to all the questions, let us look at it further. Please read and check carefully.

cheers,

?:slight_smile: [import]uid: 3826 topic_id: 15029 reply_id: 55828[/import]

Yeah, exactly.

local tabGroup = display.newGroup() -- holds everything local buttonsGroup = display.newGroup() -- holds all of the buttons local buttonsOverlay = display.newGroup() -- holds all of the button overlays local button = {} -- the buttons themselves, basically similar to above or your link. local buttonOverlay = {} tabGroup:insert(buttonsGroup) tabGroup:insert(buttonsOverlay) buttonsGroup:insert(button) buttonsOverlay:insert(buttonOverlay)

That’s not exactly how it goes - I don’t have access to the code from where I’m posting right now - but the gist is:

tabGroup -> buttonsGroup -> button[x]
tabGroup -> buttonsOverlay -> buttonOverlay[x]

So ideally I need to either add event listeners to each button[x], or to add one to buttonsGroup but then use if statements for each button within that. Likewise, I need to be able to toggle the isVisible property on each buttonOverlay[x].

The trick is that I need to do this outside of the function, so I’m returning tabGroup. My newbie brain of course assumes that I can then type this stuff…(assuming myTab = maketheTabBar())

[code]-- For attaching the event listener:
myTab.buttonsGroup.button[1]:addEventListener(“touch”, pressThis)

– For toggling visibility (by returning tabGroup, myTab == tabGroup, I think?)
myTab.buttonsOverlay.buttonOverlay[1].isVisible = false[/code]

…But of course Corona’s error is “buttonsGroup? What are you talking about?” So I’m assuming I’m using a completely wrong method to reference groups-within-groups. [import]uid: 41884 topic_id: 15029 reply_id: 55885[/import]

Hmm… I have been doing a lot of this in corona(dynamic “naming” of object… really just putting them in a table and referancing them by thier table index.)

I thought I would throw together a working sample… it is a little ugly (ok maybe more than a little) but I thought it might inspire someone else…

The following is a “Color Picker”. The number of colors displayed is based on the screen resoltion.(varible) and they are changed by referancing the rectangle(color) by it’s table index. (in this case it just cycles thru all off the objects but it is possible to change just one if you keep track of the indexes… like in anouther Lua table where the index is something usefull and the value is it’s position in the display group.)

[code]
Ww,Hh = display.viewableContentWidth, display.viewableContentHeight
BackgroundColor = display.newRect( 0,0,Ww,Hh);BackgroundColor:setFillColor(0,0,255)

function cButton(lx,ly)
local c=1
while customButton[c] do
local tT=customButton[c]
if tT[“active”]== “true” and lx > tT[“x1”] and lx < tT[“x2”] and ly > tT[“y1”] and ly < tT[“y2”] then
if tT[“command”] then
return tT[“command”]
else
return “color”,tT[“r”],tT[“g”],tT[“b”]
end
end
c=c+1
end
return nil
end

local testHandle = function (event)
– print("—began-----"…event.x…" “…event.y)
local lCMD,r,g,b = cButton(event.x,event.y)
if event.phase == “began” and lCMD then
print(”—began-----"…event.phase…"--------"…lCMD)
CMD = lCMD
elseif event.phase == “moved” and CMD then
print("—moved-----"…event.phase…"--------"…CMD)
if lCMD ~= CMD then
print("—cancel----"…event.phase…"--------"…CMD)
CMD = nil
end
elseif event.phase == “ended” and CMD then
print("—ended-----"…event.phase…"--------"…CMD)
if lCMD == “color” then
PickerGroup.alpha=0
PickerButtonGroup.alpha=1
local i = 1
–disable picker buttons
while i customButton[i][“active”]=“false”
i = i+1
end
customButton[PickerKey][“active”]=“true”
BackgroundColor:setFillColor(r,g,b)
elseif lCMD == “pick” then
displayPicker()
elseif lCMD == “more” then
displayPicker()
elseif lCMD == “cancel” then
PickerGroup.alpha=0
PickerButtonGroup.alpha=1
local i = 1
--disable picker buttons
while i customButton[i][“active”]=“false”
i = i+1
end
customButton[PickerKey][“active”]=“true”
end
CMD = nil
end
end
function createPicker()
local cgrid =math.floor(Ww/7)
local maxWIDE = 7
local maxHIGH = math.floor((Hh - 100)/cgrid )
local colorKey = 1
customButton = {}
local gW = 3–math.ceil(cgrid/2)–10 --width of lines
PickerGroup = display.newGroup()
local mH,mV = 1,1
while mH <= maxWIDE do
local bH=(mH-1)*cgrid
while mV <= maxHIGH do
local bV=(mV-1)cgrid
local rR,gG,bB = math.random (1,255),math.random (1,255),math.random (1,255)
cColor = display.newRect( PickerGroup,bH,bV,cgrid,cgrid);cColor:setFillColor(rR,gG,bB)
customButton[colorKey] = {}
customButton[colorKey][“x1”] = bH
customButton[colorKey][“x2”] = bH+cgrid
customButton[colorKey][“y1”] = bV
customButton[colorKey][“y2”] = (bV+cgrid)
customButton[colorKey][“r”]= rR
customButton[colorKey][“g”]= gG
customButton[colorKey][“b”]= bB
customButton[colorKey][“active”]=“false”
colorKey = colorKey + 1
mV = mV+1
end–vert while
mH = mH+1
mV = 1
end–horz while
– adding command buttons
–cancel
PickerGroup.alpha=0
–Picker button
PickerButtonGroup = display.newGroup()
local Choose = display.newRect(PickerButtonGroup, Ww/4,Hh/4,Ww/2,Hh/2);Choose:setFillColor(255,255,255)
customButton[colorKey] = {}
customButton[colorKey][“x1”] = Ww/4
customButton[colorKey][“x2”] = Ww-(Ww/4)
customButton[colorKey][“y1”] = (Hh/4)
customButton[colorKey][“y2”] = Hh-(Hh/4)
customButton[colorKey][“command”]= "pick"
customButton[colorKey][“active”]="true"
PickerKey = colorKey
colorKey = colorKey + 1
local title = display.newText(PickerButtonGroup,“Pick Color”,Ww/3,Hh/3, nil, 20 );title:setTextColor(0,0,0)
local Cancel = display.newRect( PickerGroup,0,Hh-100,Ww/2-2,100);Cancel:setFillColor(255,255,255)
customButton[colorKey] = {}
customButton[colorKey][“x1”] = 0
customButton[colorKey][“x2”] = Ww/2
customButton[colorKey][“y1”] = Hh-100
customButton[colorKey][“y2”] = Hh
customButton[colorKey][“command”]= "cancel"
customButton[colorKey][“active”]="false"
colorKey = colorKey + 1
local More = display.newRect( PickerGroup,Ww/2+2,Hh-100,Ww/2-2,100);More:setFillColor(255,255,255)
customButton[colorKey] = {}
customButton[colorKey][“x1”] = Ww/2
customButton[colorKey][“x2”] = Ww
customButton[colorKey][“y1”] = Hh-100
customButton[colorKey][“y2”] = Hh
customButton[colorKey][“command”]= "more"
customButton[colorKey][“active”]="false"
colorKey = colorKey + 1
local title = display.newText(PickerGroup, “Cancel”,Ww/8,Hh-50, nil, 20 );title:setTextColor(0,0,0)
local title = display.newText(PickerGroup, “More”,Ww/8
6,Hh-50, nil, 20 );title:setTextColor(0,0,0)
end–func

function displayPicker()
PickerGroup.alpha=1
PickerButtonGroup.alpha=0
local i = 1
--enable picker buttons
while i local rR,gG,bB = math.random (1,255),math.random (1,255),math.random (1,255)
PickerGroup[i]:setFillColor(rR,gG,bB)
customButton[i][“active”]=“true”
customButton[i][“r”]=rR
customButton[i][“g”]=gG
customButton[i][“b”]=bB
i = i+1
end
i = i+1
customButton[i][“active”]=“true”
i = i+1
customButton[i][“active”]=“true”
PickerButtonGroup.alpha=0
customButton[PickerKey][“active”]="false"
end
createPicker()
Runtime:addEventListener(“touch”,testHandle)
[/code] [import]uid: 40100 topic_id: 15029 reply_id: 55947[/import]