Android Question B4XPages and custom menubar

RB Smissaert

Well-Known Member
Licensed User
Longtime User
Just started with B4XPages and added a simple custom menubar, not based on the built-in Android menubar, but based on
layouts with panels, labels and buttons.
As far as I understand most apps will access the built-in menubar in some form, but I may have this wrong.
In my old, non-B4xPages app all the app screens were based on panels, called from Main. Only one panel would
be visible, so picking a screen was done by setting the particular panel visible and made all the other ones invisible.
For the menu I was using AppCompat.

Now if I do this in B4XPages and not using AppCompat, but this custom menubar and I set the required screen by creating and showing a B4X page
and adding that custom menubar, it seems there will be a lot of code duplication, to do with the menubar.

Attached a simple demo project that demonstrates this.
There is zipped .csv file as well that setsup the menu, including the overflow menu.
I can't add this .csv to DirAssets as there will be an error, file not found, even although the file is definitely there.
I think this is to with a permission problem, but not sure about that.
In any case the .csv has to be put in folder in Internal Storage, and I called that folder PhonePats.

With all this I have 2 questions:
1. Is there any problem with not using the built-in Android menubar/toolbar?
2. What would be the best way to avoid the code duplication to do with the custom menubar?

Thanks for any further insight.

RBS
 

Attachments

  • B4AProject.zip
    168.5 KB · Views: 177
  • menu_props.zip
    1.8 KB · Views: 187

udg

Expert
Licensed User
Longtime User
I didn't check you code, but you could create a class for your own menubar.
Then each page will instatiate its own copy of that class, eventually passing as an argument a "page code" so the common class code knows which page it's working on.
 
Upvote 0

RB Smissaert

Well-Known Member
Licensed User
Longtime User
I didn't check you code, but you could create a class for your own menubar.
Then each page will instatiate its own copy of that class, eventually passing as an argument a "page code" so the common class code knows which page it's working on.
Will try that.
Actually, I started with a menu class, but I think there were problems with the class handling views.
Mind you B4XPages are just classes, so it must be possible to make it work.

RBS
 
Upvote 0

udg

