B4J Code Snippet ListView based on FXML scene with image download

Hi,

I was looking for a method where I could dynamically adjust the layout of a listview and re-use the code for different projects.

While going through the forum I found an example by Eerel (imagedownloader) where he uses FX Scene builder and an imagedownloader sub to generate a listview with images and 1 label.

i;ve made some small adjustments to make it more dynamically. Basically you can specify any fxml scene with an imageview and unlimited number of labels.

1. Create a FXScene with an anchorpane. Within the anchorpane add an imageview and name the ID "ImageView1".
2. Add labels to the anchorpane and name the ID's of the labels. The ID names will be used as KEY in the MAPS
3. In your code create a list.
4. Create a map per item you want to add to the listview
Each map within the list should contain:
  1. a link to an image
  2. 1 or more values for the labels. The key should correspond to the label id. The mapvalue will be written to the label.text.
5. Add all items to the list
6. Call initilize of the fxlistviewdownloadimage with the list, FXML name and the keyname which holds the link to the image.
7. call CreateListview
8. The result is a listview, add it somewhere in your project.

By creating scene's with the scenebuilder and aligning the label ID"s with your code you are now able to create nice listviews on the spot without having to code a lot!

Main

B4X:
#Region  Project Attributes
    #MainFormWidth: 400
    #MainFormHeight: 400
   
#End Region

Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form

    Private ListView1 As ListView
    'Dim Label1 As Label

    Private SearchTitleView As FXListViewWithDownloadImage
    Private lists As List

End Sub

Sub AppStart (Form1 As Form, Args() As String)

    MainForm = Form1
    MainForm.Show
    lists.Initialize
   
    Dim m As Map
    m.Initialize
    m.Put("link", "https://file.ac/v4kCnG6NWME//MgAxADIAMgA1ADQA.jpg")
    m.Put("Title", "Walking Dead") 'make sure one label matches the key
    m.Put("Publisher", "Image")
    m.Put("Year", "2012")
    m.Put("Volume", "Volume #1")
    m.Put("blabla", "This will not become visible") 'as I do not have a label with ID blabla the value of this will not become visible.

    lists.Add(m)
   
    Dim m As Map
    m.Initialize
    m.Put("link", "https://file.ac/Nhw0QyOKfG4/MQA0ADQANgA5ADkA.jpg")
    m.Put("Title", "Walking Dead 2 ")
    m.Put("Publisher", "Image 2 ")
    m.Put("Year", "2012")
    m.Put("Volume", "Volume #2")
    lists.Add(m)
   
    Dim m As Map
    m.Initialize
    m.Put("link", "https://file.ac/sCnyZRlh41g/OAAyADIANAA4ADAA.jpg")
    m.Put("Title", "Walking Dead 3 ")
    m.Put("Publisher", "Image 3")
    m.Put("Year", "2012  ")
    m.Put("Volume", "Volume #3")
    lists.Add(m)

    SearchTitleView.Initialize(lists, "SearchResultTitle1", "link")
   
    ListView1=SearchTitleView.CreateListview
   
    MainForm.RootPane.AddNode(ListView1 ,0 ,0, 0, 0)
    MainForm.RootPane.SetAnchors(ListView1, 0, 0, 0, 0) 'The ListView will fill the entire form

End Sub


FXListViewWithDownloadImage class

B4X:
Sub Class_Globals
    Private fx As JFX
   
    Private c_ListWithMaps As List
    Private c_ListView1 As ListView
    Private c_itemlayout As String
    Private c_LinkKey As String
   
    Dim ImageView1 As ImageView
   
End Sub

