Android Question Undeclared variable

Rob White

Member
Licensed User
I am not sure the above describes my problem!
I have two _click event handlers.

B4X:
Private Sub butLoad_Click
    Main.po.NuRecord = False
    Select Main.po.Operations.Get(Main.po.CurrOp)
        Case "SowPage"
            B4XPages.ShowPage("NotImpPage")

    End Select  
   
    B4XPages.ShowPage(Main.po.Operations.Get(Main.po.CurrOp))
End Sub

and

B4X:
Private Sub butLastOp4Pad_Click
    Main.po.NuRecord = False
    Select Main.po.Operations.Get(Main.po.CurrOp)
        Case "SowPage"
            Dim qStr As String = $"Select Max(OpDate) As OpDate, ID, PadID, PlannedSeedRate,
                PlannedFertRate, SeedTypeId, SeedCultivarID, MeteredRateSeed, MeteredRateFert,
                AreaSown, FertTypeId, Comment, Depth FROM SowingData WHERE PadID = ${Main.po.SowData.Get("PadID")}"$
            ' Above query string returns only one record (list item)
            Dim l As List = DBUtils.ExecuteListOfMaps(Main.po.SQL1,qStr)
            Main.po.SowData = l.Get(0)
            Log($"SowData loaded For PadID = ${Main.po.SowData.Get("PadID")}"$)
            Utils.LogSowData
    End Select
    B4XPages.ShowPage(Main.po.Operations.Get(Main.po.CurrOp))

In butLoad_Click there are no errors BUT in the other :-

B4XMainPage - 160: Syntax error.
B4XMainPage - 159: Unknown member: po
B4XMainPage - 158: Unknown member: po

Line 160 is CASE "SowPage"

PO is defined in main with following code

B4X:
Sub Globals
    Public PO As PadObs
End Sub

Sub Activity_Create(FirstTime As Boolean)
    PO.Initialize(Activity)
    Activity.Title = "Paddock observations"
End Sub

I know images are not advised but I can not help myself, this makes in more clear.
ScreenDump.png
 

Rob White

Member
Licensed User
I am obviously not on top of variable/object scope in B4X.
Is there a document some where which may help me understand this?

The comments in Main Process_Globals says
'These global variables will be declared once when the application starts.
'These variables can be accessed from all modules.
Does "all modules" mean code modules or includes classes?
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Don't confuse Activity Globals with Activity Process_Globals.

Truth is that these differences are not important and you shouldn't bother with them as B4XPages simplifies many things. Just put the variables in the pages classes. Don't use Main.

It is explained in the B4A lifecycle video tutorial: https://www.b4x.com/etp.html and in the programming guides: https://www.b4x.com/android/documentation.html
 
Upvote 0

Rob White

Member
Licensed User
Hi all,
I have read "B4X Basic language" booklet page 21 and set up the attached project.
I have declared one public variable

B4X:
Sub Class_Globals
    Private Root As B4XView 'ignore
    Private xui As XUI 'ignore
    
    
End Sub

Sub Process_Globals
    Public MyAge As Int = 69
    
End Sub

'You can add more parameters here.
Public Sub Initialize As Object
    
    Return Me
        
End Sub

'This event will be called once, before the page becomes visible.
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    'load the layout to Root
    
End Sub

'You can see the list of page related events in the B4XPagesManager object. The event name is B4XPage.

when I reference this global variable from anotherPage :-

B4X:
Sub Class_Globals
    Private Root As B4XView 'ignore
    Private xui As XUI 'ignore
End Sub

'You can add more parameters here.
Public Sub Initialize As Object
    Return Me
End Sub

'This event will be called once, before the page becomes visible.
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    'load the layout to Root
    
End Sub

Private Sub getAge
    Dim age As Int = myModule.myage
End Sub

'You can see the list of page related events in the B4XPagesManager object. The event name is B4XPage.

