B4J Question B4J Create designer files at runtime...

Magma

Expert
Licensed User
Longtime User
Hi there...

Well I know that what I am asking may be is a "direct" question (hate to do that - not right) to Erel but may be someone already searched it or tried it.

Well we all know Balconverter (that convert bal/bjl/bil to json and json to bal/bjl/bil)...

Well i have a different question on that-logic... what if create some controls/customviews at runtime (yes reading right)... how possible is to create json and then convert it to bal/bjl... Is there a quick.. to create the "kids" / controls / data need the bal/bjl fast...

B4X:
    For Each i As B4XView In myb4xform.GetAllViewsRecursive
...................magic_creating_json that need bal/bjl/bil.......
    next
 

Magma

Expert
Licensed User
Longtime User
When i was writing the pmtemplates application i used the JSON Tree application to visualize the JSON structure.
An example:
View attachment 146442
If you designed a layout like this: tf1 = Text Field, btn1 = Button and clv1 = Custom List View.
Then the converted .bjl layout file will have this JSON structure (provided you use only 1 variant):
View attachment 146443
Drilling down in this structure give these details:
View attachment 146444
And for the data:
View attachment 146445
And then you can look at the :kids map:
View attachment 146446
For the first kid:
View attachment 146447
View attachment 146448
And so on for the other kids...
The JSON tree application also provides the B4X code to build the tree structure.
Some questions about this structure:
- are all the attributes required?
- (as you mentioned already) where can you find the correct javaType?
- what will be the structure if you use Designer Script?
- ...
Yes.. I got it...

But wanted those lists/maps automatically or using keys of controls somehow...

😉 I am asking too much...

But reverse engineering will also make the job here..
 
Upvote 0

Magma

Expert
Licensed User
Longtime User
Upvote 0

Mashiane

Expert
Licensed User
Longtime User
My suggestion is... work in small quantities.

1. Take a blank layout, convert it to json.
2. Try and rebuild that json via code. Run windiff to see if the files dont have any differences. Fortunately we have the "As" directive now.
3. Now use the json to bjl code to convert your newly done layout to bjl. See if it loads.

4. In the blank layout, add 1 basic control > convert it to json, compare what has changed, rebuild what has changed, recheck.

If this works with 1 or more components then you will be close to achieving your goals.

I wish you all the best, I think this will be very valuable.
 
Upvote 0

Magma

Expert
Licensed User
Longtime User
Some questions about this structure:
- are all the attributes required?
- (as you mentioned already) where can you find the correct javaType?
- what will be the structure if you use Designer Script?
- ...

Well not using all properties... because no need them.. and don't want also make it difficult user interface for end user.

Javatype can be found checking one by one all controls needed to designed.. at conversion of json

Designer script not needed at first...
 
Last edited:
Upvote 0

Magma

Expert
Licensed User
Longtime User
My suggestion is... work in small quantities.

1. Take a blank layout, convert it to json.
2. Try and rebuild that json via code. Run windiff to see if the files dont have any differences. Fortunately we have the "As" directive now.
3. Now use the json to bjl code to convert your newly done layout to bjl. See if it loads.

4. In the blank layout, add 1 basic control > convert it to json, compare what has changed, rebuild what has changed, recheck.

If this works with 1 or more components then you will be close to achieving your goals.

I wish you all the best, I think this will be very valuable.
Something like that...I am doing
 
Upvote 0

William Lancee

Well-Known Member
Licensed User
Longtime User
Some cautions:
1. Anchors are not in available in code generated views - you lose the ability for automatic screen-adaptive designs
2. A layout to JSON converter needs to be recursive: panels have panels have views, not easy to do
3. Make sure you have read this thread

https://www.b4x.com/android/forum/t...iles-to-json-and-vice-versa.41623/post-251260


You could use defaults for unknown or undefined properties that are needed by the BalConverter app to create the .bal/.bjl files.
Since you are master at the shell game, you could run the .exe version of BalConverter.

@PaulMeuris has provided the structure of json in #17
 
Upvote 0

Magma

Expert
Licensed User
Longtime User
....Well... i have some newssss... to share... and seems that i am in good path at least for what we want...

The following code not total ready but is what i want... to create json that will be converted to bjl or bal...

For bjl.. for example

