B4J Question B4XTable and CheckBox - problem with updating

Elric

Well-Known Member
Licensed User
Hello!

I'm trying to insert a checkbox in some B4XTable cells. No problem about that.

The problem is populating the B4XTable from a DB with some value that need to change the status of a checkbox: there is a loop in updating with continuously change of checkbox status.

I've tried to substitute the checkbox with a B4XSwitch but... I will ask for that in another thread maybe.

Anyone may help?

Thanks!

Attached a small project where the data are directly set in a list but should come from a DB. See post #8.
 
Last edited:

kimstudio

Active Member
Licensed User
Longtime User
In B4J, a behavior of view I found is if you change the view status in application actively by writing a program line, the changed event will fire. In some other languages only user changes the status by user interface the event will fire.

This will cause a issue especially in initialization phase, you set the initial status of view like set checkbox.checked = true, but the checkbox_checkedchange will fire, this event may cause some loop or unwant results.

To solve this I usually dim a global variable to mark the mode of view - to indicate whether the event is fired by application or by user, the view.tag can also be used for this purpose. In event first check this variable to decide whether just return or run the event logic. It has some risks though.
 
Upvote 0

Elric

Well-Known Member
Licensed User
Thank you @kimstudio.

I've tried to manage this issue in two ways.
1. Set the checkbox.enabled = false before changing its state and then checkbox.enabled = true.
2. (as in the small project attached) Set a global boolean variable (ynExecuteChkBox) and setting it as False at beginning of "B4XTable1_DataUpdated" event and True ad the end of "B4XTable1_DataUpdated". Then
B4X:
Private Sub chkboxTable_CheckedChange(Checked As Boolean)
    
    If ynExecuteChkBox Then
        ...
        ...
        ...
    End If
    
End Sub
.

Both ways are no success.
 
Upvote 0

kimstudio

Active Member
Licensed User
Longtime User
1. Set the checkbox.enabled = false before changing its state and then checkbox.enabled = true.
This enabled = true or false doesn't affect event fire.

ynExecuteChkBox

Try this:

B4X:
Private Sub B4XTable1_DataUpdated
    
    ynExecuteChkBox = False
    
    Private myynChecked As Boolean
    
    For i = 0 To B4XTable1.VisibleRowIds.Size - 1
        Dim p As B4XView = editCol.CellsLayouts.Get(i + 1)
        p.GetView(1).Visible = B4XTable1.VisibleRowIds.Get(i) > 0
        p.GetView(2).Visible = p.GetView(1).Visible

        Dim p As B4XView = chboxColumn1.CellsLayouts.Get(i + 1)
        p.GetView(1).Visible = B4XTable1.VisibleRowIds.Get(i) > 0
        
        If lstValueWillComeFromDB1.Size - 1 > i Then
            If lstValueWillComeFromDB1.Get(i) = "" Then
                myynChecked = False
            Else
                myynChecked = True
            End If
            p.GetView(1).Tag = 0  'use tag
            p.GetView(1).Checked = myynChecked
        End If
        
        Dim p As B4XView = chboxColumn2.CellsLayouts.Get(i + 1)
        p.GetView(1).Visible = B4XTable1.VisibleRowIds.Get(i) > 0
        
        If lstValueWillComeFromDB2.Size - 1 > i Then
            If lstValueWillComeFromDB2.Get(i) = "" Then
                myynChecked = False
            Else
                myynChecked = True
            End If
            p.GetView(1).Tag = 0  'use tag
            p.GetView(1).Checked = myynChecked
        End If
    Next
    
    ynExecuteChkBox = True
'    B4XTable1.Refresh
End Sub


'---
Private Sub chkboxTable_CheckedChange(Checked As Boolean)
    If Sender.As(CheckBox).Tag.As(Int) == 0 Then 
        Sender.As(CheckBox).Tag = 1
        Return
    End If
...
 
Upvote 0

Elric

Well-Known Member
Licensed User
Nearly there...

