B4J Question Tableview nested column help

nso91191

Member
Licensed User
Longtime User
Hi,
Please guide me how to add nested column in header of b4j tableview ( example pic uploaded ) .
If I use java fx scene builder and add nested column ok, but adding table data not display in tableview.
please help.

Thanks
 

Attachments

  • Capture.PNG
    8.9 KB · Views: 458

Daestrum

Expert
Licensed User
Longtime User
I can give you an example of using leaf columns in a TableView (requires JavaObject Library) and how to add data to the rows.

You will need to re-write a portion of the code as where I use streams to manipulate the columns. (Streams as in Stream.of(???).forEach …)
(The code as is compiles correctly using source and target 10)

The code shows how you manipulate the columns and cellfactories to get the desired results.

I created the table in code and added to mainform, but it should work on designer created ones too , as it overwrites the existing table. (tv = ...newTableView...

B4X:
Sub Process_Globals
 Private fx As JFX
 Private MainForm As Form
 Dim tv As TableView
End Sub
Sub AppStart (Form1 As Form, Args() As String)
 MainForm = Form1
 MainForm.Show
 tv = asJO(Me).RunMethod("newTableView",Null) ' create new table
 MainForm.RootPane.AddNode(tv,10,10,300,300) ' add to rootpane
 asJO(Me).RunMethod("addColumns",Array(tv,Array As String("One","Two","Three"))) ' set headers of table
 asJO(Me).RunMethod("addLeafColumn",Array(tv,1,Array As String("Sub 1","Sub 2"))) ' set headers of leaf columns under column 1 (2nd column)
 asJO(Me).RunMethod("addDataToTable",Array(tv,Array(1,2,3,4))) ' add some data
 asJO(Me).RunMethod("addDataToTable",Array(tv,Array(2,4,6,8)))
 asJO(Me).RunMethod("addDataToTable",Array(tv,Array(4,8,12,16)))
 tv.Items.Add(Array(8,16,24,32))   ' this will now work as cellfactories are set up correctly
End Sub
Sub asJO(o As JavaObject) As JavaObject
 Return o
End Sub
'Return true to allow the default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
 Return True
End Sub
#if java
import javafx.scene.control.*;
import java.util.stream.Stream;
import javafx.scene.Node;
import javafx.collections.FXCollections.*;
import javafx.collections.*;
import java.util.ArrayList;
import javafx.util.*;
import javafx.beans.property.StringProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.value.ObservableValue;
 static int ii = 0;
 public static TableView newTableView(){
     return new TableView();
 }
 public static void addColumns(TableView t,String... names){
    int i = t.getColumns().size();
    ii = i < 0 ? 0 : i;
    Stream.of(names).forEach(name -> {
        TableColumn x = new TableColumn(name);
        x.setCellValueFactory(new TestCellValueFactory(ii));
        t.getColumns().add(ii++,x);
    });
         correctCellValueFactoryParallel(t);
 }
public static void correctCellValueFactoryParallel(TableView t) {
    t.getColumns().parallelStream().forEach(
            tc -> {
                ((TableColumn) tc).setCellValueFactory(
                        new TestCellValueFactory(((TableColumn) tc).getTableView().getVisibleLeafColumns().indexOf(tc)));
            });
}
private static class TestCellValueFactory
        implements Callback<TableColumn.CellDataFeatures<Object[], Object>, ObservableValue<Object>> {
    private final int index;
    public TestCellValueFactory(int index) {
        this.index = index;
    }
    @Override
    public ObservableValue<Object> call(TableColumn.CellDataFeatures<Object[], Object> arg0) {
        return new ReadOnlyObjectWrapper(((Object[]) arg0.getValue())[this.index]);
    }
}
public static void addLeafColumn(TableView t,Integer col,String... names){
    int i = t.getVisibleLeafColumns().indexOf((TableColumn) t.getColumns().get(col));
    TableColumn tc = (TableColumn) t.getColumns().get(col);
    ii = i < 0 ? 0 : i;
    Stream.of(names).forEach(name -> {
        TableColumn x = new TableColumn(name);
        x.setCellValueFactory(new TestCellValueFactory(ii++));
        tc.getColumns().add(x);
    });
    correctCellValueFactoryParallel(t);
 }
 public static int getColumnCount(TableView t){
      return t.getColumns().size();
 }
 public static void addDataToTable(TableView t,Object...l){
      ObservableList<Object[]> ol = FXCollections.observableArrayList();
      ol.addAll(t.getItems());
      ol.addAll(l);
      t.setItems(ol);
 }
#End If
 
Last edited:
Upvote 0

Daestrum

Expert
Licensed User
Longtime User
After trying to reduce the code this is what's left. It works on tables created in the designer (not FXML one)

B4X:
Sub Process_Globals
 Private fx As JFX
 Private MainForm As Form
 Private TableView1 As TableView
End Sub
Sub AppStart (Form1 As Form, Args() As String)
 MainForm = Form1
 MainForm.RootPane.LoadLayout("lay1") 'Load the layout file. ' default tableview 3 cols
 MainForm.Show
 asJO(Me).RunMethod("addLeafColumn",Array(TableView1,1,Array As String("Sub1","Sub2"))) ' this sets up the sub headers
 TableView1.Items.Add(Array(1,2,3,4)) ' the columns are Col 1, Sub1, Sub2, Col 3 - Col 2 is placeholder only now
 TableView1.Items.Add(Array(2,4,6,8))
 TableView1.Items.Add(Array(4,8,12,16))
 TableView1.Items.Add(Array(8,16,24,32))
End Sub
Sub asJO(o As JavaObject) As JavaObject
 Return o
End Sub
'Return true to allow the default exceptions handler to handle the uncaught exception.
Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
 Return True
End Sub
#if java
import javafx.scene.control.*;
import java.util.stream.Stream;
import javafx.collections.FXCollections.*;
import javafx.collections.*;
import java.util.ArrayList;
import javafx.util.*;
import javafx.beans.property.StringProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.value.ObservableValue;
 static int ii = 0;
public static void correctCellValueFactoryParallel(TableView t) {
    t.getColumns().parallelStream().forEach(
            tc -> {
                ((TableColumn) tc).setCellValueFactory(
                        new TestCellValueFactory(((TableColumn) tc).getTableView().getVisibleLeafColumns().indexOf(tc)));
            });
}
private static class TestCellValueFactory
        implements Callback<TableColumn.CellDataFeatures<Object[], Object>, ObservableValue<Object>> {
    private final int index;
    public TestCellValueFactory(int index) {
        this.index = index;
    }
    @Override
    public ObservableValue<Object> call(TableColumn.CellDataFeatures<Object[], Object> arg0) {
        return new ReadOnlyObjectWrapper(((Object[]) arg0.getValue())[this.index]);
    }
}
public static void addLeafColumn(TableView t,Integer col,String... names){
    int i = t.getVisibleLeafColumns().indexOf((TableColumn) t.getColumns().get(col));
    TableColumn tc = (TableColumn) t.getColumns().get(col);
    ii = i < 0 ? 0 : i;
    Stream.of(names).forEach(name -> {
        TableColumn x = new TableColumn(name);
        x.setCellValueFactory(new TestCellValueFactory(ii++));
        tc.getColumns().add(x);
    });
    correctCellValueFactoryParallel(t);
 } 
#End If
 
Last edited:
Upvote 0
Cookies are required to use this site. You must accept them to continue using the site. Learn more…