Need to assign what my Designer knows with what knows the Internal Designer... so at assignedTypes adding for start only 3 types Label,B4XFloatTextField,B4XComboBox (citem01,citem02,citem03 - for my app) - attaching them too... (also the control and event name always name theitem to be possible found and for easy changing)

also kept from layouts 3 different files names with citemXX.json --- only the kids json needed...
and with lists and map manage to change the values needed...

Hope you understand what doing (at least i think those who already created a designer could understand)

B4X:
'Layout Creation...  SaveLayoutfromView
'----------------------------
Sub CreateJsonfromDesign() 'As JSON
    Dim Design As Map
    Design.Initialize
   
    Dim assignedTypes As List
    assignedTypes.Initialize
    Dim whatassign As Map
    whatassign.Initialize
   
    'Labe Item --> citem01
    whatassign.put("B4XDesigner","citem01") 'B4XDesigner is our designer we are creating...
    whatassign.put("JavaType",".LabelWrapper")
    whatassign.put("DesignerType","Label")
    assignedTypes.Add(whatassign)

    'B4XFloatTextField --> citem02
    whatassign.put("B4XDesigner","citem02")
    whatassign.put("JavaType",".CustomViewWrapper")
    whatassign.put("DesignerType","CustomView")
    assignedTypes.Add(whatassign)
   
    'B4XComboBox --> citem03
    whatassign.put("B4XDesigner","citem02")
    whatassign.put("JavaType",".CustomViewWrapper")
    whatassign.put("DesignerType","CustomView")
    assignedTypes.Add(whatassign)
   
    Dim emptylayout As String= $"{
    "MaterialIcons": false,
    "Variants": [
        {
            "Scale": 1,
            "Height": 600,
            "Width": 600
        }
    ],
    "LayoutHeader": {
        "Version": 5,
        "DesignerScript": [
            "'All variants script\n",
            "'Variant specific script: 600x600,scale=1\n"
        ],
        "GridSize": 10,
        "ControlsHeaders": [
            {
                "JavaType": ".PaneWrapper$ConcretePaneWrapper",
                "DesignerType": "Pane",
                "Name": "Main"
            }
        ],
        "Files": []
    },
    "Data": {
        "parent": "",
        "borderColor": {
            "ValueType": 6,
            "Value": "0xFF000000"
        },
        "drawable": {
            "color": {
                "ValueType": 6,
                "Value": "0xFFF0F8FF"
            },
            "csType": "Dbasic.Designer.Drawable.ColorDrawable",
            "colorKey": "-fx-background-color",
            "type": "ColorDrawable"
        },
        "orientation": "INHERIT",
        "visible": true,
        ":kids": {},
        "csType": "Dbasic.Designer.MetaMain",
        "handleResizeEvent": true,
        "type": ".PaneWrapper$ConcretePaneWrapper",
        "title": "Form",
        "enabled": true,
        "variant0": {
            "top": 0,
            "left": 0,
            "hanchor": 0,
            "width": 200,
            "vanchor": 0,
            "height": 200
        },
        "cornerRadius": {
            "ValueType": 7,
            "Value": 0
        },
        "javaType": ".PaneWrapper$ConcretePaneWrapper",
        "duration": 0,
        "file": "",
        "borderWidth": {
            "ValueType": 7,
            "Value": 0
        },
        "alpha": {
            "ValueType": 7,
            "Value": 1
        },
        "name": "Main",
        "eventName": "MainForm",
        "extraCss": "",
        "tag": ""
    },
    "FontAwesome": false
}"$
   
    Design=emptylayout.As(JSON).ToMap
   
    Dim variants As List=Design.Get("Variants")
    Dim variantlist As Map=variants.Get(0) 'Get list - only one row for my design
    variantlist.Put("Height",mainpane.Height) 'replace with the size of mainpane
    variantlist.Put("Width",mainpane.Width)
   
    Dim LayoutHeader As Map=Design.Get("LayoutHeader")
   
    LayoutHeader.put("GridSize",stepd)    'replace at the right map...
   
    Dim Data As Map = Design.Get("Data")
   
    Dim controls As List=LayoutHeader.Get("ControlsHeaders")
    Dim kids As Map
    kids.Initialize
   
    Log(controls.Size)
    Dim acontrolofthem As Map
    acontrolofthem.initialize
   
    'For k=0 To controls.Size-1  'may be start from 1 - because first object is the frame...
    '    Dim acontrolofthem As Map=controls.Get(k)
    '    Log (k & " " & acontrolofthem.Get("Name"))
    'Next
       
   
    Dim kid As Int =0
   
    For k=0 To listviewcontrols.Items.Size-1 'reading with Z-Order... from back to front
       
        Dim whatis As String=GetfromControlItemProperty(listviewcontrols.Items.Get(k),"citem")
        For i=0 To assignedTypes.Size-1
            Dim whatassign As Map=assignedTypes.Get(i)           
            If whatassign.Get("B4XDesigner")=whatis Then  'B4XDesigner is our designer we are creating...
                acontrolofthem.put("JavaType",whatassign.Get("JavaType"))
                acontrolofthem.put("DesignerType",whatassign.Get("DesignerType"))
                acontrolofthem.put("Name",listviewcontrols.Items.Get(k))
                controls.Add(acontrolofthem)
               
                Dim jp As JSONParser

                jp.Initialize(File.ReadString(File.DirAssets, whatis & ".json"))
                Dim currentkid As Map=jp.NextObject
                currentkid.Put("name",listviewcontrols.Items.Get(k))
                currentkid.Put("eventName",listviewcontrols.Items.Get(k))
               
                'set other properties
                       
                kids.put(kid.As(String).Trim, currentkid)
                kid=kid+1 'next kid
                Exit
            End If
        Next
       
       
    Next
   
    Data.Put(":kids",kids)
   
   
    Design.Put("LayoutHeader", LayoutHeader)
    Design.Put("Variants", variants)
    Design.Put("Data", Data)
    Design.Put("FontAwesome", False)
    Design.Put("MaterialIcons", False)
   
    Log(Design.As(JSON).ToString)