I need to click two times onto ChkBox to change the original value in the B4XTable (but only one click to restore the original value) with this code:
B4X:
Private Sub chkboxTable_CheckedChange(Checked As Boolean)
    
    If Sender.As(CheckBox).Tag.As(Int) == 0 Then
        Sender.As(CheckBox).Tag = 1
        Log("Auto")
        Return
    Else
        Log("User Click")
        Private RowId As Long = GetRowId(Sender)
        Private ColumnId As String = GetColumnId(Sender)
        Private myValue As String
    
        Private column As B4XTableColumn
    
        RowId = RowId - 1 ' Only because we have a list instead of a DB
    
        Select ColumnId
            Case chboxColumn1.Id
                column = B4XTable1.GetColumn(chboxColumn1.Id)
                If lstValueWillComeFromDB1.Get(RowId) = "" Then
                    lstValueWillComeFromDB1.set(RowId, strCheckBoxStateTrue)
                    myValue = strCheckBoxStateTrue
                Else
                    lstValueWillComeFromDB1.Set(RowId, strCheckBoxStateFalse)
                    myValue = ""
                End If
            Case chboxColumn2.Id
                column = B4XTable1.GetColumn(chboxColumn2.Id)
                If lstValueWillComeFromDB2.Get(RowId) = "" Then
                    lstValueWillComeFromDB2.set(RowId, strCheckBoxStateTrue)
                    myValue = strCheckBoxStateTrue
                Else
                    lstValueWillComeFromDB2.set(RowId, strCheckBoxStateFalse)
                    myValue = ""
                End If
        End Select
    
        RowId = RowId + 1 ' Only because we have a list instead of a DB
    
        Try
            B4XTable1.sql1.ExecNonQuery2($"UPDATE data SET ${column.SQLID} = ? WHERE rowid = ?"$, Array As String(myValue, RowId))
        Catch
            Log(LastException)
        End Try
    
        B4XTable1.Refresh
    End If

End Sub
 
Upvote 0

DarkoT

Active Member
Licensed User
Maybe this will help:

Example:
' declaration
Private colChkBox As B4XTableColumn
Private tblDogodki as B4XTable

Private Sub InitGrid
    tblDogodki.Clear
    
    tblDogodki.AddColumn("ID", tblDogodki.COLUMN_TYPE_TEXT)
    colChkBox = tblDogodki.AddColumn("Prip", tblDogodki.COLUMN_TYPE_NUMBERS)
    tblDogodki.AddColumn("Datum", tblDogodki.COLUMN_TYPE_TEXT)
    tblDogodki.AddColumn("StrojID", tblDogodki.COLUMN_TYPE_NUMBERS)
    tblDogodki.AddColumn("Stroj", tblDogodki.COLUMN_TYPE_TEXT)
    tblDogodki.AddColumn("OddelekID", tblDogodki.COLUMN_TYPE_NUMBERS)
    tblDogodki.AddColumn("Oddelek", tblDogodki.COLUMN_TYPE_TEXT)
    tblDogodki.AddColumn("DobaviteljID", tblDogodki.COLUMN_TYPE_NUMBERS)
    tblDogodki.AddColumn("Dobavitelj", tblDogodki.COLUMN_TYPE_TEXT)
    tblDogodki.AddColumn("Vzdrževalec", tblDogodki.COLUMN_TYPE_TEXT)
    tblDogodki.AddColumn("Telefon", tblDogodki.COLUMN_TYPE_TEXT)
    tblDogodki.AddColumn("Email", tblDogodki.COLUMN_TYPE_TEXT)
    tblDogodki.AddColumn("DogodekID", tblDogodki.COLUMN_TYPE_NUMBERS)
    tblDogodki.AddColumn("Dogodek", tblDogodki.COLUMN_TYPE_TEXT)
    tblDogodki.AddColumn("Opis", tblDogodki.COLUMN_TYPE_TEXT)
    tblDogodki.AddColumn("Datum spremembe", tblDogodki.COLUMN_TYPE_TEXT)
    tblDogodki.AddColumn("Uporabnik", tblDogodki.COLUMN_TYPE_TEXT)
    
    tblDogodki.RowHeight = 40dip
    tblDogodki.EvenRowColor = xui.Color_RGB(169,192,201)
    tblDogodki.OddRowColor = xui.Color_RGB(226,243,247)
    
    tblDogodki.SearchVisible = True
    tblDogodki.MaximumRowsPerPage = 10
    tblDogodki.BuildLayoutsCache(tblDogodki.MaximumRowsPerPage)
    tblDogodki.Refresh
    
    ' enable checkbox
    For i = 1 To colChkBox.CellsLayouts.Size - 1
        Dim parent As B4XView = colChkBox.CellsLayouts.Get(i)
        Dim panel As B4XView = xui.CreatePanel("")
        parent.AddView(panel, 0, 0, parent.Width, parent.Height)
        panel.LoadLayout("CheckBox")
    Next
