Android Question How to change particular cell value in B4XTable

emexes

Well-Known Member
Licensed User
(Call me psychic, but I think I might be about to upset any programming purists here ;-)

If you fully constructed the list-of-row-arrays data used to create table, and you still have that list-of-arrays intact, then another way you could do this would be to sneakily reach into the table via that list-of-arrays to access and change individual cells, eg this snippet here (from full Sub at bottom of this post):
B4X:
Dim TempRow() As Object    'use this as a handle/pointer to row array to be modified
 
TempRow = TableRowList.Get(3 - 1)    'get a grip on the 3rd row
TempRow(0) = "Three dozen!!!"
 
TempRow = TableRowList.Get(5 - 1)    'get a grip on the 5th row
TempRow(0) = "5 Baker's Dozen"
TempRow(1) = 5 * (12 + 1)
results in this:

upload_2019-6-29_16-18-47.png


THE FULL SUB
B4X:
Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1") 'Load the layout file.
    MainForm.Show
 
    B4XTable1.AddColumn("Wordy", B4XTable1.COLUMN_TYPE_TEXT)
    B4XTable1.AddColumn("Numbery", B4XTable1.COLUMN_TYPE_NUMBERS)
 
    Dim TableRowList As List
 
    TableRowList.Initialize
 
    For I = 1 To 10
        TableRowList.Add( Array((I & " dozen"), I * 12) )
    Next
 
    B4XTable1.SetData(TableRowList)
 
    Dim TempRow() As Object    'use this as a handle/pointer to row array to be modified
 
    TempRow = TableRowList.Get(3 - 1)    'get a grip on the 3rd row
    TempRow(0) = "Three dozen!!!"
 
    TempRow = TableRowList.Get(5 - 1)    'get a grip on the 5th row
    TempRow(0) = "5 Baker's Dozen"
    TempRow(1) = 5 * (12 + 1)

End Sub
 

emexes

Well-Known Member
Licensed User
I just realised that I tested that method in B4J, not in B4A. So if you do use it in B4A, it'll be a useful test of how good these platform-independent libraries are. Feel free to let us know what the result is.

At worst, if this sneaking-in-through-the-back-door method doesn't work in B4A, presumably you can just do another SetData using the updated TableRowList. Bonus: that'll also probably stop our programming purists from having a heart attack.

;-)
 

mangojack

Well-Known Member
Licensed User
I just realised that I tested that method in B4J, not in B4A.
Strangely, the above code works as is in B4J ... ( ie: changes immediately displayed ...)
but B4A required a final second call of B4XTable1.SetData(TableRowList) for the changes to be displayed.
 

jimmyF

Active Member
Licensed User
This is what works for me.

B4X:
If ColumnId = "Description" Then
  Dim RowData As Map = B4XTable1.GetRow(RowId)      
  Dim column As B4XTableColumn = B4XTable1.GetColumn(ColumnId)
  Dim DataA As Map = CreateMap()      
  Dim cell As String = RowData.Get(ColumnId)
  Dim Prefdlg As PreferencesDialog
  Prefdlg.Initialize(Base, "Description", 300dip, 150dip)
  Prefdlg.Title = "New Description"
  Prefdlg.AddMultilineTextItem("Description","",150dip)
  Prefdlg.ItemsBackgroundColor  = xui.Color_White
  Prefdlg.TextColor = xui.Color_Black
  Prefdlg.Theme = PrefDialog.THEME_LIGHT
  Prefdlg.Dialog.PutAtTop = True
  DataA.Put("Description", cell)
      
  Wait For (Prefdlg.ShowDialog(DataA, "OK", "CANCEL")) Complete (Result As Int)
  If Result = xui.DialogResponse_Positive Then
      Dim ans As String =  DataA.Get("Description")
                B4XTable1.sql1.ExecNonQuery2($"UPDATE data SET ${column.SQLID} = ? WHERE rowid = ?"$, Array As String(ans, RowId))
   End If
End If
 

Erel

Administrator
Staff member
Licensed User
If you fully constructed the list-of-row-arrays data used to create table, and you still have that list-of-arrays intact, then another way you could do this would be to sneakily reach into the table via that list-of-arrays to access and change individual cells, eg this snippet here (from full Sub at bottom of this post):
The code you posted is wrong. It only seemed to work because the data is inserted asynchronously and by chance you managed to update it before it was actually inserted to the memory db.

There are two options:
1. Update the data list and call SetData.
2. Update the db directly and call Refresh.
 

emexes

Well-Known Member
Licensed User
The code you posted is wrong. It only seemed to work because the data is inserted asynchronously and by chance you managed to update it before it was actually inserted to the memory db.
Yeah, I was a bit surprised that it worked (and on the first go too). I don't know what the programming equivalent of realpolitik is, but I lean towards what works in practice rather than what works in theory.

Having said that, I inserted a delay between the SetData and the update and, sure enough, it fell over per your explanation.

I did a bit more experimenting, seems that the list passed to SetData has to remain stable for 16 ms (1 frame time?). I could make it crash by setting it to Null after calling SetData, but other than that, it seems to work ok - presumably the garbage collector is held at bay because the B4XTable still has a reference to the otherwise-unused list.

On the bright side: if anybody complains about B4XTables not being initialized correctly when they load up a bunch of them when their app starts, at least we've got a heads-up on what the problem might be.
 
Top