Android Question Referencing controls from modules

Hi guys, i am using return to return data from code modules and then updating it in the activity at most places... But at some instances it becomes very difficult as the amount of things to be updated are very much and passing them across makes things unduly complicated.. Is there any way to call controls from the modules itself (like we used Form1.Label1.caption in Visual basic)
Any other better method of working this around will also be appreciated
 

Albert Kallal

Active Member
Licensed User
Ok, I'll bite!

Keep in mind, that I am relative new. But, I come from a strong VB, VBA, and vb.net background.

So, my ideas, and points of view are "from" that campground, and thus here is some ideas:

So, several approaches.

First, what you can do is create a “map” object of the fields you want to edit/use in that “general” sub.

Let’s pretend we want to:

Pass a routine same some kind of primary key id. Pull some values from a sql table, and then set these values to some text boxes in our current view (or should I call it our form being from vb land???).

Ok, in most cases, I would try and return the values, or build some kind of “structure”. Pass that to the routine, get it back, and then we have free use of our control(s) on the current form/view + activity.

But, for now, let’s assume we have a standard sub (not in our current activity module), and we want to modify some fields (edit text boxes) for us.

So, one great way is to use a “map”. This is really just like the vb collection object. You can add to the list, and pluck things out based on a key value. Really nice feature of B4A.

This code is not “too bad” for say 5 or so controls/text boxes.

So, we in our activity code will load up a map (a collection) of controls, and pass that to the “general” routine.

Say this code on a button click:
B4X:
     Dim MyFields As Map
     MyFields.Initialize

     MyFields.Put("txtHotelName",txtHotelName)
     MyFields.Put("txtCity",txtCity)
     MyFields.Put("txtProvince",txtProvince)
     MyFields.Put("txtNotes",txtNotes)

     General.LoadData(txtID.Text, MyFields)

So, in above, to be fair, we did have to know ahead of time the controls we going to “work” on in the sub routine.
And we do have that "setup" code to the collection (map).

However, the above is not all that bad for a “few” controls, and we certainly not loading up a truckload of parameters to the sub – so this is a really great way to pass a set of values back and forth, or have the sub operate on what we passed.

The sub in that standard “general” code module? It looks like this:
B4X:
Sub LoadData(ID As Int, cFields As Map)

     ' load data based on passed ID
     ' code (say sql to load data)  - air code part!!!

     ' now set controls

     MyControl("txtHotelName",cFields).Text = "My hotel name"
     MyControl("txtCity",cFields).Text = "My City"
     MyControl("txtProvince",cFields).Text = "My Provance"
     MyControl("txtNotes",cFields).Text = "My comments and notes"

End Sub


Sub MyControl(strName As String, f As Map)  As EditText

     Return f.Get(strName)

End Sub

So, see now we don't have to pass the values back and forth = we are updating the controls on the activity that called this routine.

Note the little “helper” routine. (MyControl). I used that, else I would have to declare a “editText” type var. “get” from map into that edittext var, and THEN then go SomeVar.Text = “ my text”. (that is too much code for me!!! – no way!!!).

And if someone reading this? Is it possible to do this ???
B4X:
cFields.Get("MyKeyAsString").Text = "my text for control"
(so, can I eliminate my helper function MyControl ???).

So, the above is not too bad – I say not too bad for a few controls. Certainly better than passing say 5 parameters, or even 10!!

However, even better then above for lots of controls?

In the view (forms) designer? Just make up a coding standard out of thin air in which you assume the “tag” value for each control is name of the control (or the name of the data you want to modify).

