B4J Library jTableViewExtended

This library extends TableView and provides more control on the columns, rows and cells.

What you get with TableView:

before.jpg


What you can get with TableViewExtended (with the same data):

after.jpg


You can easily enhance an existing TableView by initializing your TableViewExtended with InitializeByExtending(MyExistingTableView).

Changelog:
v1.0:
- I added the TableRow class;
- I added ClearSelection, DisableReorderingColumns, FixedCellHeight, MultipleSelection, Placeholder, SelectedCells, SelectedRows, SetRowEventsListener, Sort and SortOrder to TableViewExtended;
- I replaced RowIndex and RowStyle by Row in TableCell;
- I modified the example to open a message box on double-click on a row.

v1.1:
- I added the Column property to the TableCell class.

v1.11:
- I fixed an issue with OpenJDK 11 in the DisableReorderingColumns function.
 

Attachments

  • jTableViewExtended_111.zip
    47.7 KB · Views: 637
Last edited:

Informatix

Expert
Licensed User
Longtime User
Sorry but i think you dont understand what i am asking.

ok let me breakdown it.

to edit a cell you need to double click it and convert the cell to a textfield.

what do i want is to make it editable without double clicking it.

tnx
Basically, the idea is to replace the cell content by an editor (e.g. a TextField for a string or a number). My library does not include such an editor as there are too many possibilities of content so the cell edition code has to be written entirely in your code. You can use any method you want to trigger the edition code in the CellFactory event (which is not related to mouse, but to display). If you're able to select a cell with keys, then store the cell coordinates in a global variable and read this variable in every CellFactory event to check whether the cell has to be edited or not.
If your question is in fact: how do I select a cell with keys? I cannot answer because I did not implement the Key events in my library and I have no idea about the method you're using for keys.
 

BarryW

Active Member
Licensed User
Longtime User
I added an keypress event.

Please see my code for better understand

B4X:
Sub TableView1_KeyPressed_Event(e As Event)
    Dim key As Reflector
    key.Target = e
    Dim KeyCode As String = key.RunMethod("getCode")
    If "ENTER F2".Contains(KeyCode) Then
        'Edit Cell Here
    End If
    e.Consume
End Sub
 

Attachments

  • Table.zip
    359 KB · Views: 455

Informatix

Expert
Licensed User
Longtime User
I added an keypress event.

Please see my code for better understand

B4X:
Sub TableView1_KeyPressed_Event(e As Event)
    Dim key As Reflector
    key.Target = e
    Dim KeyCode As String = key.RunMethod("getCode")
    If "ENTER F2".Contains(KeyCode) Then
        'Edit Cell Here
    End If
    e.Consume
End Sub
Then apply what's in post #21. You store the coordinates of the selected cell in a global variable and check in the CellFactory events whether this global variable is different from Null and correspond to the cell in the event (you get the row index with Cell.Row.Index). It's an example, you can choose another method.
 

Patent

Member
Licensed User
Longtime User
Hi Informatix.

Thanks for sharing this lib to us.

How is it possile to built a row programaticaly? Not with
Dim Row As TableRow = Sender
because no sender exist.

Like :
B4X:
Dim r as TableRow=Array as Object("cell1"+"cell2".....)

greets
 

Informatix

Expert
Licensed User
Longtime User
How is it possile to built a row programaticaly? Not with
Dim Row As TableRow = Sender
because no sender exist.
The row can only be got from a cell (Cell.Row) or from a mouse event in a row (sender).

Like :
B4X:
Dim r as TableRow=Array as Object("cell1"+"cell2".....)
To add the row contents, use the Items property of the tableview (Items.Add(...)).
To get the row object that you just added, there's no easy way.
 

Patent

Member
Licensed User
Longtime User
thank you for the information.