'Initializes the object. You can add parameters to this method if needed.
'Provide a list containing maps.
'One of the key's within the map should contain a link - specify the keyname as linkkey.
'The remaining keys will be matched to the label ID's of the FX Scene. The label.text will be updated with the value of the keymap.
'ItemLayout is the FXML document name.
'LinkKey is the name of the key containing the image link
Public Sub Initialize(l As List, ItemLayout As String, LinkKey As String)

    c_ListWithMaps.Initialize
    c_ListView1.Initialize("listView1")
   
    c_ListWithMaps=l
    c_itemlayout = ItemLayout
    c_LinkKey=LinkKey
   
End Sub

Public Sub CreateListview() As ListView
   
    BuildItems(c_ListWithMaps)
   
    Return c_ListView1
   
End Sub

Public Sub UpdateListView(l As List, view As ListView) As ListView
   
    c_ListWithMaps=l
    c_ListView1=view
    BuildItems(c_ListWithMaps)
   
    Return c_ListView1
   
End Sub

Private Sub  BuildItems (links As List)
   
    Dim DownloadMap As Map
    DownloadMap.Initialize
   
    c_ListView1.Items.Clear
   
    For Each m As Object In c_ListWithMaps
       
        'the list may contain other types which we don't need now.
       
        If m Is Map Then
           
            Dim m1 As Map = m
            Dim link As String
            Dim p As AnchorPane
       
            'init
            p.Initialize("")
            p.LoadLayout(c_itemlayout)
       
            'get link
            link = m1.Get(c_LinkKey)
       
            'iterate through the remainder of the keys within the map
            For Each k As String In m1.Keys
                'ignore the link key as we already retrieved it! and loop through ALL nodes to find matching labels.
                If k <> c_LinkKey Then
                    For Each n As Node In p.GetAllViewsRecursive
                        'check if the found node is a label and the key matches the id set to the label
                        If n Is Label And n.Id = k Then
                            'set the textvalue to the label
                            Dim label1 As Label = n
                            label1.Text=m1.Get(k)
                            n=label1
                        End If
                    Next
                End If
            Next
       
            'Add the

            c_ListView1.Items.Add(p)

            DownloadMap.Put(ImageView1, link)
        End If
    Next
   

    'download the images
    Dim id As ImageDownloader
    id.Initialize
    id.Download(DownloadMap)
   

End Sub

ImageDownloader class (Unchanged)
B4X:
Sub Class_Globals
    Private cache As Map
    Private tasks As Map
    Private ongoingTasks As Map
End Sub

Public Sub Initialize
    tasks.Initialize
    cache.Initialize
    ongoingTasks.Initialize
End Sub


Public Sub Download (ImageViewsMap As Map)
    For i = 0 To ImageViewsMap.Size - 1
        tasks.Put(ImageViewsMap.GetKeyAt(i), ImageViewsMap.GetValueAt(i))
        Dim link As String = ImageViewsMap.GetValueAt(i)
        If cache.ContainsKey(link) Then
           
            Dim iv As ImageView = ImageViewsMap.GetKeyAt(i)
            iv.SetImage(cache.Get(link))
           
        Else If ongoingTasks.ContainsKey(link) = False Then
           

                ongoingTasks.Put(link, "")
                Dim j As HttpJob
                j.Initialize(link, Me)
                j.Download(link)

        End If
    Next
End Sub

Sub JobDone(Job As HttpJob)
    ongoingTasks.Remove(Job.JobName)
    If Job.Success Then
        Dim bmp As Image = Job.GetBitmap
        cache.Put(Job.JobName, bmp)
        If tasks.IsInitialized Then
            For i = 0 To tasks.Size - 1
                Dim link As String = tasks.GetValueAt(i)
                If link = Job.JobName Then
                    Dim iv As ImageView = tasks.GetKeyAt(i)
                    iv.SetImage(bmp)
                End If
            Next
        End If
    Else
        Log("Error downloading image: " & Job.JobName & CRLF & Job.ErrorMessage)
    End If
    If ongoingTasks.Size = 0 Then tasks.Clear
    Job.Release
End Sub
 

Attachments

  • FXControls.zip
    3.8 KB · Views: 378
Top