End Sub

' FullfillGrid
Private Sub RefreshGrid(BaseStatus As Int)

    ' main query za prikaz
    Query = $"select dDogIdent, (select case when count(*) > 0 then cast(1 as bit) else cast(0 as bit) end from dokLinkedObjects where dokLinkType = 'pgdogodki' and doklinkCode = dDogIdent) as priponke,
                     dDogDatum, dDogDobavitelj, sifSupplierName, dDogVzdrzevalec, dDogVzdrEmail, dDogVzdrTelefon, dDogStroj, SifMachineDescription,
                     dDogOddelek, SifOddelekDescription, dDogDogodek, sifVrDogDescription, 
                     dDogOpis, dDogLinkDokument, dDogLinkPicture, dDogDatSpr, dDogLastUser, dDogIsDeleted
             from dokDogodki inner join SifMachine on SifMachineID = dDogStroj
                             inner join SifOddelki on SifOddelekID = dDogOddelek
                             inner join sifVrsteDogodkov on sifVrDogID = dDogDogodek
                             inner join sifSuppliers on sifSupplierID = dDogDobavitelj
             where isnull(dDogIsDeleted,0) = ${BaseStatus}
             Order by dDogIdent desc"$
    Dim rs As ResultSet = Main.MsSql.ExecQuery(Query)
    Dim row As List
    row.Initialize
    

    Do While rs.NextRow
        row.Add(Array(rs.GetInt("dDogIdent"),[B] rs.GetInt("priponke")[/B], rs.GetString("dDogDatum"), rs.GetInt("dDogStroj"), rs.GetString("SifMachineDescription"), rs.GetInt("dDogOddelek"), rs.GetString("SifOddelekDescription"), _
                rs.GetInt("dDogDobavitelj"), rs.GetString("sifSupplierName"), rs.GetString("dDogVzdrzevalec"), rs.GetString("dDogVzdrTelefon"), rs.GetString("dDogVzdrEmail"), _
                rs.GetInt("dDogDogodek"),  rs.GetString("sifVrDogDescription"), rs.GetString("dDogOpis"), rs.GetString("dDogDatSpr"), rs.GetString("dDogLastUser") ))
    Loop
    rs.Close
    
    tblDogodki.SetData(row)
    tblDogodki.Refresh
    
End Sub
    
' Insert CHECKBOX for all records which has status = 1
' this is column1 (first column is col0)
Private Sub tblDogodki_DataUpdated
    
    For i = 0 To tblDogodki.VisibleRowIds.Size - 1
        Dim rowid As Long = tblDogodki.VisibleRowIds.Get(i)
        Dim Item As Map = tblDogodki.GetRow(rowid)
        Dim p As B4XView = colPriponke.CellsLayouts.Get(i + 1)
        Dim p1 As B4XView = p.GetView(1)
        Dim chk As B4XView = p1.GetView(0) 'first view is the label
        
        chk.Visible = rowid > 0
        chk.Tag = rowid
        If Item.Size > 0 Then
            If Item.Get("Prip").As(Int) = 1 Then chk.Checked = True Else chk.Checked = False
        End If
    Next
    
End Sub
 
Upvote 0

Elric

Well-Known Member
Licensed User
Thank you @DarkoT.

I've tried to adapt your code into my small project (here attached and renamed as "2") but the checkboxes are not visible and I don't understand why... :(
 
Last edited:
Upvote 0

Elric

Well-Known Member
Licensed User
Thank you for your time guys!

I solved:
  • setting the Checked status during the creation of control
  • putting a boolean control in CheckBox event
  • with a Sleep(1) between the B4XTable refresh and the change of boolean control.
Unfortunately, this work only if I need to work only with one page of B4XTable.
 

Attachments

  • B4XTableAndCheckBox.zip
    10.5 KB · Views: 76
Last edited:
Upvote 0

Elric

Well-Known Member
Licensed User
After spent some hours trying "to make a square works as circle", I've opted for a (banal) workaround: use no CheckBox but a Button, that appears as a CheckBox changing its text: unchecked with FontAwesome Chr(32) and checked with FontAwensome Chr(0xF00C).
 
Upvote 0
Top