B4J Question Can I use a 'Wait For' on a ChoiceBox in a different Module?

Mikelgiles

Active Member
Licensed User
Longtime User
Getting into something that is over my brain power I think! In the Detail Module I am downloading some detail transactions and when a new one is downloaded, I need to do one of two choices that comes from the ChoiceBox. So I need to wait until one of the two choices or a cancel has been selected before I continue processing. I need to know if I can base a wait on a Choicebox (cBox) and if so, where can I find a example. This involves two B4XTables ( a master and a detail). Also, am I missing a resource on 'wait for'? I really have looked and found some information but it all seemed to be referencing jobs rather than standard controls (other than a message box)

B4X:
'Module Main
Sub B4XTableM_CellLongClicked (ColumnId As String, RowId As Long)
    SelectedVisibleRowID  = B4XTableM.VisibleRowIDs.IndexOf(RowId)
    SelectedRowDataM = B4XTableM.GetRow(RowId)
    Dim SelectedAccount As String = B4XTableM.GetRow(RowId).Get(ColumnId)
    SelectedRow=RowId
    SelectedCol=ColumnId
    cBox.Items.Clear
    cBox.Top = SelectedVisibleRowID * 24.8+120'100
    cBox.Left=210'220'250
    cBox.items.AddAll(Array As String("Go Online", "History", "Calc_bal","Assign transaction to this account","Add New Account and assign transaction"))
    cBox.ShowChoices
    cBox.PrefHeight=B4XTableM.RowHeight
    cBox.Visible=True
End Sub
Sub cBox_SelectedIndexChanged(Index As Int, Value As Object)
    If Index = -1 Then Return
    Log(Index & "  -  " & Value)
    Select Value
        Case "Go Online" 
            fx.ShowExternalDocument(SelectedRowDataM.Get("URL"))
        Case "History"
            Log("test")
            Dim acct As String = SelectedRowDataM.GetValueAt(0)
            Detail.Show(acct)
        Case "Calc_bal"
            CalcBal
        Case "Assign transaction to this account" 
            Log("Assign transaction to this account  - " & Index & " -  " & Value)
        Case "Add new account and assign transaction"
            Log("Add New Account and assign transaction  -  " & Index & " -  " & Value)
        Case Else
    End Select
    cBox.Visible=False
End Sub

B4X:
'Module Detail
Sub ImportTransactions
    Dim qfxToLoad As String =Main.CashflowINI.get("BankAccountFileName") '"checking1"'todo get this from lost of qfx files
    Dim qfxFile As TextReader
    qfxFile.Initialize(File.OpenInput(Main.dirDownloads, qfxToLoad & ".qfx") )
    qfxData = qfxFile.ReadAll
    Dim ORG As String = ParseQFX(Array As String("/SONRS","/FI","ORG"))
    Dim FID As String = ParseQFX(Array As String("/SONRS","/FI","FID"))
    Dim INTU_BID As String = ParseQFX(Array As String("/SONRS","INTU.BID"))
    Dim INTU_USERID As String = ParseQFX(Array As String("/SONRS","INTU.USERID"))
    Dim BANKID As String = ParseQFX(Array As String("/BANKACCTFROM","BANKID"))
    Dim ACCTID As String = ParseQFX(Array As String("/BANKACCTFROM","ACCTID"))
    Dim DTSTART As String = ParseQFX(Array As String("DTSTART"))
    Dim DTEND As String = ParseQFX(Array As String("DTEND"))
    Dim BALAMT_L As String = ParseQFX(Array As String("/LEDGERBAL","BALAMT"))
    Dim BALAMT_A As String = ParseQFX(Array As String("/AVAILBAL","BALAMT"))
    Dim DTASOF_L As String = ParseQFX(Array As String("/LEDGERBAL","DTASOF"))
    Dim DTASOF_A As String = ParseQFX(Array As String("/AVAILBAL","DTASOF"))
    Dim sI As Int = 1
    Dim bI, eI, LineCount As Int
    Dim eT As Int
    Do While sI=sI
        Dim QD() As String  = Array As String("<STMTTRN><TRNTYPE>","<DTPOSTED>","<TRNAMT>","<FITID>","CHECKNUM>","<NAME>","<MEMO>")
        'some code here to assign values the array QD() to be used in the INSERT command
        If QD(0)="" Then
            Exit
        End If
        Dim rs As ResultSet = B4XTableD.sql1.ExecQuery("Select c4 FROM data WHERE c4 = '" & QD(3) & "'")   
        If rs.NextRow =False Then ' it is not a duplicate transaction that has already been added
            Dim params As List = Array(QD(0), QD(1), QD(2), QD(3), QD(4), QD(5), QD(6))
            B4XTableD.sql1.ExecNonQuery2($"INSERT INTO data VALUES("D", ?, ?, ?, ?, ?, ?, ?)"$,params)
            B4XTableD.Refresh
           
            'Here is my question.  I want to wait here until the Value shows up as = "Assign transaction to this account" or  Add new account and assign transaction".  Note that cBox is in module Main and this sub is in Module Detail
            wait for  Main.cBox_SelectedIndexChanged(Index As Int, Value As Object)
            ' will do some different functions here based on which cBox selection is chosen   
        End If   
    Loop
