Android Question New user learning - any guidance please?

SparkOut

Member
Hi there, new user here, I just discovered B4X a few weeks ago thanks to a comment made in a different forum related to LiveCode.
I'm not a programmer, so the LiveCode "English-like" syntax has been my way into getting apps and tools made, sometimes for hobbying, sometimes for doing something bespoke (but relatively small scale) to help for work. These days I don't have the same requirements and haven't actually even opened the LiveCode IDE more than a couple of times this year, so I'm finding the idea of paying another year of subscription is hard to justify. Hence the discovery of B4X was very interesting, although I've not got any problems with LiveCode.

So I spent a couple of weeks watching all Erel's videos and finding a lot of useful info and then at the weekend, for the experience, I started to try converting an old app I had made many years ago (for desktop and Android) to solve "Alphactor" puzzles (where values are attributed to letters and then a word's total value is shown, with a total sum of the word list values).

I quickly found that there is a big shift needed in understanding the anatomy of a project. A LOT of what I am going to relate will sound like complaints, and maybe some of them are, but it's not my intention to tear down B4X - I really want to get used to working in it and I do see a lot of value here, and really appreciate the efforts of Erel and everyone in the community. I do NOT want to be saying "you should do it like this" - mentioning some of my pain points will hopefully help people to show me where I can translate from LiveCode mindset - I need to learn and understand, and maybe give a few hints where there could be some better handholding for new users.

I quickly found that although there is a LOT of information in the forum here, it's VERY unclear how much of it is relevant and useful today. There really needs to be some bigger signposts for the walkthrough of getting a new user onboarded. I spent a lot of time digging through results of searches that mostly seemed to be over 10 years old, and of course in some cases the language hasn't changed, and in many it has been updated (B4X & Xui).

Persevering with the project, I quickly got a layout built. OK, the designer is limited. Even for a static display, there's no way to select a group of views and align them, match sizes or distribution. So I tried the Designer Script, and worked with that. Which is great, but then it doesn't update the WYSIWYG view, and doesn't do loops, and here's one of the big paradigm shifts to get my head around - you can't programmatically create a view name and have that automatically cast to the view object reference. At least as far as I can tell. Designer script OK, I'm happy with the layout.

So to begin the puzzle solving process, I take the fldWords.text value and do some very rudimentary error trapping to set all upper case, remove spaces and blank lines
B4X:
Sub TrimAndFix(pText As String) As String
    pText = pText.ToUpperCase
    Do While pText.Contains(CRLF & CRLF)
        pText = pText.Replace(CRLF & CRLF,CRLF)
    Loop
    pText = pText.Replace(" ","")
    Return pText