End Sub

replace at 21:04... had a bug at kids... now can convert to bjl right :)
 

Attachments

  • citems.zip
    2.3 KB · Views: 50
Last edited:
Upvote 0

PaulMeuris

Active Member
Licensed User
So i did some testing with your code... modified it a little... and got a good result (see below)...
B4X:
Sub CreateJsonfromDesign() 'As JSON
    Dim Design As Map
    Design.Initialize
  
    Dim assignedTypes As List
    assignedTypes.Initialize
    Dim whatassign As Map
    whatassign.Initialize
  
    'Label Item --> citem01
    whatassign.put("B4XDesigner","citem01") 'B4XDesigner is our designer we are creating...
    whatassign.put("JavaType",".LabelWrapper")
    whatassign.put("DesignerType","Label")
    assignedTypes.Add(whatassign)

    'B4XFloatTextField --> citem02
    whatassign.put("B4XDesigner","citem02")
    whatassign.put("JavaType",".CustomViewWrapper")
    whatassign.put("DesignerType","CustomView")
    assignedTypes.Add(whatassign)
  
    'B4XComboBox --> citem03
    whatassign.put("B4XDesigner","citem03")
    whatassign.put("JavaType",".CustomViewWrapper")
    whatassign.put("DesignerType","CustomView")
    assignedTypes.Add(whatassign)
  
    Dim emptylayout As String= $"{
    "MaterialIcons": false,
    "Variants": [
        {
            "Scale": 1,
            "Height": 600,
            "Width": 600
        }
    ],
    "LayoutHeader": {
        "Version": 5,
        "DesignerScript": [
            "'All variants script\n",
            "'Variant specific script: 600x600,scale=1\n"
        ],
        "GridSize": 10,
        "ControlsHeaders": [
            {
                "JavaType": ".PaneWrapper$ConcretePaneWrapper",
                "DesignerType": "Pane",
                "Name": "Main"
            }
        ],
        "Files": []
    },
    "Data": {
        "parent": "",
        "borderColor": {
            "ValueType": 6,
            "Value": "0xFF000000"
        },
        "drawable": {
            "color": {
                "ValueType": 6,
                "Value": "0xFFF0F8FF"
            },
            "csType": "Dbasic.Designer.Drawable.ColorDrawable",
            "colorKey": "-fx-background-color",
            "type": "ColorDrawable"
        },
        "orientation": "INHERIT",
        "visible": true,
        ":kids": {},
        "csType": "Dbasic.Designer.MetaMain",
        "handleResizeEvent": true,
        "type": ".PaneWrapper$ConcretePaneWrapper",
        "title": "Form",
        "enabled": true,
        "variant0": {
            "top": 0,
            "left": 0,
            "hanchor": 0,
            "width": 200,
            "vanchor": 0,
            "height": 200
        },
        "cornerRadius": {
            "ValueType": 7,
            "Value": 0
        },
        "javaType": ".PaneWrapper$ConcretePaneWrapper",
        "duration": 0,
        "file": "",
        "borderWidth": {
            "ValueType": 7,
            "Value": 0
        },
        "alpha": {
            "ValueType": 7,
            "Value": 1
        },
        "name": "Main",
        "eventName": "MainForm",
        "extraCss": "",
        "tag": ""
    },
    "FontAwesome": false
}"$
  
    Design=emptylayout.As(JSON).ToMap
  
    Dim variants As List=Design.Get("Variants")
    Dim variantlist As Map=variants.Get(0) 'Get list - only one row for my design
    variantlist.Put("Height",Root.Height) 'replace with the size of mainpane
    variantlist.Put("Width",Root.Width)
  
    Dim LayoutHeader As Map=Design.Get("LayoutHeader")
  
    LayoutHeader.put("GridSize",10)    'replace at the right map...
  
    Dim Data As Map = Design.Get("Data")
  
    Dim controls As List=LayoutHeader.Get("ControlsHeaders")
    Dim kids As Map
    kids.Initialize
  
    Log(controls.Size)
    Dim acontrolofthem As Map
    acontrolofthem.initialize
  
    'For k=0 To controls.Size-1  'may be start from 1 - because first object is the frame...
    '    Dim acontrolofthem As Map=controls.Get(k)
    '    Log (k & " " & acontrolofthem.Get("Name"))
    'Next
      
  
    Dim kid As Int = 0
  
    Dim controlnames As List = Array As String("citem01","citem02","citem03")
    For k = 0 To controlnames.Size -1
    Dim whatis As String = controlnames.Get(k)
    Dim whatassign As Map = assignedTypes.Get(k)