End Sub
 

OliverA

Expert
Licensed User
Longtime User
Try the following:
In your code module, change
B4X:
wait for  Main.cBox_SelectedIndexChanged(Index As Int, Value As Object)
to
B4X:
wait for  cBox_HandleAction(Action As String, Index As Int, Value As Object)
Select Action
   Case "Assign"
       Log("Action: Assign")
   Case "Add"
       Log("Action: Log")
   Case Else
       Log($"Unsupported Action: ${Action}"$)
End Select
In your Main module, change
B4X:
        Case "Assign transaction to this account" 
            Log("Assign transaction to this account  - " & Index & " -  " & Value)
        Case "Add new account and assign transaction"
            Log("Add New Account and assign transaction  -  " & Index & " -  " & Value)
        Case Else
to
B4X:
        Case "Assign transaction to this account" 
            Log("Assign transaction to this account  - " & Index & " -  " & Value)
            'NOTE: Change ModuleName to the name of the module that has the Wait For cBox_HandleAction
            'Do not enclose in quotes. For example, if the module is named Detail, then change to
            'CallSubDelayed3(Detail, "cBox_HandleAction", "Assign", Index, Value)
            CallSubDelayed3(ModuleName, "cBox_HandleAction", "Assign", Index, Value)
        Case "Add new account and assign transaction"
            Log("Add New Account and assign transaction  -  " & Index & " -  " & Value)
            CallSubDelayed3(ModuleName, "cBox_HandleAction", "Add", Index, Value)
        Case Else
Note: Untested code
 
Upvote 0

Mikelgiles

Active Member
Licensed User
Longtime User
Try the following:
In your code module, change
B4X:
wait for  Main.cBox_SelectedIndexChanged(Index As Int, Value As Object)
to
B4X:
wait for  cBox_HandleAction(Action As String, Index As Int, Value As Object)
Select Action
   Case "Assign"
       Log("Action: Assign")
   Case "Add"
       Log("Action: Log")
   Case Else
       Log($"Unsupported Action: ${Action}"$)
End Select
In your Main module, change
B4X:
        Case "Assign transaction to this account"
            Log("Assign transaction to this account  - " & Index & " -  " & Value)
        Case "Add new account and assign transaction"
            Log("Add New Account and assign transaction  -  " & Index & " -  " & Value)
        Case Else
to
B4X:
        Case "Assign transaction to this account"
            Log("Assign transaction to this account  - " & Index & " -  " & Value)
            'NOTE: Change ModuleName to the name of the module that has the Wait For cBox_HandleAction
            'Do not enclose in quotes. For example, if the module is named Detail, then change to
            'CallSubDelayed3(Detail, "cBox_HandleAction", "Assign", Index, Value)
            CallSubDelayed3(ModuleName, "cBox_HandleAction", "Assign", Index, Value)
        Case "Add new account and assign transaction"
            Log("Add New Account and assign transaction  -  " & Index & " -  " & Value)
            CallSubDelayed3(ModuleName, "cBox_HandleAction", "Add", Index, Value)
        Case Else
