B4A Library [Class] Flexible Table

klaus

Expert
Licensed User
Longtime User
The Table class needs following libraries:
JavaObject internal
SQL internal
StringUtils internal
ScrollViewd2D additional.
You need to download the ScrollView2D.jar and ScrollView2D.xml files and copy them into the AdditionalLibraries\B4X folder.
Check these libraries in the Libraries Manager tab in the IDE.
For explanations about libraries, you may have a look HERE.
 

Oscarin

Member
Thanks, but I ended up using

SD FlexGrid (Table) library​

 

RB Smissaert

Well-Known Member
Licensed User
Longtime User
Using this class, still on version 2.26 as I made several modifcations of the code.
There is a bug to do with the Sub AddRow that can cause a serious slowdown of loading a large table.

The last few lines of that Sub should be:

B4X:
    If cShowStatusLine Then
        If (lblStatusLine.IsInitialized And enableStatusLineAutoFill) Then setStatusLine(Data.Size & " rows") ' should this be automatic ?
    End If

Omitting: If cShowStatusLine Then
Means the status label is updated for every row of the provided data, even if you don't want the status label, so even if cShowStatusLine = False

Also these lines:

[CODE
SV2.Panel.Height = Data.Size * cRowHeight
SVF.Panel.Height = SV2.Panel.Height
updateIPLocation
[/CODE]

I think, can be taken out of the Sub AddRow and be added instead to the end of the code in ShowRow, with a small performance gain.

Unless I am mistaken the above still applies to the latest version. 3.30.

RBS
 

klaus

Expert
Licensed User
Longtime User
Unless I am mistaken the above still applies to the latest version. 3.30.
It is still there.

Have you tested it ?
ShowRow is called many times during scrolling, do you see any scroll performance loss ?
How many rows are you loading ?
 

RB Smissaert

Well-Known Member
Licensed User
Longtime User
It is still there.

Have you tested it ?
ShowRow is called many times during scrolling, do you see any scroll performance loss ?
How many rows are you loading ?
Yes, tested and all working fine.
As said, the main thing is to do with cShowStatusLine.

RBS
 

RB Smissaert

Well-Known Member
Licensed User
Longtime User
OK, will post.

RBS
This is all the code to do with the table class and outside my current table class:

In Main:
---------------------------

B4X:
Sub tbl_Cell_Click(oTbl As Table, RC As RowCol)
    
    strClickedTable = oTbl.Panel.Tag
    
    Select strClickedTable
        Case "tblMeds"
            iMedListIndex = RC.Row
        Case "tblIssues"
            iIssueListIndex = RC.Row
            strSelectedIssueDrug = oTbl.GetValue(1, iIssueListIndex)
        Case "tblIssuesDistinct"
            iIssueListIndex = RC.Row
        Case "tblValues"
            strClickedValueDate = oTbl.GetValue(0, RC.Row)
            strClickedValueName = oTbl.GetValue(1, RC.Row)
            
            'dClickedValue is only used for if altering values
            '-------------------------------------------------
            Try
                dClickedValue = oTbl.GetValue(2, RC.Row)
            Catch
                dClickedValue = 0
            End Try
            iNum_Values_RowID = tblValues.GetValue(6, RC.Row)
        Case "tblFilteredValues"
            strClickedValueDate = oTbl.GetValue(0, RC.Row)
            strClickedValueName = oTbl.GetValue(RC.Col, RC.Row)
            
            'dClickedValue is only used for if altering values
            '-------------------------------------------------
            Try
                dClickedValue = oTbl.GetValue(RC.Col, RC.Row)
            Catch
                dClickedValue = 0
            End Try
            iNum_Values_RowID = oTbl.GetValue(RS_FilteredValues.ColumnCount - 1, RC.Row)
        Case "tblSavedSQL"
            iSavedSQLRow = RC.Row
        Case "tblFolders"
            Dim bTblFoldersMultiSelect As Boolean = oTbl.SelectedRows.Size > 1
            btnDefaultFolder.Visible = (bTblFoldersMultiSelect = False)
        Case "tblPatsAtAddress"
            lblAddress.Text = AddressFromID(oTbl.GetValue(0, RC.Row))
    End Select
    
    If bCollectTableCellsForSQLInClause Then
        oListTableCells.Add(oTbl.GetValue(RC.Col, RC.Row))
    End If
    
End Sub

Sub tbl_Cell_LongClick(oTbl As Table, RC As RowCol)
    
    Select oTbl.Panel.tag
        Case "tblValues", "tblUniqueValues", "tblFilteredValues", "tblMeds", "tblIssues", "tblIssuesDistinct", "tblIssuesSingle", _
             "tblProblems", "tblBP", "tblAppointments", "tblReferrals", "tblConsultations", "tblSavedSQL", "tblRegHistory", _
             "tblDiary", "tblVaccinations"
            ShowTableCell(oTbl, RC, 2)
        Case "tblDialog"
            If RC.Col > 0 Then
                ShowTableCell(oTbl, RC, 2)
            Else
                LoadPatientFromTable(oTbl, RC)
            End If
        Case "tblPatientList", "tblPatsAtAddress", "tblPats", "tblSQLResult", "tblPreviousPatients"
            LoadPatientFromTable(oTbl, RC)
    End Select
    
End Sub

In a code module called General:
---------------------------------------------

B4X:
Sub Process_Globals

    Public mapAlteredTableRowColour As Map
    Public mapAlteredTableTextColour As Map
    Public mapArrAlteredRowColour As Map
    Public mapArrAlteredRowTextColour As Map
    
    Public mapRowsItalic As Map
    Public mapArrRowsItalic As Map

    Public iMinSortThreshold As Int

    Public iMaxColumnWidth As Int
    Public bMultiColumnSort As Boolean

    Public bSortTableCaseInsensitive As Boolean

    Private ExcelUnixDiff As Long = 25569       'days between Jan 01 1900 and Jan 01 1970
    Private DaySecs As Long = 86400             'number of seconds in a day
    Private DayMiliSecs As Long = 86400000      'number of milli-seconds in a day
    
    Public bAllowOnlyRealXLDates As Boolean
    Public strTableDateExample As String
    Public strTableDateFormat As String

End Sub

Sub Init_General
    
     mapAlteredTableRowColour.Initialize
    mapAlteredTableTextColour.Initialize
    mapArrAlteredRowColour.Initialize
    mapArrAlteredRowTextColour.Initialize
    
    mapRowsItalic.Initialize
    mapArrRowsItalic.Initialize
    
End Sub

Public Sub ExcelDate2Age(iExcelDate As Int) As Int
    
    Dim lTicks As Long
    Dim iYear As Int
    Dim iMonth As Int
    Dim iDay As Int
    Dim iAge As Int
    
    lTicks = ExcelDate2Ticks(iExcelDate)
    iYear = DateTime.GetYear(lTicks)
    iMonth = DateTime.GetMonth(lTicks)
    iAge = Starter.lTodayYear - iYear
    
    If Starter.lTodayMonth < iMonth Then
        iAge = iAge - 1
    Else
        If Starter.lTodayMonth = iMonth Then
            iDay = DateTime.GetDayOfMonth(lTicks)
            If iDay > Starter.lTodayDay Then
                iAge = iAge - 1
            End If
        End If
    End If
    
    Return iAge

End Sub

Public Sub ExcelDate2String(lXLDate As Long) As String

    Dim lVal As Long
    
    If bAllowOnlyRealXLDates Then
        If lXLDate < 1 Then
            Return ""
        End If
    End If
    
    lVal = (lXLDate - ExcelUnixDiff) * DaySecs
    lVal = DateUtils.UnixTimeToTicks(lVal)

    Return(DateTime.Date(lVal))
    
End Sub

Public Sub Ticks2String(lTicks As Long, strFormat As String, bMegaTicks As Boolean) As String
    
    'RunLog("Ticks2String, lTicks: " & lTicks)
    
    If lTicks = 0 Then 'but this could be 01/01/1970 midnight!
        Return ""
    End If
    
    If strFormat.Length = 0 Then
        strFormat = "dd/MMM/yyyy"
    End If
    
    DateTime.DateFormat = strFormat
    
    If bMegaTicks Then
        Return DateTime.Date(lTicks * 1000)
    Else
        Return DateTime.Date(lTicks)
    End If
    
End Sub

Public Sub ArrayType(Var As Object) As String
    
    Dim Res As String

    Dim VarType As String = GetType(Var)

    If VarType.StartsWith("[") Then

        Dim SecondChar As String = VarType.SubString2(1,2)
        Select Case SecondChar
            Case "B"
                Res = "Byte"
            Case "S"
                Res = "Short"
            Case "I"
                Res = "Int"
            Case "J"
                Res = "Long"
            Case "F"
                Res = "Float"
            Case "D"
                Res = "Double"
            Case "C"
                Res = "Char"
            Case "L"
                If VarType.Contains("String") Then
                    Res = "String"
                Else
                    Res = "Object"
                End If
            Case Else
                Res = ""
        End Select

    End If

    Return Res

End Sub

Public Sub FormatMilliSecs(lMilliSecs As Long) As String

    Dim iSeconds As Int
    Dim iMinutes As Int
    Dim iHours As Int
    
    If lMilliSecs < 1000 Then
        Return lMilliSecs & " milli-seconds"
    End If
    
    If lMilliSecs < 10000 Then
        Return Round(lMilliSecs / 1000) & " seconds"
    End If
    
    If lMilliSecs < 60000 Then
        Return Round(lMilliSecs / 1000) & " seconds"
    End If
    
    If lMilliSecs < 3600000 Then
        iMinutes = lMilliSecs / 60000
        iSeconds = (lMilliSecs - (iMinutes * 60000)) / 1000
        Return iMinutes & " minutes, " & iSeconds  & " seconds"
    End If
    
    iHours = lMilliSecs / 3600000
    iMinutes = (lMilliSecs - iHours * 3600000) / 60000
    
    Return iHours & " hours, " & iMinutes  & " minutes"
    
End Sub

Then I attached my current table class as I have it now and also a sorting class with the sorting algo's.
I do realize that it might be somewhat tricky to convert the sorting code in the latest table class, but I think
it may be worth it.

RBS
 

Attachments

  • Table.bas
    208.1 KB · Views: 104
  • clsSorting.bas
    28.7 KB · Views: 100

RB Smissaert

Well-Known Member
Licensed User
Longtime User
The posted file Table.bas had faulty code in the 2 Subs that passed a map a B4XOrderedMap to the table class and this has been fixed.
Nil to do with the sorting code, but I thought best to correct it.

RBS
 

Attachments

  • Table.bas
    186.6 KB · Views: 101

Sergey_New

Well-Known Member
Licensed User
Longtime User
Thank you! The table had a hidden column (width=0), now it has appeared. Is it possible to set this column to its original width=0?
 

Sergey_New

Well-Known Member
Licensed User
Longtime User
I have an old version of the table where there is no hideColumn
P.S. Found: hideCol
 
Last edited:

JoséCarlos

Member
Licensed User
Need help.
I have many small CSV files.
As there are many, I want to include it in KVS and I would like to know if there is a solution to be able to open it through TableV3_30?
Thanks.
 

klaus

Expert
Licensed User
Longtime User
Sorry, but i do not really understand your problem.
You have many csv files.
What do you include in KVS ?
I have never used KVS.
What do you mean with: open it through TableV3_30
You can easily read a csv file into a Table CustomView.
Do you want to show several or even many Tables at the same time ?
Depending on the answers to the questions above, the solution could / would be different.
I am afraid that for small csv files, the Table CustomView is too big.
I have CustomViews for Tables with different levels, not yet published, and cross-platform to accomplish what you want.
But i need more detailed information on what exactly you want to do and what you expect.
Can you post a small project showing either what you have already done and what you want to achieve.
Maybe you could have a look at this thread: https://www.b4x.com/android/forum/threads/slow-loading-clv-with-table-solved.144928/page-2#posts
 

JoséCarlos

Member
Licensed User
Good Morning.
Thanks for your response.
I have several .csv files.
a.csv, b.csv, c.csv, d.csv............
I stored them all in KeyValueStore:
kvs.Put("a", a.csv)
kvs.Put("b", b.csv)
kvs.Put("c", c.csv)
kvs.Put("d", d.csv).........

In your example in TableV3_30 we used:
Table1.LoadTableFromCSV2(File.DirInternal, "a.csv", True, ";", True) to a.csv
Table1.LoadTableFromCSV2(File.DirInternal, "b.csv", True, ";", True) to b.csv.....


My question can be asked:
kvs.Get("a"), kvs.Get("b"), kvs.Get("c"), kvs.Get("d"),....
Thanks.
 

klaus

Expert
Licensed User
Longtime User
As i have never used KeyValueStore it is difficult to give a concrete advice.
You say that you have :
I have several .csv files.
a.csv, b.csv, c.csv, d.csv.

What is the content of a.csv, b.csv etc ?
Are these file names or what else.
When you call kvs.Get("a"), what do you get in return ?
 
Cookies are required to use this site. You must accept them to continue using the site. Learn more…