End Sub
It was easy enough to obtain the text, and put back into the view after correcting, then compare the number of words to the number of the values (I'll do more error trapping in due course).

In the logic of the app, there is quite a heavy use of a dynamic multidimensional matrix containing the values for each letter which are traversed, recalculated, pivoted with other items in different rows, set and updated as the solution algorithm processes it. In LiveCode it's very simple to address any element indexed by any number of dimensions, in a variety of containers. In the case of the app to port, the data is in a simple string variable and elements are referred to directly and can get and set "item i of line l of sMatrix". I translated this to B4X by declaring Private sMatrix as List in the Class_Globals sub. To populate the original data rows, I iterated through the words list and declared and initialized a new List, did the letter counts and then sMatrixLine.Add(Count). Once each word's letter count had been fully populated, using sMatrix.Add(sMatrixLine) built up the matrix data as a List of Lists. So far so good.

But how do I access individual elements of the big matrix? For the outer loop to iterate through the lines of counts it is simple but how to take a value at a given index of each of those lines, without being able to address a list with a multidimenisional index? I don't know whether there's a "better/more concise/more approved/more elegant/more efficient" way than
B4X:
For tLine = 0 To sMatrix.Size - 1
   Dim sMatrixLine As List
   sMatrixLine.Initialize
   sMatrixLine = sMatrix.Get(tLine)
   For tLoop = 0 to sMatrixLine.Size -1
      'work on each element in the matrix and process accordingly
   Next
Next
The processing involves a lot of comparison of data in other indexed rows of the matrix and transposition of different values after performing operations on them. I'm uncertain of the best way to do this without continually creating temporary Lists, accessing an index of it, and then taking a whole row from the master sMatrix, updating an element in that and then replacing the whole row back into sMatrix.

So anyway, after working out at least "this" way of manipulating the data, I was left with a master matrix that showed the same data as the original LiveCode app. Great! Job done, sort of. Let's take the data and display the solution with each letter view having the value inserted. OK... how do I iterate through the matrix and put the relevant value into the relevant view? The view names I have set as "fldA", "fldB" etc but could just as easily be alphanumeric "fld0" for A, "fld1" for B etc. But I can see no way to take the value for letter A and do something like
B4X:
("fld" & Loop).Text = Answer
I found on the forum a suggestion to make a map of objects keyed by tag name at the start of the app with
B4X:
    For Each v As B4XView In sResultFlds
        mFields.Put(v.Tag, v)
    Next
and then retrieve the object by tag with
B4X:
Sub GetView(viewRef As String) As B4XView
    Dim v As B4XView
    v = mFields.Get(viewRef)
    Return v
End Sub
That works but I'm not really very clear about what is being done in the map - I'm a bit uneasy that I'm creating new objects that clutter up the app, or is it passing the view by reference? I think I get that in the GetView sub each view reference is created, returned and destroyed but then how does the returned object refer to the view if it's already destroyed?

Now I think I've got a working app, trying it out on my phone it works with the prebuilt default list of words and values. But that's not going to work for people to put in their own puzzles for solving. So I need to allow editing of the words and values and in the designer the values view has been set with a keyboard type of Numbers. Trying to edit the column of number values proves a problem though, although the keyboard shows a CR key, it has no effect in the view. Pasting a column of values from elsewhere also then strips out the CRs and gives a long string of numbers in the top line. How do I deal with this?

How do I edit the app title and icon in the titlebar? In the layout designer under Main Properties I have changed the Form Title. I have named the layout differently and used the new name in the LoadLayout call of the B4XMainPage Private Sub. The Form Title set in the designer seems to have no effect, and the icon option shows and empty set of choices and can't edit/paste anything in there.

So I hope I sound like I mean to, that is "encouraged but somewhat daunted, and frustrated by blundering around without signposts" - at least ones that I can be sure are pointing the right way and not to the old ghost town.

Any help for a new user to get to grips with the concepts involved?
 

SparkOut

Member
Screenshots of the B4J version, although I'm also creating the app for Android. I can't see how to change the title.
1762611251861.png

B4X:
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    Root.LoadLayout("AlphactorSolver")
    sMatrix.Initialize
End Sub
1762611105894.png

1762611133154.png
 
Upvote 0

SparkOut

Member
Aha, for the title, I have since discovered I can put
B4X:
B4XPages.SetTitle(Me,"Alphactor Solver")
in the B4XPage_Created Sub. In B4A I have edited the manifest with the icon data and put the required icon files in the relevant folders, all seems to be OK with that now. It's definitely not intuitive though, and a bit disconcerting that the Designer has properties for title etc that don't apparently relate to this at all.
 
Upvote 0

walt61

Well-Known Member
Licensed User
Longtime User
Welcome to B4X, @SparkOut ; below some (hopefully useful) hints. If you didn't already, you may also want to have a look at @klaus 's booklets - see the first link on https://www.b4x.com/android/documentation.html

But how do I access individual elements of the big matrix?
sMatrixLine is an Object. Therefore, if you change a value in that list, it is changed in the parent list (sMatrix) as well (an object is always accessed by reference [pointers], not by value).
B4X:
Dim oneItem As String = sMatrixLine.Get(i) ' Get the item at index 'i'
sMatrixLine.Set(i, "Something new") ' Set the item at index 'i' to string "Something new"; instead of a string, any object can be used as well ('oneItem' must then be properly declared too)
Dim theSameLine As List = sMatrixLine ' theSameLine is now the same object as sMatrixLine
theSameLine.Set(i, "Something even newer") ' This change happens in sMatrixLine (and sMatrix), as we're working with objects

I'm not really very clear about what is being done in the map
When you store objects in a map, they are indeed passed by reference (a pointer), e.g.:
B4X:
Dim myMap As Map
myMap.Initialize
Dim lbl As Label
myMap.Put("label1", lbl)
Dim lbl2 As Label = myMap.Get("label1") ' lbl2 points to the same object as lbl; changes made to lbl2 are actually made to lbl; the object is not destroyed as long as you stay within its scope, e.g. myMap could be declared globally, while lbl2 could be declared in a Sub

How do I edit the app title and icon in the titlebar?
If the app is a B4XPages one (recommended), set the title with:
B4X:
 B4XPages.SetTitle(thePage, "The title") ' Use the proper value for 'thePage'
If not - not recommended, especially as you work cross-platform:
B4X:
Activity.Title = "My title" ' B4A
MainForm.Title = "My title" ' B4J

How do I set the form icon in Designer?
Click the 'Files' tab in the Designer (underneath the left hand pane), then 'Add Files', and add the icon's file there. Then, you'll be able to assign it to the Form.

Hope this helps!
 
Upvote 0

SparkOut

Member
Welcome to B4X, @SparkOut ; below some (hopefully useful) hints. If you didn't already, you may also want to have a look at @klaus 's booklets - see the first link on https://www.b4x.com/android/documentation.html
Thanks very much @walt61 .
I have indeed already read much of the booklet contents, some has been helpful, but with lacking experience, some has been a case of waiting for enlightenment. I'm not expecting to build Rome in a day, but I do want to feel like I'm getting somewhere. With perseverence, I will.

sMatrixLine is an Object. Therefore, if you change a value in that list, it is changed in the parent list (sMatrix) as well (an object is always accessed by reference [pointers], not by value).
B4X:
Dim oneItem As String = sMatrixLine.Get(i) ' Get the item at index 'i'
sMatrixLine.Set(i, "Something new") ' Set the item at index 'i' to string "Something new"; instead of a string, any object can be used as well ('oneItem' must then be properly declared too)
Dim theSameLine As List = sMatrixLine ' theSameLine is now the same object as sMatrixLine
theSameLine.Set(i, "Something even newer") ' This change happens in sMatrixLine (and sMatrix), as we're working with objects
OK, so if the penny has correctly dropped, then this is gold. So I don't have to take the (second dimension) List in sMatrix index line, iterate through that line as a copy, and then set that line back into the parent List. Because I've created a *reference* to an index of sMatrix with Dim sMatrixLine = sMatrixLine = sMatrix.Get(i) then any update of an element in sMatrixLine is reflected in sMatrix, right? I'm not creating new variable *content* in a copy, I'm creating a new *pointer* to the original "live" content.

When you store objects in a map, they are indeed passed by reference (a pointer), e.g.:
B4X:
Dim myMap As Map
myMap.Initialize
Dim lbl As Label
myMap.Put("label1", lbl)
Dim lbl2 As Label = myMap.Get("label1") ' lbl2 points to the same object as lbl; changes made to lbl2 are actually made to lbl; the object is not destroyed as long as you stay within its scope, e.g. myMap could be declared globally, while lbl2 could be declared in a Sub
I hope I've understood a little clearer now and see what it's doing. This creation of a map of views that I can then use to programmatically work on interactive views to set the text, or layout or style is something that is going to become my first go to Sub in any project. I'm surprised there's nothing like that already built in. How do most people refer to a view to be able to work on it without hard-coding everything?

If the app is a B4XPages one (recommended), set the title with:
B4X:
 B4XPages.SetTitle(thePage, "The title") ' Use the proper value for 'thePage'
If not - not recommended, especially as you work cross-platform:
B4X:
Activity.Title = "My title" ' B4A
MainForm.Title = "My title" ' B4J
Thanks, yes. I did discover that already, and made a post but as I'm a new forum user, it's still awaiting moderation, so you'll see it weirdly appear and seemingly unthank you, sorry.

Click the 'Files' tab in the Designer (underneath the left hand pane), then 'Add Files', and add the icon's file there. Then, you'll be able to assign it to the Form.

Hope this helps!
Thanks again, it definitely helps, a lot.
 
Upvote 0

walt61

Well-Known Member
Licensed User
Longtime User
Because I've created a *reference* to an index of sMatrix with Dim sMatrixLine = sMatrixLine = sMatrix.Get(i) then any update of an element in sMatrixLine is reflected in sMatrix, right? I'm not creating new variable *content* in a copy, I'm creating a new *pointer* to the original "live" content.
That's correct.

How do most people refer to a view to be able to work on it without hard-coding everything?
When (like in your case) using a number of similar views, a CustomListView can avoid hard-coding: https://www.b4x.com/android/forum/t...listview-cross-platform-customlistview.84501/
 
Upvote 0

klaus

Expert
Licensed User
Longtime User
To do this:
("fld" & Loop).Text = Answer

You can use an array of views like this:
In Class_Globals declare the views:
B4X:
Private fld(), fld0, fld1, fld2, fld3 As B4XView
The first one is the array and the next ones are the individual views you have created in the Designer.
And in B4XPage_Created define the array:
B4X:
fld = Array As B4XView(fld0, fld1, fld2, fld3)
Then you can access each view with its index like:
fld2 with fld(2)
And also:
B4X:
    For i = 0 To fld.Length - 1
        fld(i).Text = Something
    Next

You are speaking of multidimensional matrices.
Multidimensional matrices do exist in B4X like.
B4X:
    Private MyMatrix(10, 10) As Int
    For i = 0 To 9
        For j = 0 To 9
            MyMatrix(i, j) = Rnd(0, 101)
        Next
    Next
This fills the matrix with random numbers between 0 and 100.
The declaration Private MyMatrix(10, 10) As Int should be in Class_Globals.
The content of the matrix can be any kind of variable type, even views like in the other example above.
 
Upvote 0

SparkOut

Member
Thanks @klaus

I see how the array of views can work, I will experiment and see how it compares to the map. For simple numerically indexed views it makes a lot of sense to use the array, but I must admit I like the idea of getting a view by reference to map to retrieve the object via the tag, or other identification.

I made sMatrix a List of Lists, as I was led to believe arrays are essentially fixed size, or else somewhat troublesome to resize. I need to have a flexible number of rows in the matrix according to the number of words in the puzzle. So a List of Lists seems to be a suitable choice. Defining a variable as a pointer to the object to work on each iteration makes sense now. It's exactly this paradigm shift I was hoping to get help with. Thank you..
 
Upvote 0
Top