Note: Untested code
OliverA, Thank you so much. I did get a error (too many parameters) on the CallSubDelayed3 but this fixed the problem and seems to do what I need.
B4X:
CallSubDelayed3(Detail, Value, "Assign", True)
CallSubDelayed3(Detail, Value, "Add and Assign", True)
Looks like I need to fine tune my searching talents and not limit my searches to B4J. Most of the information was listed under B4A. Erel has already advised me to not limit searches so I need to be more careful.

Again thanks, thanks, and thanks!
 
Upvote 0

Mikelgiles

Active Member
Licensed User
Longtime User
Opps... I spoke too quick. It did wait as expected but never returned to the calling sub.
CallSubDelayed3 wants to call another sub which is not what I am needing. I need for it to return to the calling sub. I will comment again tomorrow when I get my head screwed back on. Wait for may be over my head for this time LOL.
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Create a workflow of what you need and lets go from there. Returning to a calling sub is not an issue, but let’s get the workflow down pat first
 
Upvote 0

Mikelgiles

Active Member
Licensed User
Longtime User
Create a workflow of what you need and lets go from there. Returning to a calling sub is not an issue, but let’s get the workflow down pat first

'I used 'STEP 1 thru 'STEP 5 in the code to hopefully do a understandable workflow. I also tried a different approach only to find that I really dont understand the 'wait for' command nor the Dialog object. My background goes back before DOS and before there was a PC. VB6 is as far as I got and the lack of knowledge of objects and Java is really giving me a hard time. And age LOL.

Detail module
B4X:
Sub ImportTransactions
    Dim qfxToLoad As String =Main.CashflowINI.get("BankAccountFileName") '"checking1"'todo get this from lost of qfx files
    Dim qfxFile As TextReader
    qfxFile.Initialize(File.OpenInput(Main.dirDownloads, qfxToLoad & ".qfx") )
    qfxData = qfxFile.ReadAll
    Dim ORG As String = ParseQFX(Array As String("/SONRS","/FI","ORG"))
    Dim FID As String = ParseQFX(Array As String("/SONRS","/FI","FID"))
    Dim INTU_BID As String = ParseQFX(Array As String("/SONRS","INTU.BID"))
    Dim INTU_USERID As String = ParseQFX(Array As String("/SONRS","INTU.USERID"))
    Dim BANKID As String = ParseQFX(Array As String("/BANKACCTFROM","BANKID"))
    Dim ACCTID As String = ParseQFX(Array As String("/BANKACCTFROM","ACCTID"))
    Dim DTSTART As String = ParseQFX(Array As String("DTSTART"))
    Dim DTEND As String = ParseQFX(Array As String("DTEND"))
    Dim BALAMT_L As String = ParseQFX(Array As String("/LEDGERBAL","BALAMT"))
    Dim BALAMT_A As String = ParseQFX(Array As String("/AVAILBAL","BALAMT"))
    Dim DTASOF_L As String = ParseQFX(Array As String("/LEDGERBAL","DTASOF"))
    Dim DTASOF_A As String = ParseQFX(Array As String("/AVAILBAL","DTASOF"))
    Dim sI As Int = 1
    Dim bI, eI, LineCount As Int
    Dim eT As Int
    Do While sI=sI
        Dim QD() As String  = Array As String("<STMTTRN><TRNTYPE>","<DTPOSTED>","<TRNAMT>","<FITID>","CHECKNUM>","<NAME>","<MEMO>")
        'some code here to assign values the array QD() to be used in the INSERT command
        If QD(0)="" Then
            Exit
        End If
        Dim rs As ResultSet = B4XTableD.sql1.ExecQuery("Select c4 FROM data WHERE c4 = '" & QD(3) & "'")   
        If rs.NextRow =False Then ' it is not a duplicate transaction that has already been added
            Dim params As List = Array(QD(0), QD(1), QD(2), QD(3), QD(4), QD(5), QD(6))
            B4XTableD.sql1.ExecNonQuery2($"INSERT INTO data VALUES("D", ?, ?, ?, ?, ?, ?, ?)"$,params)
            B4XTableD.Refresh
           
            wait for  cBox_HandleAction(Action As String, Index As Int, Value As Object)  'STEP 1 - each time it finds a new transaction
            Select Action
               Case "Assign"
                   Log("Action: Assign") 'STEP 5 will asign this transaction to a account
               Case "Add"
                   Log("Action: Log") or 'STEP 5  will add a new account and assign this transaction to that account
               Case Else
                   Log($"Unsupported Action: ${Action}"$) or  or 'STEP 5
            End Select
            ' will do some different functions here based on which cBox selection is chosen   
        End If   
    Loop