another thing: is it possible to do things with an css file?
what are the pseudo classes names, .table-view .table-cell { ?
 

Patent

Member
Licensed User
Longtime User
a, ok. Standard. I thougt i have to do anything special..... :cool:
thanks a lot
 

Mashiane

Expert
Licensed User
Longtime User
Hi

I'd like to use this inside a custom view. I'm trying to create an editable tableview that can have a maximum of 20 columns. So I declared

B4X:
Private tcCol(19) As TableColumn
inside class globals and I'm getting an error on this line when I compile. Yes, in your example this is inside Process_Globals and classes

I fear that perhaps my approach might not work.

In my own SetColumns method I added...

B4X:
If bIsReport = True Then
        'extend this tableview
        tveThis.InitializeByExtending(TV)
        tveThis.Items.Initialize
        tveThis.SingleCellSelection = True
        'set up the extended editor for each column
        For colCnt = 0 To colTot
            colMap = Columns.GetValueAt(colCnt)
            colName = colMap.get("name")
            colWidth = colMap.get("width")
            colTag = colMap.Get("tag")
            colVisible = colMap.Get("visible")
            ' set columns widths, default is 150
            If colWidth = "-1" Then colWidth = 150
       
            'set the cell factory
            tcCol(colCnt) = tveThis.GetColumn(colCnt)
            tcCol(colCnt).SetCellFactoryWithMouseEvents("Col" & colCnt)
            tcCol(colCnt).Width = colWidth
            tcCol(colCnt).Resizable = True
            'initialize the textboxes
            tfEditor(colCnt).Initialize("Editor" & colCnt)
        Next
        tveThis.SetRowEventsListener("Row")
    End If

And then added the respective handlers

B4X:
Sub ExtendedMousePressed(EventData As MouseEvent,idx As Int)
    Dim Cell As TableCell = Sender
    Dim FirstTimeInCell As Boolean = PrevRow <> Cell.Row.Index Or PrevCol <> 0
    If FirstTimeInCell Then
        PrevRow = Cell.Row.Index
        PrevCol = 0
    Else If EditedCell = Null Then
        'Marks the cell and raises a CellFactory event to replace the text of the city name by a TextField
        EditedCell = Cell
        EditedCell.Tag = Cell.Row.Index
        Cell.Update

        'Sets the focus on the editor (requires to consume the event first)
        EventData.Consume
        tfEditor(idx).RequestFocus
    End If
End Sub

Sub ExtendedCellFactory(Cell As TableCell, Empty As Boolean, idx As Int) As Object
    'No need to do anything for empty cells
    If Empty Then Return Null

    'If the cell is marked, returns a TextField to edit the city name
    If Cell = EditedCell Then
        If Cell.Row.Index <> EditedCell.Tag Then
            'If the cell was recycled after a scrolling, cancel the operation
            EditedCell = Null
        Else
            tfEditor(idx).Text = Cell.Item
            Return tfEditor(idx)
        End If
    End If
    Return Cell.Item
End Sub


'extended tableview
Sub Col0_MousePressed(EventData As MouseEvent)
    ExtendedMousePressed(EventData,0)
End Sub

Sub Col0_CellFactory(Cell As TableCell, Empty As Boolean) As Object
    Return ExtendedCellFactory(Cell,Empty,0)
End Sub

Sub    Editor0_Action
    'Commits the change
    Update_Col(0)
End Sub

So the idea is to have each Col0 - Col19 respective methods. The compilation is going well and stops at the definition...

B4X:
B4J Version: 6.00
Parsing code.    (1.69s)
Compiling code.    (0.98s)
Compiling layouts code.    (0.01s)
Organizing libraries.    (0.00s)
Compiling generated Java code.    Error
B4J line: 93
Private tcCol(19) As TableColumn
javac 1.8.0_152
src\b4j\Mashy\PenNPaper\editabletv.java:1229: error: constructor ColumnWrapper in class ColumnWrapper cannot be applied to given types;
_tccol[i0] = new flm.b4j.tableviewextended.ColumnWrapper();
             ^
  required: TableColumn<Object[],?>
  found: no arguments
  reason: actual and formal argument lists differ in length

That's exactly the line with Private tcCol(19) As TableColumn

Is there something I'm missing? Can you please advise?

Thanks
 

Informatix

Expert
Licensed User
Longtime User
Hi

I'd like to use this inside a custom view. I'm trying to create an editable tableview that can have a maximum of 20 columns. So I declared

B4X:
Private tcCol(19) As TableColumn
inside class globals and I'm getting an error on this line when I compile. Yes, in your example this is inside Process_Globals and classes

I fear that perhaps my approach might not work.

In my own SetColumns method I added...

B4X:
If bIsReport = True Then
        'extend this tableview
        tveThis.InitializeByExtending(TV)
        tveThis.Items.Initialize
        tveThis.SingleCellSelection = True
        'set up the extended editor for each column
        For colCnt = 0 To colTot
            colMap = Columns.GetValueAt(colCnt)
            colName = colMap.get("name")
            colWidth = colMap.get("width")
            colTag = colMap.Get("tag")
            colVisible = colMap.Get("visible")
            ' set columns widths, default is 150
            If colWidth = "-1" Then colWidth = 150
     
            'set the cell factory
            tcCol(colCnt) = tveThis.GetColumn(colCnt)
            tcCol(colCnt).SetCellFactoryWithMouseEvents("Col" & colCnt)
            tcCol(colCnt).Width = colWidth
            tcCol(colCnt).Resizable = True
            'initialize the textboxes
            tfEditor(colCnt).Initialize("Editor" & colCnt)
        Next
        tveThis.SetRowEventsListener("Row")
    End If

And then added the respective handlers

B4X:
Sub ExtendedMousePressed(EventData As MouseEvent,idx As Int)
    Dim Cell As TableCell = Sender
    Dim FirstTimeInCell As Boolean = PrevRow <> Cell.Row.Index Or PrevCol <> 0
    If FirstTimeInCell Then
        PrevRow = Cell.Row.Index
        PrevCol = 0
    Else If EditedCell = Null Then
        'Marks the cell and raises a CellFactory event to replace the text of the city name by a TextField
        EditedCell = Cell
        EditedCell.Tag = Cell.Row.Index
        Cell.Update

        'Sets the focus on the editor (requires to consume the event first)
        EventData.Consume
        tfEditor(idx).RequestFocus
    End If
End Sub

Sub ExtendedCellFactory(Cell As TableCell, Empty As Boolean, idx As Int) As Object
    'No need to do anything for empty cells
    If Empty Then Return Null

    'If the cell is marked, returns a TextField to edit the city name
    If Cell = EditedCell Then
        If Cell.Row.Index <> EditedCell.Tag Then
            'If the cell was recycled after a scrolling, cancel the operation
            EditedCell = Null
        Else
            tfEditor(idx).Text = Cell.Item
            Return tfEditor(idx)
        End If
    End If
    Return Cell.Item
End Sub


'extended tableview
Sub Col0_MousePressed(EventData As MouseEvent)
    ExtendedMousePressed(EventData,0)
End Sub

Sub Col0_CellFactory(Cell As TableCell, Empty As Boolean) As Object
    Return ExtendedCellFactory(Cell,Empty,0)
End Sub

Sub    Editor0_Action
    'Commits the change
    Update_Col(0)
End Sub

So the idea is to have each Col0 - Col19 respective methods. The compilation is going well and stops at the definition...

B4X:
B4J Version: 6.00
Parsing code.    (1.69s)
Compiling code.    (0.98s)
Compiling layouts code.    (0.01s)
Organizing libraries.    (0.00s)
Compiling generated Java code.    Error
B4J line: 93
Private tcCol(19) As TableColumn
javac 1.8.0_152
src\b4j\Mashy\PenNPaper\editabletv.java:1229: error: constructor ColumnWrapper in class ColumnWrapper cannot be applied to given types;
_tccol[i0] = new flm.b4j.tableviewextended.ColumnWrapper();
             ^
  required: TableColumn<Object[],?>
  found: no arguments
  reason: actual and formal argument lists differ in length

That's exactly the line with Private tcCol(19) As TableColumn

Is there something I'm missing? Can you please advise?

Thanks
You can force the columns to Null if you want to avoid the error, but it's not recommended because a column is not supposed to be a Null object:
Private tcCol(19) As TableColumn = Array As TableColumn(Null, Null, Null, ... x 19)
 

imbault

Well-Known Member
Licensed User
Longtime User
Hi Fred,
is it possible to show a tooltip message, when the mouse fires a mouseover on a cell ?

Thanks
 

behnam_tr

Active Member
Licensed User
Longtime User
Error on DisableReorderingColumns With JDK11
tveCities.DisableReorderingColumns

B4X:
Waiting for debugger to connect...
Program started.
java.lang.IllegalAccessError: class flm.b4j.tableviewextended.TableViewExtended tried to access method javafx.scene.control.skin.TableHeaderRow.reorderingProperty()Ljavafx/beans/property/BooleanProperty; (flm.b4j.tableviewextended.TableViewExtended is in unnamed module of loader 'app'; javafx.scene.control.skin.TableHeaderRow is in module javafx.controls of loader 'app')
    at flm.b4j.tableviewextended.TableViewExtended.DisableReorderingColumns(TableViewExtended.java:82)
    at b4j.example.main._appstart(main.java:192)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:629)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:237)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:167)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:111)
    at anywheresoftware.b4a.shell.ShellBA.raiseEvent2(ShellBA.java:100)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:98)
    at b4j.example.main.start(main.java:38)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
    at java.base/java.lang.Thread.run(Thread.java:834)
java.lang.RuntimeException: java.lang.IllegalAccessError: class flm.b4j.tableviewextended.TableViewExtended tried to access method javafx.scene.control.skin.TableHeaderRow.reorderingProperty()Ljavafx/beans/property/BooleanProperty; (flm.b4j.tableviewextended.TableViewExtended is in unnamed module of loader 'app'; javafx.scene.control.skin.TableHeaderRow is in module javafx.controls of loader 'app')
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:140)
    at anywheresoftware.b4a.shell.ShellBA.raiseEvent2(ShellBA.java:100)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:98)
    at b4j.example.main.start(main.java:38)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
    at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.IllegalAccessError: class flm.b4j.tableviewextended.TableViewExtended tried to access method javafx.scene.control.skin.TableHeaderRow.reorderingProperty()Ljavafx/beans/property/BooleanProperty; (flm.b4j.tableviewextended.TableViewExtended is in unnamed module of loader 'app'; javafx.scene.control.skin.TableHeaderRow is in module javafx.controls of loader 'app')
    at flm.b4j.tableviewextended.TableViewExtended.DisableReorderingColumns(TableViewExtended.java:82)
    at b4j.example.main._appstart(main.java:192)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:629)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:237)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:167)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:111)
    ... 12 more
 
Top