I get a red squiggly line (
codeModule - 7: Undeclared variable 'mymodule' is used before it was assigned any value.
stdClass - 11: Undeclared variable 'mymodule' is used before it was assigned any value.
AnotherPage - 19: Undeclared variable 'mymodule' is used before it was assigned any value.
MyModule - 9: Unused variable 'MyAge'. (warning #9)
AnotherPage - 18: Sub 'getAge' is not used. (warning #12)
stdClass - 10: Sub 'getAge' is not used. (warning #12)
codeModule - 6: Sub 'getAge' is not used. (warning #12)

) and a compile fails

B4J Version: 8.90
Parsing code. Error
Error parsing program.
Error description: Undeclared variable 'mymodule' is used before it was assigned any value.
Error occurred on line: 19 (AnotherPage)
Dim age As Int = myModule.myage

Attached is the complete project.

Where am I going so wrong?
 

Attachments

  • TestScope.zip
    4.3 KB · Views: 111
Upvote 0

William Lancee

Well-Known Member
Licensed User
Longtime User
I hate to say this, but you need to look at how B4Xpages work. I looked at your code, and it is isn't close to what it should be.

My advice is to search for B4Xpages and download an example, unzip it and study it. Even if this is unwelcome advice.
 
Upvote 0

Rob White

Member
Licensed User
Point taken, I never attempted to create a B4X application. My only aim was as simple as possible example to explore the scoping.

So taking the 3 page example:-

If I cut and paste the routine from page 21 of "B4X Basic Language V2.1" booklet into B4Xpage2 and then try to reference (use) MyVar IN THE SAME MODULE I get errors.

Here is the code



B4X:
Sub Class_Globals
    Private Root As B4XView 'ignore
    Private xui As XUI 'ignore
    Private lblHello As B4XView
    Private ImageView1 As B4XView
    Private Page3 As B4XPage3
    Private cb1 As B4XComboBox
End Sub

Sub Process_Globals
    Public MyVar As String = "myname"
    
End Sub

'You can add more parameters here.
Public Sub Initialize
    
End Sub

'This event will be called once, before the page becomes visible.
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    'load the layout to Root
    Root.LoadLayout("Page2")
    Page3 = B4XPages.GetPage("Page 3")
    
End Sub

Private Sub B4XPage_Appear
    cb1.cmbBox.Items.Add("Line 2")
    cb1.cmbBox.Items.Add("Line 3")

    lblHello.Text = $"Hello ${B4XPages.MainPage.txtUser.Text}!"$
    UpdateImage
End Sub
'You can see the list of page related events in the B4XPagesManager object. The event name is B4XPage.

Private Sub test
    myvar = "new name"
End Sub


Sub btnDraw_Click
    B4XPages.ShowPage("Page 3")
End Sub

Sub UpdateImage
    If Page3.Panel1.IsInitialized Then
        ImageView1.SetBitmap(Page3.cvs.CreateBitmap)
    End If
End Sub

Sub btnSignOut_Click
    Page3.ClearImage
    UpdateImage
    B4XPages.ShowPageAndRemovePreviousPages("MainPage")   
End Sub

B4XPage2 - 11: Unused variable 'MyVar'. (warning #9)
B4XPage2 - 39: Undeclared variable 'myvar'. (warning #8)
B4XPage2 - 38: Unused variable 'myvar'. (warning #9)
B4XPage2 - 38: Sub 'test' is not used. (warning #12)

If I try to reference same variable (as B4Xpage2.MyVar) from B4Xpage3 it can not be found - Not a surprise

The instructions do not seem to work. What am I missing
 
Upvote 0

Rob White

Member
Licensed User
I am pleased to say I now have things worked out!
The confusion came from the statement made in #4
Just put the variables in the pages classes.
I need some data available in all modules and Classes (including B4X pages). To do this I have created a code module where I have placed the data definitions in the process_globals subroutine and following the instruction referenced above can access the data.

Thank you Erel and Wil
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
To do this I have created a code module where I have placed the data definitions in the process_globals subroutine and following the instruction referenced above can access the data.
Classes are preferable over code modules in B4A.

In most cases it is better to create a class instance in B4XMainPage and access it with:
B4X:
B4XMainPage.DataDefinitions.DoSomething
 
Upvote 0

William Lancee

Well-Known Member
Licensed User
Longtime User
I always use B4XPages and I don't use code modules. If I need global data and related utility Subs, I create a non-B4Xpages Class with public class globals and public subs.
Then in B4XMainPage (or any other page that needs direct access), I declare a one or more instances of that class. For example, "cMatrix" a class for complex matrix manipulation. Then where I need it I declare Private cMx as cMatrix and Initialize the instance. Then use cMx.displayStyle (a global variable in this case) or cMx.createMatrix(Real, Imaginary), a global Sub. Scope is handled consistently in B4X and leads to very readable code.

If you have more than one instance of a Class, each instance has distinct globals. So if you need one set, then create one instance and place it in B4XMainPage or pass it down as a argument.
 
Last edited:
Upvote 0
Top