B4J Question Two 'forms' where does the code go?

raphipps2002

Active Member
Licensed User
Longtime User
[apologies for wrong terminology used to vb.net]

I have a main form where, when pressing a button on it, opens another form. On the second form there is a button which should I thought jump to the sub where the event is and do what it is supposed to do. But it doesn't. Should all the code go in the Main code module or is it ok to have code 'behind' each form, so that code is identified with that window? on the second form I 'Generated Members' and created events which appear in my another code module. Will the button click even default back the the main code or do i need to associate the form2 with that second code module in another way?

Hope that makes sense?

As you know with vb.net...clicking that button automatically associates the code with a form. All the 'views' or 'objects' are directly associated with it. With B4J it seems you can have everything everywhere.
 

dilettante

Active Member
Licensed User
Longtime User
I hope I'm not adding confusion, and I'll admit to being a rank newbie at B4J (and B4A) but here's what I have gotten to work after a fashion.

I have a Layout1 for my MainForm. It just has a Button and a TextField. When you click the Button it should "raise a dialog" (another form) used to request a "name" (just some text).

Then I have a class FetchName that loads a Layout2 as its SubForm. This has a TextField and a Button. When displayed the user should enter a "name" into the TextField and click the Button.

After this, the SubForm disappears and in Main the entered value is retrieved and then displayed in the MainForm's TextField.

So very trivial, or so I thought.

Here is what I have:

B4X:
Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private btnGetName As Button
    Private txtName As TextField
    Private FetchName As FetchName
End Sub
 
Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1") 'Load the layout file.
    FetchName.Initialize
    MainForm.Show
End Sub
 
Sub btnGetName_Action
    FetchName.Fetch
End Sub
 
Sub Ok
    txtName.Text = FetchName.Name
End Sub

B4X:
Sub Class_Globals
    Private fx As JFX
    Private SubForm As Form
    Private txtName As TextField
    Private btnOk As Button
End Sub
 
Public Sub Initialize
    SubForm.Initialize("SubForm", -1, -1)
    SubForm.RootPane.LoadLayout("Layout2")
End Sub
 
Public Sub Fetch
    txtName.Text = ""
    SubForm.Show
End Sub
 
Sub btnOk_Action
    txtName.RequestFocus 'Move focus here for next Fetch request.
    SubForm.Close
    Main.Ok 'Callback to Main.
End Sub
 
Sub getName As String
    Return txtName.Text
End Sub

This sorta kinda works except of course "in real life" you'd want the dialog SubForm to be modal and I haven't a clue how to make that happen.

Also I had to sort of kludge in a hard-coded callback into Main since I haven't figured out how to implement and raise events in a B4J Class.


But I do feel like I'm missing something (probably a lot).
 
Upvote 0

dilettante

Active Member
Licensed User
Longtime User
Ok, here is my "take two" on this, which addresses the modal issue and eliminates the hard-coded callback.

B4X:
Private Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private btnGetName As Button
    Private txtName As TextField
    Private FetchName As FetchName
End Sub
 
Private Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1") 'Load the layout file.
    FetchName.Initialize
    MainForm.Show
End Sub
 
Private Sub btnGetName_Action
    FetchName.Fetch
    txtName.Text = FetchName.Name
End Sub

B4X:
Private Sub Class_Globals
    Private fx As JFX
    Private SubForm As Form
    Private txtName As TextField
    Private btnOk As Button
End Sub
 
Public Sub Initialize
    SubForm.Initialize("SubForm", -1, -1)
    SubForm.RootPane.LoadLayout("Layout2")
End Sub
 
Public Sub Fetch
    txtName.Text = ""
    SubForm.ShowAndWait
End Sub
 
Private Sub btnOk_Action
    txtName.RequestFocus 'Move focus here for next Fetch request.
    SubForm.Close
End Sub
 
Public Sub getName As String
    Return txtName.Text
End Sub

The key here is the ShowAndWait method, which I'm embarrassed to admit I had overlooked.

