1) I noticed when traversing through the nodes on a form the node has an Id property. But I don't see any way to add that using the Designer. I thought there should be an Id property for the node in the properties pane in the Designer.
Ok, thanks. I was looking at the "XUI View Example - B4J" and when I traversed the nodes, some of the nodes already had values in some of the node.id and node.tag properties that were not put there in code or the designer (see below). I wondered how they got there and I wasn't sure if node.id could be useful for the programmer. If the id property is only in B4J then I will have to use the Tag property instead.
Where did these values come from?
B4X:
i=0
ListOfButtons.Initialize
For Each v As Node In MainForm.RootPane.GetAllViewsRecursive
i=i+1
Log($"(${i}) node.id="${v.Id}" node.Tag="${v.Tag}""$)
If v.Id = "Btn" And v Is Button Then
ListOfButtons.Add(v)
End If
Next
Dim ii As Int = 0
For Each b As Button In ListOfButtons
b.Text = "Num " & ii
ii = ii + 1
Next
'Log (with values in Id and Tag that I can't explain):
(3) node.id="arrow-button" node.Tag=""
(4) node.id="arrow" node.Tag=""
(5) node.id="list-view" node.Tag=""
(6) node.id="virtual-flow" node.Tag=""
(92) node.id="" node.Tag="clear"
(94) node.id="" node.Tag="v"
(104) node.id="" node.Tag="reveal"
(106) node.id="" node.Tag="v"
Is there any way to reference in code the View's Name (or Node's name) that is defined in the Designer without having to duplicate it in the Tag property? Most languages allow finding the view/control via its name. I find it redundant to have it in 2 locations (Name & Tag) because updating the view name means updating the tag as well.
Views don't have names. Views are regular objects and objects don't have names. You can also load the same layout multiple times.
Don't use Node.id.
Avoid adding a counter to a For Each loop.
There are many ways to organize the views.
Tip: use B4XView instead of Node. It is cross platform and in most cases more powerful.
Views don't have names. Views are regular objects and objects don't have names. You can also load the same layout multiple times.
Don't use Node.id.
Avoid adding a counter to a For Each loop.
There are many ways to organize the views.
Tip: use B4XView instead of Node. It is cross platform and in most cases more powerful.
I'm trying to match up views to columns from an SQLite table without writing the names in code (less coding the better). I wanted to create a Map that contained the SQLite ColumnName as the key and the View or view name as the value. Each view that corresponds to a table column would have the table column name as its tag. In Delphi it is trivial because each TDBEdit field for example, would have a Datasource property (points indirectly to table) and the ColumnName property for the table. All of the column data retrieved from the table row gets automatically put into the proper views when a new row is retrieved, and when the record is saved it retrieves the column values from the views and stores it into the table. There is no need to write custom code for every form.
I would have used the tag property for this and build a map:
B4X:
Root.LoadLayout("layout")
For Each v As B4XView In Root.GetAllViewsRecursive
If v.Tag <> Null Then
Dim Tag As String = v.Tag
If Tag.StartsWith("map_") Then MapOfViews.Put(Tag.Substring(4), v)
End If
Next
The tag of all views that should be added to this map should start with map_.
B4X:
Sub GetView(Name As String) As B4XView
Return MapOfViews.Get(Name)
End Sub
I'm obviously doing something wrong because my iteration over Root.GetAllViewsRecursive are returning only 2 views with tags starting with "map" even though every view on the form has such a "map..." tag. I have attached a sample app using your XUI Views Example app. I chose this app because it has a variety of B4XViews in it.
Most of the tags show up as an empty string.
B4X:
Sub BuildViewMap
Private locMsg As String
Log("Loading MapOfViews ---->")
MapOfViews.Initialize
Private locNdx As Int=0
For Each v As B4XView In Base.GetAllViewsRecursive
If v.Tag <> Null Then
locNdx = locNdx + 1 'Counter is for debugging purposes only
Dim Tag As String = v.Tag
If Tag.StartsWith("[") = False Then 'Ignore internal views with tag "[...]"
If Tag.StartsWith("map") Then 'Is this one of our tags?
MapOfViews.Put(Tag, v) 'Put the whole tag in the map (we don't care about the "map" prefix)
locMsg = "*"
Else
locMsg = " "
End If
Log($"${locMsg}Tag(${locNdx})=${Tag} ${GetType(v)}"$)
End If
End If
Next
Log("==================")
Log("MapOfViews: Total Views Loaded=" & (MapOfViews.Size))
For Each locKey As String In MapOfViews.Keys
Log(locKey)
Next
Log("=== End MapOfViews ===")
End Sub
Sub GetView(Name As String) As B4XView
BuildViewMap 'Put here for testing purposes only
Private locB4XView As B4XView
locB4XView = MapOfViews.Get(Name) 'Lets see if we can find the view with tag=Name
Return locB4XView
End Sub
Private Sub btnExecute_Click
Private locSearch As String="mapB4XFloatTextField1" 'Look for any tag string
Private locViewFnd As B4XView
locViewFnd = GetView(locSearch) 'We will look for one of the views using locSearch
If locViewFnd.IsInitialized Then 'Did we find the view with the tag?
Log("View Found: " & locViewFnd.Tag)
Else
Log("View NOT FOUND: " & locSearch)
End If
End Sub
Here is the log file when it iterates through the views:
Sub BuildViewMap
Dim SwiftButtons As Map 'should be a global variable
SwiftButtons.Initialize
For Each v As B4XView In Base.GetAllViewsRecursive
If v.Tag Is SwiftButton Then
Dim sf As SwiftButton = v.Tag
'if you like to filter it by the tag then do it here, with sf.Tag
SwiftButtons.Put(sf.Tag, sf)
Else if v.Tag Is RoundSlider Then
'....
End If
Next
End Sub