End Sub
'Main module
B4X:
Sub B4XTableM_CellLongClicked (ColumnId As String, RowId As Long) 'STEP 2 waits until a right click is done in B4XTableM
    SelectedVisibleRowID  = B4XTableM.VisibleRowIDs.IndexOf(RowId)
    SelectedRowDataM = B4XTableM.GetRow(RowId)
    Dim SelectedAccount As String = B4XTableM.GetRow(RowId).Get(ColumnId)
    SelectedRow=RowId
    SelectedCol=ColumnId
    cBox.Items.Clear
    cBox.Top = SelectedVisibleRowID * 24.8+120'100
    cBox.Left=210'220'250
                                                                  'STEP 3 assignes choices for cbox and sets to visible and shows choices
    cBox.items.AddAll(Array As String("Go Online", "History", "Calc_bal","Assign transaction to this account","Add New Account and assign transaction"))
    cBox.ShowChoices
    cBox.PrefHeight=B4XTableM.RowHeight
    cBox.Visible=True
End Sub
Sub cBox_SelectedIndexChanged(Index As Int, Value As Object)
    If Index = -1 Then Return   'STEP 4 select a choice
    Log(Index & "  -  " & Value)
    Select Value
        Case "Go Online" 
            fx.ShowExternalDocument(SelectedRowDataM.Get("URL"))
        Case "History"
            Log("test")
            Dim acct As String = SelectedRowDataM.GetValueAt(0)
            Detail.Show(acct)
        Case "Calc_bal"
            CalcBal
        Case "Assign transaction to this account" 
            Log("Assign transaction to this account  - " & Index & " -  " & Value)
            'NOTE: Change ModuleName to the name of the module that has the Wait For cBox_HandleAction
            'Do not enclose in quotes. For example, if the module is named Detail, then change to
            'CallSubDelayed3(Detail, "cBox_HandleAction", "Assign", Index, Value)
            CallSubDelayed3(ModuleName, "cBox_HandleAction", "Assign", Index, Value)'STEP 4a  needs to return to the line following STEP 1
        Case "Add new account and assign transaction"
            Log("Add New Account and assign transaction  -  " & Index & " -  " & Value)
            CallSubDelayed3(ModuleName, "cBox_HandleAction", "Add", Index, Value)  'STEP 4a  needs to return to the line following STEP 1
        Case Else
    End Select
    cBox.Visible=False
End Sub
 
Upvote 0

Mikelgiles

Active Member
Licensed User
Longtime User
it will keep running until a condition is met. look for the EXIT a few lines down. it was just a easy way to continue until the end of the transactions.
 
Upvote 0

Mikelgiles

Active Member
Licensed User
Longtime User
i see... i made simple project for you, i hope you can get the idea
Interesting and I am working to understand it all. Two questions for now
1) You have made the module Detail into a class? I am new on classes and have used some but never written any. What is the benefit of making it a class. As I was using Detail I was thinking that I had to add 'Main.' to the front of anything that was created in main in order to use it in Detail. It appears in your code that the Combobox works in both modules without doing anything special.

2) ComboClicked works with any ComboBox regardless of the name and regardless of which module it is created in?

And thank you for the example. I will play with it some more and see if I can understand it better.
 
Upvote 0

rraswisak

