ListView GetItem returns last row only

pkos

New Member
Licensed User
Longtime User
Hello, this is a simple example I made to mimic ListView.GetItem behaviour:
B4X:
Sub Process_Globals
   Type twostrings (a As String , b As String)   
End Sub
Sub Globals
End Sub
Sub Activity_Create(FirstTime As Boolean)
If firsttime Then
   Dim lv As ListView 
   lv.Initialize ("")   
   Dim ts As twostrings
    ts.Initialize
   
   'add two rows
   ts.a = "a_row_1"
   ts.b = "b_row_1"
   lv.AddTwoLines2(ts.a ,ts.b , ts)
   ts.a = "a_row_2"
   ts.b = "b_row_2"
   lv.AddTwoLines2(ts.a ,ts.b , ts)

   'read listview row count
   Log ("lv.size=" & lv.Size)
   
   'read listview row data
   i = 0
   Do While i < lv.Size      
      Log ("lv.GetItem=" & lv.GetItem(i))
      
      Dim ts As twostrings 
      ts.Initialize 
      ts = lv.GetItem(i)
      Log ("row number " & i & _
         " ,stringA=" & (ts.a) & _
         " ,stringB=" & (ts.b))
         
      i = i + 1
   Loop
End If
End Sub
Sub Activity_Resume
End Sub
Sub Activity_Pause (UserClosed As Boolean)
End Sub
At runtime on log window the result is:

** Activity (main) Create, isFirst = true **
lv.size=2

lv.GetItem=[b=b_row_2, a=a_row_2, IsInitialized=true]
row number 0 ,stringA=a_row_2 ,stringB=b_row_2

lv.GetItem=[b=b_row_2, a=a_row_2, IsInitialized=true]
row number 1 ,stringA=a_row_2 ,stringB=b_row_2

** Activity (main) Resume **

There is nowere the 1st row (row_1) of listview.
Can you see where the code error is? :sign0144:
 

pkos

New Member
Licensed User
Longtime User
Thanks Erel, this is the corrected code

B4X:
Sub Activity_Create(FirstTime As Boolean)
If firsttime Then
   Dim lv As ListView 
   lv.Initialize ("")   
   Dim ts As twostrings
   ts.Initialize 
   
   'add two rows
   ts.a = "a_row_1"
   ts.b = "b_row_1"
   lv.AddTwoLines2(ts.a ,ts.b , ts)
   Dim ts As twostrings
   ts.a = "a_row_2"
   ts.b = "b_row_2"
   lv.AddTwoLines2(ts.a ,ts.b , ts)

   'read listview row count
   Log ("lv.size=" & lv.Size)
   
   'read listview row data
   i = 0
   Do While i < lv.Size      
      Log ("lv.GetItem=" & lv.GetItem(i))
      
      Dim ts As twostrings 
      ts.Initialize 
      ts = lv.GetItem(i)
      Log ("row number " & i & _
         " ,stringA=" & (ts.a) & _
         " ,stringB=" & (ts.b))
         
      i = i + 1
   Loop
End If
End Sub
 
Upvote 0

netsistemas

Active Member
Licensed User
Longtime User
Redefinir la variable.

Me ha costado, pero he visto la diferencia.

Hay que definir la variable que se carga cada vez.
En el código correcto existen 2 DIM

Dim ts As Twostrings
ts.First = Nombre
ts.Second = Telefono
Listview1.AddTwoLines2 (Nombre, Telefono, ts) ',Cliente)

y de nuevo otro DIM.

----------
You must define the variable 'n' times. Not in a GLOBAL area definition.
 
Upvote 0

davepamn

Active Member
Licensed User
Longtime User
1. I generate a listview member called
Dim listViewTrucks As ListView

2. Next, I define a type call twostring
Type twostrings (aLabel As String , bLabel As String)

3. Last, I process items into
Dim ts As twostrings
ts.Initialize
B4X:
  For i = 0 To MenuItems.Size - 1
oRowMap=MenuItems.Get(i)
ts.aLabel=oRowMap.Get("station")
ts.bLabel=oRowMap.Get("description")
listviewStations.AddTwoLines2(ts.aLabel,ts.bLabel,ts)
  Next

For i=0 To listviewStations.Size-1
ts.Initialize
ts=listviewStations.GetItem(i)
Log ("row number " & i &  " ,stringA=" & (ts.aLabel) & " ,stringB=" & (ts.bLabel)) 
Next

