Android Code Snippet [B4X] B4XTable - Resize columns based on content

Status
Not open for further replies.
This code measures the required width based on the cells text and set it:

B4X:
Sub B4XTable1_DataUpdated
    Dim ShouldRefresh As Boolean
    'NameColumn and NumberColumn are global B4XTableColumns that we want to measure
    For Each column As B4XTableColumn In Array(NameColumn, NumberColumn)
        Dim MaxWidth As Int
        For i = 0 To B4XTable1.VisibleRowIds.Size - 1
            Dim RowId As Long = B4XTable1.VisibleRowIds.Get(i)
            If RowId > 0 Then
                Dim pnl As B4XView = column.CellsLayouts.Get(i + 1)
                Dim lbl As B4XView = pnl.GetView(0)
                Dim txt As String = B4XTable1.GetRow(RowId).Get(column.Id)
                MaxWidth = Max(MaxWidth, cvs.MeasureText(txt, lbl.Font).Width + 10dip)
            End If
        Next
        If MaxWidth > column.ComputedWidth Or MaxWidth < column.ComputedWidth - 20dip Then
            column.Width = MaxWidth
            ShouldRefresh = True
        End If
    Next
    If ShouldRefresh Then
        B4XTable1.Refresh
    End If
End Sub

cvs is a global B4XCanvas. Create it with this code when the app starts:
B4X:
Dim p As B4XView = xui.CreatePanel("")
   p.SetLayoutAnimated(0, 0, 0, 1dip, 1dip)
   cvs.Initialize(p)
 
Last edited:

LucaMs

Expert
Licensed User
Longtime User
Generalized:
' Call it from the xTable DataUpdated event.
' lstColumns: pass Null to resize all columns.
Sub B4XTableColumnResizesOnContent(xTable As B4XTable, lstColumns As List)
    If Not(lstColumns.IsInitialized) Then
        lstColumns = xTable.Columns
    End If
   
    Dim p As B4XView = xui.CreatePanel("")
    p.SetLayoutAnimated(0, 0, 0, 1dip, 1dip)
    Dim xCanvas As B4XCanvas
    xCanvas.Initialize(p)
   
    Dim ShouldRefresh As Boolean
   
    For Each column As B4XTableColumn In lstColumns
        Dim MaxWidth As Int
        For i = 0 To xTable.VisibleRowIds.Size - 1
            Dim RowId As Long = xTable.VisibleRowIds.Get(i)
            If RowId > 0 Then
                Dim pnl As B4XView = column.CellsLayouts.Get(i + 1)
                Dim lbl As B4XView = pnl.GetView(0)
                Dim txt As String = xTable.GetRow(RowId).Get(column.Id)
                MaxWidth = Max(MaxWidth, xCanvas.MeasureText(txt, lbl.Font).Width + 10dip)
            End If
        Next
        If MaxWidth > column.ComputedWidth Or MaxWidth < column.ComputedWidth - 20dip Then
            column.Width = MaxWidth
            ShouldRefresh = True
        End If
    Next
    If ShouldRefresh Then
        xTable.Refresh
    End If
End Sub
 

beelze69

Active Member
Licensed User
Longtime User
I think I got is figured out using this code. It is working for me now after several hours:
B4X:
Sub Globals
    Private B4XTable1 As B4XTable
    Private cvs As B4XCanvas
    Private xui As XUI
    Private NameColumn(6) As B4XTableColumn
End Sub

B4X:
NameColumn(0) = B4XTable1.AddColumn("Name", B4XTable1.COLUMN_TYPE_TEXT)
    NameColumn(1) = B4XTable1.AddColumn("Customer Id", B4XTable1.COLUMN_TYPE_NUMBERS)
    NameColumn(2) = B4XTable1.AddColumn("Company", B4XTable1.COLUMN_TYPE_TEXT)
    NameColumn(3) = B4XTable1.AddColumn("Address", B4XTable1.COLUMN_TYPE_TEXT)
    NameColumn(4) = B4XTable1.AddColumn("Email", B4XTable1.COLUMN_TYPE_TEXT)
    NameColumn(5) = B4XTable1.AddColumn("Country", B4XTable1.COLUMN_TYPE_TEXT)

B4X:
Sub B4XTable1_DataUpdated
    Dim ShouldRefresh As Boolean
    For Each Column As B4XTableColumn In Array (NameColumn(0), NameColumn(1), NameColumn(2), NameColumn(3), NameColumn(4), NameColumn(5) )
        Dim MaxWidth As Int
        For i = 0 To B4XTable1.VisibleRowIds.Size
            Dim pnl As B4XView = Column.CellsLayouts.Get(i)
            Dim lbl As B4XView = pnl.GetView(0)
            MaxWidth = Max(MaxWidth, cvs.MeasureText(lbl.Text, lbl.Font).Width + 10dip)
        Next
        If MaxWidth > Column.ComputedWidth Or MaxWidth < Column.ComputedWidth - 20dip Then
            Column.Width = MaxWidth
            ShouldRefresh = True
        End If
    Next
    If ShouldRefresh Then
        B4XTable1.Refresh
    End If
End Sub
Hi Mahares,

I tried your code and it works fine...

But I am facing a small issue... I want to display only 3 columns and the entire B4Xtable neatly fits into 3/4th of the Mobile screen , but that leaves a big gap at the right part area of the mobile screen...

So how do we ensure that the columns that we display are evenly spaced to occupy the Mobile screen (the First column begins on the Left edge of the screen and the Last Column ends at the right edge of the screen)..