And even better you could set/make the “tag” value to say mean the column from the database? (I do this in asp.net all the time (I use “f” as my own made up attribute for asp.net controls in the mark-up).

This approach would thus eliminate all that code to fill up the map, and we can now DUMP the map, and PASS the current activity to the routine.
(and there is just oh so many examples here for B4A that use the tag - so think "tags" when trying to reference controls.

So, now no map code, and we have just one line for the call like this:
B4X:
     General.LoadData2(txtID.Text, Activity)

So, note now how we passing the Activity to the “general” code module, and it can thus now get/grab/use or do quite much anything to the view we passed. (but the controls collection is not clean like in vb land).

Our general code now becomes this:
B4X:
Sub LoadData2(ID As Int, a As Activity)

         Log(ID)    ' again - some air code here to load say data based on "ID"

            MyControl2("HotelName",a).Text = "My hotel name"
            MyControl2("City",a).Text = "My City"
            MyControl2("Provance",a).Text = "My Provance"
            MyControl2("Notes",a).Text = "my comments and notes"
       
End Sub

Sub MyControl2(strF As String, a As Activity) As EditText

     For i = 0 To a.NumberOfViews - 1
        If a.GetView(i).Tag = strF Then

            Return a.GetView(i)

         End If
      Next

End Sub

So, now no hard coded “map” collection to pass. No map collection to create!

So, if we have 3, or 20 controls/values? We just pass the “activity” to the routine, and then work on the controls we need/want based on the “tag”. So YOU have to set the tag in the view designer - the reason is we can’t get at the control names (I suspect this is the VERY reason for you asking your question!!!!).

And our “general” sub that could in theory be used/called from different views/activities.

However, last but not least? Another approach to not pass all that stuff back and forth? The answer is don’t!

One way would be to “keep” the code in activity, and create our “general” code routines as a class. In this case, we thus don’t pass a whole bunch of values back and forth, but use a class (object). So, we can have standard code in that class, but we run/use/call the code local to our activity code.

So, data values, and code is in a class object. (they work really much the same a VB6/VBA classes. And in fact they work like vb.net one also! (but no overloading and inheritance like we have in vb.net).

So, our code becomes this:

B4X:
     Dim clsTestCode As MyClassTest

     clsTestCode.LoadData(txtID.Text) ' load up our data

     txtHotelName.Text = clsTestCode.HotelName
     txtCity.Text = clsTestCode.City
     txtProvince.Text = clsTestCode.Province
     txtNotes.Text = clsTestCode.Notes

So, we work the problem kind of up-side down. We have some routines in that “class”, but all kinds of lists, maps, and truckloads of values are now simply public members of the class, and we use the values “johnny on the spot”, and thus don’t really pass a whole lot of things to the class. So, we keep the code that mods values for controls in the current activity

The class module code is thus like this:
B4X:
Sub Class_Globals


     Public HotelName        As String
     Public City             As String
     Public Province         As String
     Public Notes            As String

End Sub

'Initializes the object. You can add parameters to this method if needed.

Public Sub Initialize
End Sub

Public Sub LoadData(ID As Int)

      ' air code here to load data - maybe sql to sqlite data

     HotelName     = "My Hotel Name"
     City          = "My City"
     Province = "My Province"
     Notes         = "My comments and notes"

End Sub
And I might get “some” flack for using public members, but really even in vb.net, save your fingers and ignore everyone using the get/set code blocks to set a member. (variable) of the class. Just make them public!!! save that coding time!!!

And note even for that class example? We could consider to pass the activity to that class. And thus have it set/modify the controls rather much the “same” as what we did when we passed the activity to the “general” standard (non class) code module. (the 2nd example).

I think in most cases? I would tend towards passing a “map” for many values. Thus you don’t care much if you need 2, or 80 values.

And if you must? You can pass the activity and we quite close to what we often did in .net land or say Access/VBA (we pass a form reference). So you can then work the controls in the sub routines. (but you have to adopt that “tag” approach to mean the name of the control(s) and reference them that way. (or think of the tag as the data column name).

Of course in my example the form controls where ALL “editText” controls, so I am cheating somewhat here! (I made this look easy!!!).

If you have say check box, toggle switch etc.? Well, then the above simple clean code is not so clean anymore.

I still relative new to B4A, but you might be able to “cast” the type, and thus cook up a referencing approach that works for check boxes etc. and not just on “one” type.

But, then again, if you use a map, you can stuff in edittext, or any kind of control(s) into that map collection and pass that. Just remember to pluck out the type into a control type declared in that routine, and then set the values.

And your “general” code has to correctly set/get/use/grab values for a check box or whatever control – and they are all a bit different, so you code would be a bit different always.

There is a “gem stone” of a routine that you can see/lift/grab/pirate for some really nice code that “walks” the controls on a form.

The nice kit of code is called:
StateManager.

This one:

https://www.b4x.com/android/forum/t...android-applications-settings-and-state.9777/

HIGH recommend above!

I been using the above for some forms. It is REALLY nice, since you JUST call the routine, and it will automatic save the state of all controls on a form out to a file. (I missed that feature big time!!!). I thought state manager was to allow you to save some values like a “.ini” file. So, it does allow this, and it follows the “map” like idea.

However, it ALSO has a feature to do the most cool thing on the planet!

If you have a form with text boxes and all kinds of stuff? You call the routine, and it will automatic save ALL OF the controls and values for you! (about 1 line of code!!!).

It is just ONE simple call, and it does all the cooking, baking, serving and even pours you a glass of wine.

And the code looks to be about 9 years old – and still going strong!!!

That code is a VERY valuable example since it shows how to walk/traverse the forms (view) controls collection, determine the control type.

If B4A supported over-loading, then my helper function could return any typed control. Perhaps one does not require nor need to return edit text, and can return a type of object. Just not had the time to test and play here.

(if I had time, I would ask this/that question: Can we return a different control type from a routine? (and of course use the properties/methods of that retuned type?).

So, I hope the above helps.
I am in a similar boat – leaning thing that JUST get me by for the next task at hand.

I can write code B4A now – so that’s what I am doing. I wish I had more time to learn, but I have to get some things done. So, I am no doubt doing a number of things in a “less” than ideal approach.

So, I do want to point out that the above ideas are the result of what I call survival mode – have to get things done.

I do hope it does give you some ideas however.

I been meaning to try out and learn to use the dialogs library (it has a designer approach and data bound ability to write/save data to sqlite – and does this FOR YOU! That means you not having to write a bunch of code that over and over does the same thing (that is pull data from a screen layout – and save it to a table).

However, the sate manager code above is ALSO a fantastic starting point for a read/write system for forms to save data to sqlLite.

I as noted am too pressed for time to learn something to save more time! (so, I am likely to lift some code from the state manager and use that to auto-matic write out data to sql server). It either that, or go off and learn that dialogs library stuff!

Anyway, I hope the above 2-3 ideas will give you some helpful ideas.

Regards,
Albert D. Kallal
Edmonton, Alberta Canada
 
Last edited:
Upvote 0
Top