I have a scene with a number of images loaded remotely. I call for those images on scene:show and in their listener I check if the user is still on that scene, if not, I simply remove the event.target.
My problem is that the user can enter->exit->enter the scene quick enough, so that the listener would load and show the images from the first entrance.
I would like to be able to pass an ID when I call loadRemoteImage, so that when it comes back in the listener I can check if it is still relevant.
Any ideas?
You could try wrapping the loadRemoteImage in a new function that overrides the callback like this
function loadRemoteImgWithData(data, url, method, listener, params, destFilename, baseDir, x, y)
if type(data) ~= "table" then
error("first argument must be data table", 2)
end
if type(params) ~= "table" then
y = x
x = baseDir
baseDir = destFilename
destFilename = params
params = nil
end
local function listenerOverride(event)
event.data = data
listener(event)
end
display.loadRemoteImage( url, method, listenerOverride, params, destFilename, baseDir, x, y )
end
Related
I'm using Lua 5.1 with IUP 3.5, and trying to use a list callback to populate an Address list depending on the Place selected. (The list is an editbox, so I will need to handle that in due course, but let us deal with the basics first). I've clearly got a fundamental misunderstanding of how to do this.
The code:
function MakeAnIupBox
--make some more elements here
listPlace = iup.list{}
listPlace.sort = "YES"
listPlace.dropdown = "YES"
--populate the list here
--now handle callbacks
listPlace.action = function(self) PlaceAction(text, item, state) end
end
function PlaceAction(text, item, state)
listAddress.REMOVEITEM = "ALL"
if state == 1 then -- a place has been selected
--code here to populate the Addresses list
end
end
The iup documentation describes the action callback for a list as
ih:action(text: string, item, state: number) -> (ret: number) [in Lua]
However, when I run this code I get:
text -- looks like some sort of metatable
item, state -- both nil
I've also tried coding the callback as
function MakeAnIupBox
--make some more elements here
listPlace = iup.list{}
listPlace.sort = "YES"
listPlace.dropdown = "YES"
--populate the list here
end
function listPlace:action (text, item, state)
listAddress.REMOVEITEM = "ALL"
if state == 1 then -- a place has been selected
--code here to populate the Addresses list
end
end
but that fails to run: the error is attempt to index global 'listPlace' (a nil value)
I'd prefer not to embed the callback in "MakeAnIupBox" because I'm hoping to make it (and the other associated callbacks) a resuable component in several Lua programmes that all process similar datasets but from different UIs.
If you do not want to embed the callback function inside your function, you can define it before and later assign it to your specified destination.
function Callback(self, a, b)
-- do your work ...
end
function CallbackUser1()
targetTable = { }
targetTable.entry = Callback
end
function CallbackUser2()
otherTargetTable = { }
otherTargetTable.entry = Callback
end
This solution needs the arguments to be always the same.
Note: All following definitions are identical
function Table:func(a, b) ... end
function Table.func(self, a, b) ... end
Table.func = function(self, a, b) ... end
The problem is in Lua usage.
In the first case, remember that this:
function ih:action(text, item, state)
translates into this:
function action(ih, text, item, state)
So it is missing the ih parameter.
In the second case, listCase exists only after MakeAnIupBox is called. You can solve that by declaring the function inside the MakeAnIupBox scope.
Building on the suggestion of Antonio Scuri which was not totally explicit, I have worked out that the code needs to read:
function MakeAnIupBox
--make some more elements here
listPlace = iup.list{}
listPlace.sort = "YES"
listPlace.dropdown = "YES"
--populate the list here
--now handle callbacks
listPlace.action = function(self, text, item, state) PlaceAction(listPlace, text, item, state) end
end
function PlaceAction(ih, text, item, state)
listAddress.REMOVEITEM = "ALL"
if state == 1 then -- a place has been selected
--code here to populate the Addresses list
end
end
I have 2 Lua files, namely mydialog.lua and rangecontrol.lua. The code in mydialog.lua is as follows:
local function mydialog()
--omitted
local wb_responses=activeobj() --wb_responses points to the current activeobj(), say Obj1
UI.m_txt=sys.rangetextcontrol(UI.sbSizerInput:GetStaticBox() ,wb_responses) --wb_responses is passed by reference
--Selection event happened
--Omitted
--If clicked on a checkbox execute the following line
print(wb_responses) --Still prints Obj1 instead of Obj2
end
sys.tools.mydialog=mydialog
Code in rangecontrol.lua:
local function rangetextcontrol(parent, wb_txtBox)
local m_txtBox=nil
m_txtBox=wx.wxTextCtrl( parent, wx.wxID_ANY, "", wx.wxDefaultPosition, wx.wxDefaultSize, 0 )
local function GetRange()
wb_txtBox=activeobj()
local ws=activeobj():cur()
local rng=ws:selection()
if (rng==nil) then return end
m_txtBox:SetValue(rng:tostring()) -- Here wb_txtBox correctly refers to Obj2
end
m_txtBox:Connect( wx.wxEVT_LEFT_DOWN, function(event)
wb_txtBox=activeobj() --Current activeobj() changed, say Obj2
local ws=wb_txtBox:cur()
ws:connect(GetRange) --There is a selection event, call GetRange
event:Skip()
end)
return m_txtBox
end
sys.rangetextcontrol=rangetextcontrol
Briefly what happens:
1) A dialog starts and it has a textcontrol (there might be several textcontrols)
2) When user makes a selection from an object, the text box is populated.
3) My goal is to track from which object the selection is made.
My confusion: Although I pass wb_responses a userdata type, which should be passing by reference to the rangetextcontrol which keeps track of the selections, it seems that wb_responses never changes since it always prints info on Obj1. Therefore, I assume it always points to the first object that it has been initialized with in mydialog.lua. What could I be doing/thinking wrong?
local function mydialog()
--omitted
local wb_responses=activeobj() --wb_responses points to the current activeobj(), say Obj1
UI.m_txt=sys.rangetextcontrol(UI.sbSizerInput:GetStaticBox() ,wb_responses) --wb_responses is passed by reference
--Selection event happened
print(wb_responses) --Still prints Obj1 instead of Obj2
end
You print wbresponses right after you initialize it. How should it change its value? There won't be any event handling between those two lines of code.
This is a weird question as I'm not so sure how to ask, but here's the problem:
BeforeTime = os.clock()
function NewFunction( Name, Value )
Name = function()
return Value
end
end
NewFunction( RunningTime, (os.clock()-BeforeTime) )
while true do
print(RunningTime()) -- will always return same value, i want the updated
end
The example above is not exactly my context, but its the easiest way to explain my problem.
I guess I could require that the parameter 'Value' needs to be a function, but is there another way?
NewFunction creates a function and assigns it to the Name parameter. But, in Lua, actual parameters are passed by value (like Java and C) and formal parameters are effectively local variables. The assigned value is never used and it can't be used outside the function.
To make a function return a non-empty list of values, use a return statement.
Here's a similar function for a timer:
local function CreateTimer()
local BeforeTime = os.clock()
return function()
return os.clock() - BeforeTime
end
end
You can use it like this:
local RunningTime = CreateTimer()
while true do
print(RunningTime())
end
Your code does not run because NewFunction doesn't do what you think it should.
If you add the line below before the loop, then it works fine.
RunningTime = function() return (os.clock()-BeforeTime) end
Basically I want to know when function;
button[n]:onclick() --where n can be any string value
gets called, and send its name (specifically I want to send "n") to another function;
function allbuttons(n) --where n is the n from button[n]:onclick()
which then processes all possible requests.
I want to do this because button[n] is specified, and therefore the button[n]:onclick() gets triggered every time the button is clicked, but it doesn't seem right to write these function every time I want another buttonclick to be processed in the big allbuttons function;
function button['options']:onclick()
allbuttons('options')
end
function button['quit']:onclick()
allbuttons('quit')
end
(...)
function button[n]:onclick()
allbuttons(n)
end
I've tried something like;
debug.sethook(allbuttons, 'c')
function allbuttons()
n = debug.getinfo(2).name
end
but I guess I don't fully understand how to use debug.sethook ..
Set button[n]:onclick to be the function you want (allbuttons), except that here there is one tricky bit, the value n. You likely know already that you could do
button[n].onclick = allbuttons
But if the event dispatcher calls onclick as button[n]:onclick() then allbuttons will always get button as first argument. If what you really want in allbuttons is to know the button[n] instance that was clicked, all you need to do is change the definition of allbuttons(n) to allbuttons(button) and change its code accordingly.
If you need n and it's not available any other way, you can create an anonymous closure with access to n as an upvalue (see http://www.lua.org/pil/6.1.html for details):
function sendClickToCommon(button, n)
button[n].onclick = function (self)
allbuttons(n)
end
end
sendClickToCommon(button, 1)
sendClickToCommon(button, 2)
sendClickToCommon(button, 3)
Or you could do it this way too:
function getAllbuttonsN(n)
return function (self)
allbuttons(n)
end
end
button[1].onclick = getAllbuttonsN(1)
The code is simpler but the index appears twice in the expression, a potential source of error.
I can't figure out how to put the objects created by a simple function in a table, to have them figure as individual identities..
E.g.
local function spawncibo()
nuovoCibo = display.newImage("immagini/cibo/cibo001.png")
end
timer.performWithDelay(1500, spawncibo, -1)
I tried to do it with a for loop, but it doesn't work (if i try to print the table I always get a nil result).
Any suggestion would be immensely appreciated!
Providing I have correctly understood your question, you may try something like this :
local cibo = {}
local function spawncibo()
cibo[#cibo+1] = display.newImage(string.format(
"immagini/cibo/cibo%3d.png", #cibo+1))
end
timer.performWithDelay(1500, spawncibo, -1)
This will read files cibo001.png, cibo002.png, ... every 1.5 s and put all images into the cibo array.
local spawnedCibos = {}
local function spawncibo()
nuovoCibo = display.newImage("immagini/cibo/cibo001.png")
table.insert(spawnedCibos, nuovoCibo);
end
timer.performWithDelay(1500, spawncibo, -1);
local function enterFrameListener( event )
for index=#spawnedCibos, 1, -1 do
local cibo = spawnedCibos[index];
cibo.x = cibo.x + 1;
if cibo.x > display.contentWidth then
cibo:removeSelf();
table.remove(spawnedCibos, index);
end
end
end
You could try this...
local spawned = {} -- local table to hold all the spawned images
local timerHandle = nil -- local handle for the timer. It can later be used to cancel it if you want to
local function spawnCibo()
local nuovoCibo = display.newImage('immagini/cibo/cibo001.png')
table.insert(spawned, nuovoCibo) -- insert the new DisplayObject (neovoCibo) at the end of the spawned table.
end
local function frameListener()
for k, v in pairs(spawned) do -- iterate through all key, value pairs in the table
if (conditions) then -- you will probably want to change conditions to some sort of method to determine if you want to delete the cibo
display.remove(spawned[k]) -- remove the part of the object that gets rendered
spawned[k] = nil -- remove the reference to the object in the table, freeing it up for garbage collection
end
end
end
timer.performWithDelay(1500, spawnCibo, 0) -- call spawnCibo() every 1.5 seconds, forever (That's what the 0 is for) or until timer.cancel is called on timerHandle
Runtime:addEventListener('enterFrame', frameListener) --
If you've got any other questions, feel free to ask.