Custom types (Structures)

Discussion in 'Teaching Programming with B4X' started by HotShoe, Sep 6, 2015.

  1. HotShoe

    HotShoe Well-Known Member Licensed User

    A Structure is an organized group of information that defines a specific data set. There are many types of structures available in B4X, including Classes, database records, Maps, and custom types. In this lesson we will focus mainly on the custom type.

    Delphi users will recognize the custom type as a Record, and C/C++ users will recognize them as a Struct{}, and Java folks likely see them as a Data Class. In fact all of these are Class objects in each of those languages.

    B4X simply allows the developer to create a custom Class to hold similar or different variable types inside it. Consider these Type definitions in B4A:

    Code:
    Type cfgrec(filefg, filebg, markfg, markbg, dircolor, linkcolor, markedcolor, infolblbg, infolblfg As Int, startdir As String, hidden As Boolean)

    Type filelist(perms, owner, group As String, size As Long date, time, name As String)

    Dim crec As cfgrec
    Dim files As filelist
    These are used in my File manager app. The first word in a custom type declaration is the keyword Type followed by the name of the class you are defining, and then all of the declarations for the variable names and types inside of that new data type or class inside the surrounding parenthesis ().

    Code:
    Type cfgrec(filefg, filebg, markfg, markbg, dircolor, linkcolor, markedcolor, infolblbg, infolblfg As Int, startdir As String, hidden As Boolean)
    SO, cfgrec is the name of the new data type we want to create, and inside of that data type it contains 9 integers to store color values used for the different parts of the user interface. Next it stores a string that is the directory to start in each time the app runs, and then a boolean to tell the app whether or not to show hidden files.

    All of that is used as a configuration record for the app and it is then stored in the apps DirInternal directory, which is protected. You MUST create a variable of the custom type before you can use that new Type:

    Code:
    Dim crec As cfgrec
    When the app first runs, the config file is opened and read in the getcfg sub:

    Code:
    Sub getcfg

    Dim cfile As RandomAccessFile

    cfile.Initialize(
    File.DirInternal, "ADT.cfg"False)

    Try
    crec = cfile.ReadObject(
    0)

    Catch
    crec.dircolor = 
    Colors.Yellow
    crec.filebg = 
    Colors.Black
    crec.filefg = 
    Colors.White
    crec.linkcolor = 
    Colors.Green
    crec.markbg = 
    Colors.Yellow
    crec.markedcolor = 
    Colors.Magenta
    crec.markfg = 
    Colors.Black
    crec.startdir = curdir
    crec.infolblbg = 
    Colors.White
    crec.infolblfg = 
    Colors.Black
    crec.hidden = 
    False

    savecfg
    End Try

    cfile.Close

    End Sub
    The sub routine above opens the confg file and reads its contents into the crec variable which is defined as our custom type cfgrec in Process_Globals. If the file does not exist or if there is another error, the catch clause of the Try/Catch executes and assigns default values to each member of out custom type and then saves that by calling the savecfg sub below.

    Code:
    Sub savecfg
    Dim cfile As RandomAccessFile

    cfile.Initialize(
    File.DirInternal, "ADT.cfg"False)

    cfile.WriteObject(crec, 
    False0)
    cfile.Close

    End Sub
    Savecfg is called whenever something in our cfgrec custom type variable changes, like when the user selects a new color combination. Notice that we use the RandomAccessFile object to read and write the cfgrec and we only use position 0 of the file since we are only storing 1 record. Also note that cfile is not declared globally. That is because these 2 subs are the only methods that ever access the config file, and a global variable would use unneeded memory.

    The code fragment below is not complete, but it is also lifted from the file manager app. It demonstrates how the elements of the Filelist type can be used. Since we declared these in the Process_Globals of the main activity, these types are available anywhere in the app. For large or complex apps, I create a code module and declare my global structures in there along with any custom sub routines to handle things globally instead, just for convenience.

    Code:
    Dim tmp1 as String

    If tlst.IsInitialized Then

    For i = 0 To tlst.Size - 1
    tmp1 = tlst.get(i)

    files.perms = WordNum(tmp1, 
    1'WordNum and PosWord are found in the Mlstrings library
    files.owner = WordNum(tmp1, 2)
    files.group = WordNum(tmp1, 
    3)
    files.size = WordNum(tmp1, 
    4)
    files.date = WordNum(tmp1, 
    5)
    files.time = WordNum(tmp1, 
    6)

    tmp = WordNum(tmp1, 
    7)

    gi = PosWrd(tmp1,
    7)
    gi2 = tmp1.Length
    st = tmp1.SubString2(gi,gi2)

    files.name = st

    flist.Add(files)
    Next

    End If
    In the example above, tlist is a simple list that we read a list of files into. The way the list was read (using the Mlfiles library) returns a list of strings containing information about each file separated by comas. Flist which is just before the Next in the For loop is another list, but it contains a list of our custom type named files.

    Assigning to or reading from Type variables is really simple. You must specify the Type name and then the element that you want to read or change separated by a dot like this:

    files.name = “somefilename.txt”

    or

    txt = files.name

    So, files.name tells the underlying logic of B4X that we want to use the object named files and access the variable inside of it named name and assign it the string “somefilename.txt”, or read its value into the string txt.


    Sorting Custom Types (Added 09-16-2015)

    A very handy feature of Lists in B4X is that they support the sorting of custom types on any field. For example :

    flist.SortType("date", True)
    flist.SortTypeCaseInsensitive("name", True)

    These two methods are built-in to Lists and make sorting a group of records easy. Both take the same arguments, the NAME of the field inside of the custom type, and whether the sort is in ascending order or not. The SortType method sorts taking capitalization into account, and the SortTypeCaseInsensitive ignores the case of each letter.

    In the examples above, the first sorts the file list flist by date and the second sorts it by name (filename). We just have to tell each method the name of the field to sort by as a string or string variable. :

    Code:
    Sub sortname_CheckedChange(Checked As Boolean)
       
    If sortname.Checked Then
       sorttype.Checked = 
    False
       sortsize.Checked = 
    False
       sortdate.Checked = 
    False
       
       sortfield = 
    "name"
       
    End If
       
    End Sub

    Sub sortdate_CheckedChange(Checked As Boolean)

       
    If sortdate.Checked Then
       sortname.Checked = 
    False
       sortsize.Checked = 
    False
       sorttype.Checked = 
    False
       
       sortfield = 
    "date"
       
    End If
       
    End Sub
    Sortname, sortdate, sortsize, and sorttype above are check boxes that the user can select in the display options, and sortfield is a string variable that is assigned the field name to sort by.

    Code:
    flist.SortTypeCaseInsensitive(sortfield, True)

    Summary

    Custom types don't replace regular variables that you commonly use in an app, and they are not meant to. The real power of these structures is to keep information grouped into a single location that is easy to get to in your app. You can define as many Types as you need in an app. The file manager uses 6 custom Types for various purposes, but the most important is the configuration information (crec for configuration record) and all information about each file as a list of type files (held in the globally defined list flist).

    In summary, You can use custom types for a whole array of things to keep information grouped into easy to access clumps of data. I find that the more specific the type is when it is defined, the better custom Types work. Custom types are very useful for reading and writing data to and from databases as well, and I think they tend to make code more readable.

    This is the standard disclaimer stating that this lesson is meant to show some of the possibilities using the custom types in B4X. It is in no way the only way to use types, or the only way to achieve a given result. No animals were harmed in the writing of this lesson, but some bits may have been broken.

    --- Jem
     
    Last edited: Sep 16, 2015
    BPak, Ferbis, Peter Simpson and 14 others like this.
  2. WAZUMBi

    WAZUMBi Well-Known Member Licensed User

    :D
     
  3. HotShoe

    HotShoe Well-Known Member Licensed User

    I wanted to see if anyone was paying attention. :)
     
  4. Cableguy

    Cableguy Expert Licensed User

    I am, and loving it!

    May I suggest 2 tutos?
    - ShortCircuit
    -try catch
     
  5. HotShoe

    HotShoe Well-Known Member Licensed User

    Peter Simpson and inakigarm like this.
  6. HotShoe

    HotShoe Well-Known Member Licensed User

    Updated 09-16-15.

    I forgot to add one of the most powerful features of Types. the SortType methods of a List.
     
    BPak, Erel and DonManfred like this.
  7. Erel

    Erel Administrator Staff Member Licensed User

    Another nice feature of Types is that you can serialize types instances to bytes with RandomAccessFile.WriteObject / WriteB4XObject.

    So instead of saving all the values in a text file and then parsing the text file you can create a List with types and save this list with a single line of code. Later you can of course read it with ReadObject or ReadB4XObject.
     
    lemonisdead, BPak and DonManfred like this.
  8. HotShoe

    HotShoe Well-Known Member Licensed User

    Exactly why I use them so often and why I included my getcfg and savecfg subs in the examples. I am always finding uses for custom types.

    --- Jem
     
    BPak, rwblinn and Erel like this.
  9. LucaMs

    LucaMs Expert Licensed User

    Too few people use Classes.
    I think that a thread dedicated to Classes can be helpful.

    Too bad I'm too lazy to write it :D
     
  10. klaus

    klaus Expert Licensed User

    There is a whole chapter about Classes in the B4A Users Guide, 33 pages with examples and source code.
     
    lemonisdead and Erel like this.
  11. LucaMs

    LucaMs Expert Licensed User

    As you know, few people read the Guide (unfortunately); also, this is a "special forum", which could help to understand Classes better.
     
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice