Dynamicall calling a sub

Scubaticus

Active Member
Licensed User
As I was looking for a way of dynamically a sub I end up with the following solution
Sub App_Start
gotoSub("thisSub")
appClose
End Sub

Sub gotoSub (whichSub)

ErrorLabel(gotoError)
inError = false

AddComboBox("Form1", whichSub, 0, 0, 0, 0)
control(whichSub).Add(0)
control(whichSub).Add(1)

control(whichSub).SelectedIndex = 0
AddEvent(whichSub, SelectionChanged, whichSub)

'The event SelectionChanged will trigger the call
control(whichSub).SelectedIndex = 1
control(whichSub).Dispose
return

gotoError:

if inError then return
inError = true

if control(whichSub).Count = 2 then
Msgbox ("Error: Calling another gotoSub(" & chr(34) & whichSub & chr(34) & ") before the first one finished!", "thisSub", cMsgboxOK, cMsgBoxExclamation)
end if

return


End Sub

Sub thisSub (a,b)
Msgbox ("How did you get in thisSub?", "thisSub", cMsgboxOK)
gotoSub ("anotherSub")
End sub

Sub anotherSub (a,b)
Msgbox ("Another dynamically called sub.", "AnotherSub", cMsgboxOK)

'The next gotoSub causes an error
gotoSub ("thisSub")
End sub

Now this litte app works and the subs are called dynamically, but when used in a bigger app it's giving me index (control(whichSub).SelectedIndex = 1) error, saying the index does not exists. A .Count however shows 2 items. I also wondered at what time a .Dispose is really disposed, because first I used a single combo box, but after a .Dispose I got an error the control was already defined when I tried to create it again.

So it works but doesn't work. Any concerns?

Scub
 

Cableguy

Expert
Licensed User
Longtime User
If you are going to create the same control again, why not instead just empty the combo list, and/or delete specific items?

In my Helpfile Creator app I used a combobox and an arraylist to keep a valid relation between the existim items and the related controls...
For example my app dinamicly adds textboxs and lets you delete any textbox created... then deleting the related item in the combobox would cause a relation error...but adding an arraylist and fillet at the same time as the combobox in order to keep a valid relation based on items value and not on items index....
 

dzt

Active Member
Licensed User
Remove
control(whichSub).Dispose

and in every dynamically called sub add in the first line

control("DynSubName").Dispose
ex. control("thisSub").Dispose

In your way you are disposing controls before the event is fired

EDIT: No, my mistake. Events are fired and .Dispose never called. But doing what I said, works fine.
 
Last edited:

Scubaticus

Active Member
Licensed User
In your way you are disposing controls before the event is fired

The event is fired when control(whichSub).SelectedIndex = 1 is executed (thats what I see in the debugger). The next step is .Dispose so I don not understand what you mean by dispose before event is fired.

When I do an addcombo, add some (2) items, add the event, change the value which will execute the event and then dispose the combo, I still lhave a count of 2, but cannot change the selectedindex.

The litte app above works normally, but not in a bigger app.

I have to say however that this is my first event driven language I'm working with.

@Calbleguy: for the combo's I also use an array to retriev the index I want (which is not the selecteditem because I load the combo's from sorted CSVLoad tables. It would be nice to have our own defined 'selecteditem' value instead..or a way to direct link a table field as selectedindex and another tablefield as the item() value)


Scub.
 

Cableguy

Expert
Licensed User
Longtime User
It would be nice to have our own defined 'selecteditem' value instead..or a way to direct link a table field as selectedindex and another tablefield as the item() value)

keep in mind that if you operate both arrays at the same time, your relation stays unchangeable...
so you can fill both array in one sub and the use the index to call a sub or erase an item in both arrays
 

Scubaticus

Active Member
Licensed User
keep in mind that if you operate both arrays at the same time, your relation stays unchangeable...

What I normally do to load the combobox values from a table is:

'------------------------------------------------------
Sub addComboValues(forCARD, forField, fromTbl, fromFld)
'------------------------------------------------------