Output problem
StringA and StringB are blank
 
Last edited:
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
B4X:
For i = 0 To MenuItems.Size - 1
  Dim ts As twostrings
  ts.Initialize
  oRowMap=MenuItems.Get(i)
  ts.aLabel=oRowMap.Get("station")
  ts.bLabel=oRowMap.Get("description")
  listviewStations.AddTwoLines2(ts.aLabel,ts.bLabel,ts)
Next

If you dim outside the for loop you only create ONE instance of ts... On each iteration in your forloop you "overwrite" the content with the new one. You then put THIS instance into your listview. But you do not put the values you expected. You insert an REFERENCE to the DIMmed ts (outside the for loop)...
On next iteration you change ts, put it into the listview (again the same referenced ts as before. ALL TWO listviewentries now have the same content.
On next iteration the same and same and same and same...

Solution:
You have to put the dim and initialize inside the for loop to create a NEW instance of ts for each interation which you then put into listviewStations. This way you put a reference to the DIMmed ts (inside for loop) into your Listview. For each entry an own instance of ts and therefor changing content in ts :)

This behavioure is part of ObjectOrienttedProgramming
 
Last edited:
Upvote 0

davepamn

Active Member
Licensed User
Longtime User
That works, but it is not intuitive why moving the dim ts as twostrings inside the loop makes the code work

However the ItemClick is not working.

The ts returns blank for aLabel and bLabel

Sub listviewStations_ItemClick (Position As Int, Value As Object)
Dim ts As twostrings
ts.Initialize
ts=listviewStations.GetItem(Position)
lblOriginStation.Text=ts.aLabel
lblStationDescription.Text=ts.bLabel
End Sub
 
Upvote 0

davepamn

Active Member
Licensed User
Longtime User
The Value as Object has two fields

aLabel and bLabel and they are assigned blank values.

Do I need a different event handler?

In the previous code, I was able to see the contents of aLabel and bLabel by iterating using getitem.

Why does the event handler lose the values that were in the listview?
 
Upvote 0

davepamn

Active Member
Licensed User
Longtime User
I discovered the problem. Getitem changes the reference count and causes the structure to return null. When I comment out the following code, the app worked.
B4X:
For i=0 To listviewStations.Size-1
ts.Initialize
ts=listviewStations.GetItem(i)
Log ("row number " & i & " ,stringA=" & (ts.aLabel) & " ,stringB=" & (ts.bLabel))
Next
 
Last edited:
Upvote 0

davepamn

Active Member
Licensed User
Longtime User
No. You dont have TWO values. You can put only ONE "Value"

B4X:
listviewStations.AddTwoLines2(ts.aLabel,ts.bLabel,ts)

"ts" is the VALUE. ts.alabel is the text for line 1, ts.blabel the text for line 2.


I agree TS is the type cast and has aLabel and bLabel as structure elements
 
Upvote 0

davepamn

Active Member
Licensed User
Longtime User
Here is what worked
B4X:
For i = 0 To MenuItems.Size - 1
        Dim ts As twostrings
        ts.Initialize
        oRowMap=MenuItems.Get(i)
        ts.aLabel=oRowMap.Get("station")
        ts.bLabel=oRowMap.Get("description")
        listviewStations.AddTwoLines2(ts.aLabel,ts.bLabel,ts)
    Next

'Don't use getitem because it deferences the object

Sub listviewStations_ItemClick (Position As Int, Value As Object)
    Dim ts As twostrings
    ts.Initialize
    ts=Value
    lblOriginStation.Text=ts.aLabel
    lblStationDescription.Text=ts.bLabel
End Sub
 
Last edited:
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
You can have a look at this example.

For you it could look like

B4X:
Dim retmap As Map
retmap.Initialize
retmap.Put("tag","TagValue"&i)
retmap.Put("itemID","ItemID"&i)
retmap.Put("name","ItemName"&i)
retmap.Put("line1",ts.alabel)
retmap.Put("line2",ts.blabel)
retmap.Put("ts",ts)

and like in example you can get out the "ts" from the one and only Value. But this value is a MAP :)
 

Attachments

  • listviewtest.zip
    7.5 KB · Views: 397
Upvote 0

mangojack

Expert
Licensed User
Longtime User
@davepamn .. to make your code easier to read use code tags .. See attached image .
 

Attachments

  • Code Tags.JPG
    Code Tags.JPG
    13.1 KB · Views: 367
Upvote 0
Top