Sorry.. if I sound too basic...

Thanks...
 

Mahares

Expert
Licensed User
Longtime User
are evenly spaced to occupy the Mobile screen (the First column begins on the Left edge of the screen and the Last Column ends at the right edge of the screen)..
You csan do something like this:
B4X:
B4XTable1.AddColumn("Student_Num",  B4XTable1.COLUMN_TYPE_NUMBERS).Width=33%x
    B4XTable1.AddColumn("Student_Name", B4XTable1.COLUMN_TYPE_TEXT).Width=33%x
    B4XTable1.AddColumn("Student_City", B4XTable1.COLUMN_TYPE_TEXT).Width=33%x
or use colomn names like this and apply to all three columns:
B4X:
Dim c1 As B4XTableColumn
    c1= B4XTable1.AddColumn("Student_Num",  B4XTable1.COLUMN_TYPE_NUMBERS)
    c1.Width =33%x
 

beelze69

Active Member
Licensed User
Longtime User
You csan do something like this:
B4X:
B4XTable1.AddColumn("Student_Num",  B4XTable1.COLUMN_TYPE_NUMBERS).Width=33%x
    B4XTable1.AddColumn("Student_Name", B4XTable1.COLUMN_TYPE_TEXT).Width=33%x
    B4XTable1.AddColumn("Student_City", B4XTable1.COLUMN_TYPE_TEXT).Width=33%x
or use colomn names like this and apply to all three columns:
B4X:
Dim c1 As B4XTableColumn
    c1= B4XTable1.AddColumn("Student_Num",  B4XTable1.COLUMN_TYPE_NUMBERS)
    c1.Width =33%x
Hi Mahares,

Sorry... it is not working...
 

Mahares

Expert
Licensed User
Longtime User
Sorry... it is not working...
What is not working. You did not post any of your code. The code I posted for you is a guideline. If you use an array of 3 columns, you can do this. It works:
B4X:
Dim col(3) As B4XTableColumn
    col(0)= B4XTable1.AddColumn("Student_Num",  B4XTable1.COLUMN_TYPE_NUMBERS)  'use your own column names
    col(0).Width =33%x
    col(1)= B4XTable1.AddColumn("Student_Name",  B4XTable1.COLUMN_TYPE_TEXT)
    col(1).Width =33%x
    col(2)= B4XTable1.AddColumn("Student_City",  B4XTable1.COLUMN_TYPE_TEXT)
    col(2).Width =33%x
 

beelze69

Active Member
Licensed User
Longtime User
What is not working. You did not post any of your code. The code I posted for you is a guideline. If you use an array of 3 columns, you can do this. It works:
B4X:
Dim col(3) As B4XTableColumn
    col(0)= B4XTable1.AddColumn("Student_Num",  B4XTable1.COLUMN_TYPE_NUMBERS)  'use your own column names
    col(0).Width =33%x
    col(1)= B4XTable1.AddColumn("Student_Name",  B4XTable1.COLUMN_TYPE_TEXT)
    col(1).Width =33%x
    col(2)= B4XTable1.AddColumn("Student_City",  B4XTable1.COLUMN_TYPE_TEXT)
    col(2).Width =33%x
Hi Mahares,

Attaching the sample code..

Requesting for guidance on where I am going wrong...
 

Attachments

  • colsNotEvenlySpaced.zip
    337.4 KB · Views: 282

Mahares

Expert
Licensed User
Longtime User
Requesting for guidance on where I am going wrong...
Your B4XTable1_DataUpdated sub is resizing the column every time it is updating and interfering with your columns width. Comment the entire sub and its code and you will be good to go.
 

beelze69

Active Member
Licensed User
Longtime User
Your B4XTable1_DataUpdated sub is resizing the column every time it is updating and interfering with your columns width. Comment the entire sub and its code and you will be good to go.
Thanks Mahares,

Now it is fine..

But another peculiar problem I am facing.. I converted the above code into b4XPages..Now, in the Search Portion of the B4XTable, when I type something .. MOST OF THE TIME it works fine.. But once or twice I am getting the following error :

B4X:
java.lang.RuntimeException: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.String.toLowerCase()' on a null object reference
    at anywheresoftware.b4a.keywords.Common$13.run(Common.java:1716)
    at android.os.Handler.handleCallback(Handler.java:873)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:201)
    at android.app.ActivityThread.main(ActivityThread.java:6823)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:873)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.String.toLowerCase()' on a null object reference
    at b4a.example.b4xtable._settexttocell(b4xtable.java:2752)
    at b4a.example.b4xtable$ResumableSub_ImplUpdateDataFromQuery.resume(b4xtable.java:1713)
    at anywheresoftware.b4a.keywords.Common$13.run(Common.java:1714)
    ... 7 more

Can you guide me on where I am going wrong ?
 
Last edited:

Mahares

Expert
Licensed User
Longtime User
But another peculiar problem I am facing..
If you can post the B4XPagesproject and tell me what you type, I will be glad to tes it for you. If it also happens in the project you posted above, give me the details and I can test it also.
 

beelze69

Active Member
Licensed User
Longtime User
If you can post the B4XPagesproject and tell me what you type, I will be glad to tes it for you. If it also happens in the project you posted above, give me the details and I can test it also.
Hi Mahares,

Thanks.. There was some 'residual code' of something that I tried earlier but which I did not remove... Now it appears fine... But I will definitely take help if that problem comes again...
 
Status
Not open for further replies.
Top