Active Member
Licensed User
First of all, i found my self that Wait For and CallSubDelayed is great feature of B4X. It's simplified of complex code interacting between module, activity or services.

What is the benefit of making it a class
B4A and B4J (and maybe in B4i as well, i don't know - i never install B4i version of B4X) has Code Module which we can create any sub and called from anywhere. The difference is... in B4A - static module can't handle event (using wait for in code module) but B4J did. So whenever you change (in my sample project) the class version sub into code module sub it will also work as expected.

By using class approach it will work on both environment.

ComboClicked works with any ComboBox regardless of the name and regardless of which module it is created in?
Yes as long as they call same name. AFAIK - with class - we can create several instance of class contain wait for and call later, for example;

in class module called clsMessage:
B4X:
Sub Class_Globals
   Private fx As JFX
   Private note As String
End Sub

Public Sub Initialize(noteToDisplay As String)
   note = noteToDisplay
End Sub

Public Sub StartListening
   Do While 1 = 1
       Wait For ShowMessage
       Log(note)
   Loop
End Sub

in main module:
B4X:
Sub Process_Globals
   Private fx As JFX
   Private MainForm As Form
   Private cMsg1, cMsg2 As clsMessage
End Sub

Sub AppStart (Form1 As Form, Args() As String)
   MainForm = Form1
   MainForm.RootPane.LoadLayout("a")
   MainForm.Show
  
   cMsg1.Initialize("Message from cMsg1 class instance")
   cMsg1.StartListening

   cMsg2.Initialize("Message from cMsg2 class instance")
   cMsg2.StartListening
End Sub

Sub Button1_Click
   CallSubDelayed(cMsg1,"ShowMessage")
End Sub

Sub Button2_Click
   CallSubDelayed(cMsg2,"ShowMessage")
End Sub

if there some one who can make thing work but bad how to explain, its probably me.
 
Upvote 0

Mikelgiles

Active Member
Licensed User
Longtime User
First of all, i found my self that Wait For and CallSubDelayed is great feature of B4X. It's simplified of complex code interacting between module, activity or services.


B4A and B4J (and maybe in B4i as well, i don't know - i never install B4i version of B4X) has Code Module which we can create any sub and called from anywhere. The difference is... in B4A - static module can't handle event (using wait for in code module) but B4J did. So whenever you change (in my sample project) the class version sub into code module sub it will also work as expected.

By using class approach it will work on both environment.


Yes as long as they call same name. AFAIK - with class - we can create several instance of class contain wait for and call later, for example;

in class module called clsMessage:
B4X:
Sub Class_Globals
   Private fx As JFX
   Private note As String
End Sub

Public Sub Initialize(noteToDisplay As String)
   note = noteToDisplay
End Sub

Public Sub StartListening
   Do While 1 = 1
       Wait For ShowMessage
       Log(note)
   Loop
End Sub

in main module:
B4X:
Sub Process_Globals
   Private fx As JFX
   Private MainForm As Form
   Private cMsg1, cMsg2 As clsMessage
End Sub

Sub AppStart (Form1 As Form, Args() As String)
   MainForm = Form1
   MainForm.RootPane.LoadLayout("a")
   MainForm.Show
 
   cMsg1.Initialize("Message from cMsg1 class instance")
   cMsg1.StartListening

   cMsg2.Initialize("Message from cMsg2 class instance")
   cMsg2.StartListening
End Sub

Sub Button1_Click
   CallSubDelayed(cMsg1,"ShowMessage")
End Sub

Sub Button2_Click
   CallSubDelayed(cMsg2,"ShowMessage")
End Sub

if there some one who can make thing work but bad how to explain, its probably me.

My background goes from a little before DOS and the IBM PC and ended with VB6 but I never learned about classes. I did get pretty good with VB6 in the easy stuff. But I am learning that I am barely touching the surface With B4X stuff. There is so much powerful stuff that I am having a problem understanding. And old age makes it even worse LOL.

I am going to play with this class by trying to include it in my app just to get clear on how.
 
Last edited:
Upvote 0
Top