B4J Question Need one sub routine for multiple buttons

chuck3e

Active Member
Licensed User
Longtime User
Short question is how do I get multiple buttons to go to the same sub routine?

This should have a simple solution but I can't figure it out for B4J. I have this working in Android but the same logic isn't working in B4J. I have 30 buttons that I want to change the Button.Text dynamically for, but I want to do the text change in one sub routine via the array. I am saving the buttons in an array to do this. I am not creating the buttons with code. I'm using Scene Builder.

If I give each button its own unique Java FX CSS Id (Node ID?) everything works fine but I have to create a separate sub routine for each button. If I give them all the same Id it doesn't work. How can I give each button its own Id but have them all go to the same sub routine when it is clicked?

Editing to add more info:
I see areas in the Scene Builder called "On Action" and "On Mouse Click" under the fx:id but can't find any doc to explain these. Will these give me what I want?
 
Last edited:

derez

Expert
Licensed User
Longtime User
It works like in b4a:
You give all the buttons the same css id, and have one sub for action.
in the sub do this:
B4X:
Dim b as button
b = sender
b.text = ....
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
I see areas in the Scene Builder called "On Action" and "On Mouse Click" under the fx:id but can't find any doc to explain these. Will these give me what I want?
No. You shouldn't use those fields.

The difference between B4A is that there is only one ID field. In B4A we have Name and EventName. If you can then you should give all these buttons the same ID.
 
Upvote 0

chuck3e

Active Member
Licensed User
Longtime User
It works like in b4a:
You give all the buttons the same css id, and have one sub for action.
in the sub do this:
B4X:
Dim b as button
b = sender
b.text = ....

Dave, thanks for your reply but that is exactly what I am doing and that part produces the results as it should but that is not the problem. See my reply to Erel.
 
Upvote 0

chuck3e

Active Member
Licensed User
Longtime User
Erel,
Thanks for the reply. The problem is that giving all the buttons the same Id somehow messes up the way the array works. If I give all the buttons the same Id then all the names in the array have to be the same or else I get the "Object should first be initialized..." error. I have to be missing something because this is a common practice, isn't it? Where you have multiple buttons but want them to go to the same sub routine?

So, if I do this, after giving each button a unique id in Scene Builder:
B4X:
Buttons = Array As Button(Button1,  Button2,  Button3,  Button4,  Button5, _               
                              Button6,  Button7,  Button8,  Button9,  Button10)      

For i = 0 To Gx -1
        Buttons(i).text = GrabName(i).Substring2(11,13) & "/" & GrabName(i).Substring2(13,15) & "/" &
        GrabName(i).Substring2(15,17) & " " & GrabName(i).Substring2(17,24) 'parse the file date
        Buttons(i).Tag = GrabName(i)    'save the file name 
    Next

then all the buttons get the text changed correctly.

But this needs a unique sub routine for each button:

B4X:
Sub Button1_MouseClicked (EventData As MouseEvent)
    b = Sender 'Cast the Object to Button
    MyFile = b.tag  'full file name
End Sub

Sub Button2_MouseClicked (EventData As MouseEvent)
    b = Sender 'Cast the Object to Button
    MyFile = b.tag  'full file name
End Sub

And I get the correct results.

but If I do this after giving all the buttons the same id of "Button" in Scene Builder:
B4X:
Buttons = Array As Button(Button,  Button,  Button,  Button,  Button, _                
                              Button,  Button,  Button,  Button,  Button)

Only one button gets the text changed (and strangely it's the 7th button of the 10 buttons).

If I change the id in Scene builder to "Button" but leave the names in the array as "Button1, Button2..." then I get a "Object should first be initialized..." error.

-Chuck
 
Upvote 0

chuck3e

Active Member
Licensed User
Longtime User
While waiting for a solution to the above issue I decided on the following work-around. It works but it is not neat. At least it will save a lot of potential redundant code.


B4X:
Sub Button1_MouseClicked (EventData As MouseEvent)
'    ...1,000 lines of code go here....
End Sub

Sub Button2_MouseClicked (EventData As MouseEvent)
    Button1_MouseClicked (EventData) 'This goes back to Button1's logic rather than duplicate it here.
End Sub

Sub Button3_MouseClicked (EventData As MouseEvent)
    Button1_MouseClicked (EventData) 'This goes back to Button1's logic rather than duplicate it here.
End Sub

-C
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
This problem is less about determining which button is pressed and more about how to assign data to the relevant tag in the first place.

There are going to be many potential solutions to this problem as time goes on, but my preference so far is to add tags to the StyleClasses as they won't get in the way of anything else.

I have previously copied them to tags in the objects on starting the app. In this case you can't do that as you want to use the tags for something else. So I've left them in the StyleClass field.

Then, in the Scene Builder, create a group around the buttons, (Select the buttons then in Arrange menu, select Wrap in, then Group a new Node is created with a css id of Group) you can change the css id of the group to something meaningful and you can then generate the Member for the group in the IDE.

Once you know that Group in JavaFX has a method called getChildren, the rest is straight forward:

B4X:
Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private Btn As Button
    Private BtnGroup As Node
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("1") 'Load the layout file.

    AssignTags

    MainForm.Show

End Sub

Sub Btn_Action

Dim B As Button = Sender
Log(B.Tag)

End Sub
Sub AssignTags

    Dim Children As List
    Dim JO As JavaObject = BtnGroup
    Children = JO.RunMethod("getChildren",Null)
    For Each Child As Button In Children
        If Child.StyleClasses.IndexOf("Tag:Btn1") <> -1 Then Child.Tag= "This is Btn1"' or whatever else
        If Child.StyleClasses.IndexOf("Tag:Btn2") <> -1 Then Child.Tag= "This is Btn2"
        If Child.StyleClasses.IndexOf("Tag:Btn3") <> -1 Then Child.Tag= "This is Btn3"
        If Child.StyleClasses.IndexOf("Tag:Btn4") <> -1 Then Child.Tag= "This is Btn4"
        If Child.StyleClasses.IndexOf("Tag:Btn5") <> -1 Then Child.Tag= "This is Btn5"
    Next
End Sub


Just one possible solution.

Example project attached.
 

Attachments

  • test.zip
    1.2 KB · Views: 417
Last edited:
Upvote 0
Top