comboFld = cardInfo(forCARD).frmPrefix & forField
AddArrayList(comboFld & Arr)

for ii = 0 to control(fromTbl).RowCount-1

cellVal = control(fromTbl).Cell(fromFld,ii)
control(comboFld).Add(cellVal)
control(comboFld & Arr).Add(control(fromTbl).Cell("NR",ii))

next
End Sub

My CSV table(s) looks like:

NR,ITEM
1,Item1
5,Item2
23,Item3
7,Item4

Now when I want my real selectedindex I use control(comboFld &Arr).Item(x) where x = the combo's selected index.

So in my case I need for every defined combobox:

- Table
- Combobox
- Array

Every value of my combo boxes can be changed, deleted and added.
Perhaps there's a smarter way doing this, but I didn't find one at the moment.

Scub
 

Scubaticus

Active Member
Licensed User
I'm not sure if this is the code in your code.

So does this mean after I change a value which triggers a sub the program AND executes the Sub (another thread) AND continues to the next line?

.....
combo.selecteditem = 1 (triggers to call the sub)
combo.dispose (while the sub is still executed)
.....

This could explain the errors I've got. When returning from the sub, the combo is already disposed.....

Is this true?

Scub.
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
There is only one thread (most of the times).
Because of the .Net implementation you will not be able to dispose the control until you've exit from the event sub.
The workaround for this issue is to use a timer:
B4X:
Sub Combo1_Event
...
timer1.interval = 10 'ms
timer1.enabled = true
end sub

Sum Timer1_Tick
 Timer1.Enabled = false
 Combo1.Dispose
End Sub
 

Scubaticus

Active Member
Licensed User
Ok, thanks guys for all your quick replies. I'll try if the dispose in the sub works for me.

When I look at Erels code, he does the same, but in another sub giving the Combo1_Event sub time to finish.

But when I understand Erels explanation right (dispose a control within an event raised), what dzt does, is not 'legal' either?

Scub.
 

dzt

Active Member
Licensed User
Hi Scubaticus,

In my country we say:
"Those who the night makes, sees them the day and it laughs"

I think the yesterday approach drives to a chaos.

Attached is my approach under the daylight, completely different.
Shows among the way I thought, what happens when we call a sub from inside another sub.

I hope I helped a bit.

Regards
 

agraham

Expert
Licensed User
Longtime User
I looked for a low-overhead way of dynamically calling a sub without the overhead of creating a control and thought of using an existing control on which I could raise an event - the main form!

As Addevent seems to actually ReplaceEvent I can switch the forms' Show event and fire it by the form's Show method. So now I can control which Sub runs when any code calls Form.Show. I am not sure if that is what you wanted.

There is an oddity in that trying to reinstate the Form's original Show event Sub does not work. Maybe Erel can explain why.
 

Scubaticus

Active Member
Licensed User
I think the yesterday approach drives to a chaos.

Sub gotoSub (whichSub)

select whichSub
case "thisSub"
thisSub(1,2)
return

case "anotherSub"
anotherSub(1,2)
return

end select

End Sub

This is a solution I started with at the first place, but I did not want code a lot of cases for every call I made. I was just looking to call a sub which name is in a variable. I think it best to wait for the next release, but it's a nice discussion anayway!

Scub
 

Scubaticus

Active Member
Licensed User
form's Show method
I my case I not aways have a .show. When adding a record i.e. I just clear out fields, set some defaults and return to the screen which was already there.

I also thought the .show would be a solution (it's nice to see we all do things the same way :).

Now I'm using the select case method, coding out every sub I want to call. It's safe, but does not fit in my template the way I want it.

We'll just wait for the real Call (var) in the next release.

Scub
 

Scubaticus

Active Member
Licensed User
You're code is like playing with fire ;)
I'm always looking for boundaries ;)

Next version will include a simple CallSub(String) method.
I know, but I was looking for a temporary way doing the same in the meantime, but the fire is getting to hot.

Scub
 
Top