Expert
Licensed User
Longtime User
I used that same hint for some of my apps.
Each B4xPage has room on its layout for a "command panel" (it's just an empty panel).
The a common class (clCommands) receives (in its initialize sub) from each page a reference to its command panel and a page code.
clCommands loads the proper layout in the passed panel and manages clicks on its items based on the PageCode received on initialization.

In other words, clCommand does all the work (eventually calling back subs in b4xpages if needed).
 
Upvote 1

RB Smissaert

Well-Known Member
Licensed User
Longtime User
I used that same hint for some of my apps.
Each B4xPage has room on its layout for a "command panel" (it's just an empty panel).
The a common class (clCommands) receives (in its initialize sub) from each page a reference to its command panel and a page code.
clCommands loads the proper layout in the passed panel and manages clicks on its items based on the PageCode received on initialization.

In other words, clCommand does all the work (eventually calling back subs in b4xpages if needed).
Not sure I fully understand, but will have a look at that.
In this setup I take it there is no separate menu class, all will be done by clCommands?

RBS
 
Upvote 0

teddybear

Well-Known Member
Licensed User
Attached a simple demo project that demonstrates this.
There is zipped .csv file as well that setsup the menu, including the overflow menu.
I can't add this .csv to DirAssets as there will be an error, file not found, even although the file is definitely there.
I think this is to with a permission problem, but not sure about that.
In any case the .csv has to be put in folder in Internal Storage, and I called that folder PhonePats.


RBS
You can put the .cvs into DirAssets, but you need to do a bit of change in your code. it will work.
B4X:
    'this will be a zero-based UTF8 byte array
    '-----------------------------------------
    'RAF.Initialize(strFolder, strFile, True) <====== Comment this line out
    '--------Add 2 lines below---------------
    File.Copy(strFolder, strFile, File.DirInternal, strFile)
    RAF.Initialize(File.DirInternal, strFile, True)
    '--------------------------------------------
 
Upvote 0

udg

Expert
Licensed User
Longtime User
Exactly. Maybe your menu class is what I call clCommands
Here are a few snippets that should make it clearer what I do
B4X:
'in each B4xPage that needs to show the commands menu
Private Comands As clComands
Private const PageCode As Int = 4   'each page has it own code
   
Private pnlCmd As B4XView   'this one is part of the page layout

'in B4XPage_Created
Comands.Initialize(Me, pnlCmd, PageCode)

'Class clComands
Sub Class_Globals
    Private xui As XUI
    Private p1 As B4XView
    Private PageCode As Int
    Private CBack As Object
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize(CB As Object, pnlCmd As B4XView, pCode As Int)
    PageCode = pCode
    p1 = pnlCmd
    p1.LoadLayout("lytComands")
    CBack = CB
End Sub

Private Sub cmd_Click
    Dim btn As B4XView = Sender
    Dim idx As Int = btn.tag
    'comand executed only if for a different page
    If idx <> PageCode Then
        Select idx
            Case 0
                Log("exit comand")
                CallSubDelayed(CBack, "stopme")
            Case 1
                B4XPages.ShowPageAndRemovePreviousPages("pgPage1")
            Case 2
                B4XPages.ShowPageAndRemovePreviousPages("pgPage2")
            Case 3
                B4XPages.ShowPageAndRemovePreviousPages("pgPage3")
        End Select
    End If
End Sub

In this case the clComands is used to switch between pages when a button/panel/image is clicked on the Commands panel.
 
Upvote 0

RB Smissaert

Well-Known Member
Licensed User
Longtime User
You can put the .cvs into DirAssets, but you need to do a bit of change in your code. it will work.
B4X:
    'this will be a zero-based UTF8 byte array
    '-----------------------------------------
    'RAF.Initialize(strFolder, strFile, True) <====== Comment this line out
    '--------Add 2 lines below---------------
    File.Copy(strFolder, strFile, File.DirInternal, strFile)
    RAF.Initialize(File.DirInternal, strFile, True)
    '--------------------------------------------
OK, thanks will do that.
Will save a lot of hassle explaining about the .csv.

RBS
 
Upvote 0

RB Smissaert

Well-Known Member
Licensed User
Longtime User
I didn't check you code, but you could create a class for your own menubar.
Then each page will instatiate its own copy of that class, eventually passing as an argument a "page code" so the common class code knows which page it's working on.
>> eventually passing as an argument a "page code" so the common class code knows which page it's working on

What do you suggest to pass as the page code?
Ideally, maybe it would be Me, so the class instance of the B4XPage, except I am not sure what the variable type of the passed argument would be in the Initialize Sub of the
receiving menu class. In a non-B4XPages project it would be Activity, so you would get something like this:

B4X:
'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize(oParent As Activity)
    
End Sub

But now it won't be Activity, so what would be best to pass as the argument to the Sub Initialize of the menu class?

RBS
 
Upvote 0

teddybear

Well-Known Member
Licensed User
>> eventually passing as an argument a "page code" so the common class code knows which page it's working on

What do you suggest to pass as the page code?
Ideally, maybe it would be Me, so the class instance of the B4XPage, except I am not sure what the variable type of the passed argument would be in the Initialize Sub of the
receiving menu class. In a non-B4XPages project it would be Activity, so you would get something like this:

But now it won't be Activity, so what would be best to pass as the argument to the Sub Initialize of the menu class?

RBS
The page code is an integer that indicated which page it is, it is defined in each page. as udg said that you should initialize menu class that udg has posted which called clCommands in each page. it will work by cmd_click.
 
  • Like
Reactions: udg
Upvote 0

udg

Expert
Licensed User
Longtime User
Look at my code in post #7 above.
I pass a simple int defined as a constant on each page. In the example above it is used to avoid calling code/commands referring to the same page you are showing.
In my example a menu bar let you switch from one page to the other and the "page code" is in fact the position of the button (or panel/image, I can't recall) that represents a page on the command bar. This same code is assigned to each command button's tag property.

BTW, you could use that same setup when you want to display different command menus based on the logged in user role.
I often have staff, manager, supervisor. This way each user is presented only the options he/she is allowed to select. Role is generally defined in the DB along with other data specific to each user.
 
Upvote 0

RB Smissaert

Well-Known Member
Licensed User
Longtime User
Look at my code in post #7 above.
I pass a simple int defined as a constant on each page. In the example above it is used to avoid calling code/commands referring to the same page you are showing.
In my example a menu bar let you switch from one page to the other and the "page code" is in fact the position of the button (or panel/image, I can't recall) that represents a page on the command bar. This same code is assigned to each command button's tag property.

BTW, you could use that same setup when you want to display different command menus based on the logged in user role.
I often have staff, manager, supervisor. This way each user is presented only the options he/she is allowed to select. Role is generally defined in the DB along with other data specific to each user.
OK, thanks, I got it and will try that.
Somehow I missed post 7 with the code examples.

RBS
 
  • Like
Reactions: udg
Upvote 0

RB Smissaert

Well-Known Member
Licensed User
Longtime User
OK, thanks, I got it and will try that.
Somehow I missed post 7 with the code examples.

RBS
It is a bit more complex than in the posted example code (with clComnand) as I want my menu class to load the menu, which is one horizontal panel, holding
4 different layouts (with about 4 to 6 menu buttons and a menu title label) and also about 5 vertical panels where buttons are loaded to in code. These vertical panels
are for the overflow buttons. The horizontal panels are partly set by the .csv file and the vertical panels are fully set by the .csv file.
Then I also want it to deal with showing the various pages, dependant on what buttons was clicked.
I think your sample code mainly deals with the second part, showing the pages and I take that is why you called it clCommand and I call mine clsMenu.
At moment all the menu code is in Main, so moving that to clsMenu now.
Will work it out.

RBS
 
  • Like
Reactions: udg
Upvote 0
Top