'        For i = 0 To assignedTypes.Size -1
'            Dim whatassign As Map=assignedTypes.Get(i)
'            Log(whatassign)
'            If whatassign.Get("B4XDesigner") = whatis Then  'B4XDesigner is our designer we are creating...
                acontrolofthem.put("JavaType",whatassign.Get("JavaType"))
                acontrolofthem.put("DesignerType",whatassign.Get("DesignerType"))
                acontrolofthem.put("Name",controlnames.Get(k))
                controls.Add(acontrolofthem)
              
                Dim jp As JSONParser

                jp.Initialize(File.ReadString(File.DirAssets, whatis & ".json"))
                Dim currentkid As Map=jp.NextObject
                currentkid.Put("name",controlnames.Get(k))
                currentkid.Put("eventName",controlnames.Get(k))
              
                'set other properties
                      
                kids.put(kid.As(String).Trim, currentkid)
                'Log(currentkid.As(JSON).ToString)
                kid=kid+1 'next kid
                'Exit
'            End If
'        Next
    Next
    'Log(kids)
    Data.Put(":kids",kids)
  
  
    Design.Put("LayoutHeader", LayoutHeader)
    Design.Put("Variants", variants)
    Design.Put("Data", Data)
    Design.Put("FontAwesome", False)
    Design.Put("MaterialIcons", False)
  
    Log(Design.As(JSON).ToString)

End Sub
With this subroutine i created a citems.json file.
Then i used my pmtemplates application to convert that JSON file into a .bjl file.
Then i opened the .bjl file in the Visual Designer from the B4J IDE.
The 3 citems appeared at 0,0 so i moved them around a little bit.
1695879252056.png

And then i wrote a few lines of code to load that layout.
B4X:
    Dim pn As Pane
    pn.initialize("")
    pn.LoadLayout("citems")
    Root.AddView(pn,0,0,600,600)
And this is the result:
1695879380626.png

@Magma you are on the right path... still a lot of coding to do... recursive sub to get all the children from a pane for instance as indicated by @William Lancee ...
 
Upvote 0

Magma

Expert
Licensed User
Longtime User
The 3 citems appeared at 0,0 so i moved them around a little bit.
...yes, i didn't set all the properties.. (for that was the rem set the properties) only name and event name...

And yes, the road is long... but is a start
 
Upvote 0
Top