You can probably even stuff all of the .Fetch logic into .Initialize here, but I'd probably only do that if I knew I only needed to use the 2nd form once during a run.
 
Last edited:
Upvote 0

dilettante

Active Member
Licensed User
Longtime User
I'm still curious whether or not there is a more "obvious" or "official" way to do this sort of thing. Mine may be a sort of a hack.
 
Upvote 0

dilettante

Active Member
Licensed User
Longtime User
No, I hadn't. But it is helpful.

Handling the CloseRequest to prevent unloading when not ready looks useful.

I'm not sure why you'd want to pass Parent (a Form) to Initialize of ModalForm though. I'd almost rather pass the parent "object" (Main here) to permit callbacks but I can't figure out its type so I can't declare the parameter... e.g. As Object doesn't work.
 
Upvote 0

dilettante

Active Member
Licensed User
Longtime User
The child form behaves better when its owner form is set.

I could buy that. However in the example:

B4X:
Public Sub Initialize (Parent As Form)
    frm.Initialize("frm", 300dip, 200dip)
    frm.Title = "Choose color"
    frm.SetFormStyle("UTILITY")
    frm.RootPane.LoadLayout("2")
   
    FillList
   
End Sub

I do not see where Parent is used at all, let alone used to set an owner/owned relationship. What am I missing?

You can pass the "parent" module. It should Object and you should call Me to pass it.

I figured as much, and tried it. However being As Object, I wasn't able to call into a callback method of Main that way.

It feels like I need to cast it to some interface type (not sure what type) or use some sort of "late bound" call mechanism (CallSub or something?).
 
Upvote 0

raphipps2002

Active Member
Licensed User
Longtime User
Well It seems I started this ...I am new to B4J after using B4A for two months and getting to grips with that. I don't understand the fetch business above.

I simply have a parent and child form and one calls the other. Works ok. But the button on the child form does not work if i generate the Sub's on the child form (generate members) But if I do on the parent all the code in the subs works.

I want to isolate the the code to each form...like in vb.net

I have zipped the app here and if anyone can help me understand what i am doing wrong i'd appreciate it
 

Attachments

  • SQL_DB.zip
    29.3 KB · Views: 346
Upvote 0

raphipps2002

Active Member
Licensed User
Longtime User
Ok i see....well this is a difference with my vb.net knowledge. So, it seems that most of the code in a project will be 'behind' the main form. Which is fine if not different. So full steam ahead with my app!...thanks
 
Upvote 0

dilettante

Active Member
Licensed User
Longtime User
See my post #4 above. Most of the "code behind" a Form can be in a unique Class created to host each unique Form. That gets around having a gigantic, complicated Main module.
 
Upvote 0

dilettante

Active Member
Licensed User
Longtime User
Just a suggestion. There doesn't seem to be a "right" way to do this in B4J.

Frankly I'd expected something like an "add Form" item on the IDE menu that built you a Class something like this with the skeleton code you'd need. Maybe we'll get that in a future release, or something similar based on the pattern that works best.
 
Upvote 0

raphipps2002

Active Member
Licensed User
Longtime User
Thanks for your help. I hoped the transition between B4A and B4j would be easy but it seems there is much I dont understand right now. I decided to avoid the two forms as above as I discovered the TAB pane which looked like a nice aesthetic way to do what I want. SO I added the ID's to the Java FX css and used the member generator, to what I thought, would create some events when I clicked a tab as follows:

in Process Globals

B4X:
Private tabMain As Node
    Private tabMain2 As Node
    Private tab1Btn1 As Button
    Private tabMain1 As Node

B4X:
Sub tab1Btn1_MouseClicked (EventData As MouseEvent)

Log("tab butt1")
End Sub
Sub tabMain2_MouseClicked (EventData As MouseEvent)
  
    Log("tab2")
End Sub
Sub tabMain1_MouseClicked (EventData As MouseEvent)
  
    Log("tabmain1")
End Sub

However, none of these events work! So, now what am I doing wrong. Can you help pls
 
Upvote 0
Top