0

I've been working on a project to try and learn Java and I've been having trouble with getting Tableview to work. I've reviewed the other posts and so far I've made sure that:

  • Getters and Setters are set and spelled correctly
  • CellValueFactory is set correctly for all
  • The variable name in CellValueFactory is identical to Variable in my object

However, despite all of this I'm still not getting my data to populate. Compiling this list creates an empty TableView with placeholder text, despite my println showing that the list and tableview both contain valid data.

In the real version of this code where the user is able to add to the tableview, additions "appear" in the list as blank but selectable entries.

The GUI class is

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;

import java.io.IOException;
import java.util.ArrayList;

public class GUI extends Application {

    //Variable initialization
    @FXML
    TableView tvTest=new TableView ();
    @FXML
    TableColumn<TestObj, Integer> keyCol=new TableColumn<>("Key");
    @FXML
    TableColumn<TestObj, String> aCol=new TableColumn<>("A");
    @FXML
    TableColumn<TestObj, String> bCol=new TableColumn<>("B");
    @FXML
    TableColumn<TestObj, String> cCol=new TableColumn<>("C");

    ArrayList<TestObj> testObjs=new ArrayList<TestObj>();
    ObservableList<TestObj> testObjList;

    //Sets up window
    @Override
    public void start(Stage primaryStage)throws IOException {
        primaryStage.setTitle("Table View Test");
        Parent root = FXMLLoader.load(getClass().getResource("tvTest.fxml"));
        Scene scene = new Scene(root,800,500);
        primaryStage.setResizable(false);
        primaryStage.setScene(scene);
        setupTable();
        primaryStage.show();
    }

    //Creates cell factories and loads up lists
    private void setupTable(){

        //Test objects
        testObjs.add(new TestObj(1,"A1","B1","C1"));
        testObjs.add(new TestObj(2,"A2","B2","C2"));
        testObjs.add(new TestObj(3,"A3","B3","C3"));
        testObjList= FXCollections.observableList(testObjs);

        //Cell value factory creation
        keyCol.setCellValueFactory(new PropertyValueFactory<TestObj,Integer>("key"));
        aCol.setCellValueFactory(new PropertyValueFactory<TestObj,String>("A"));
        bCol.setCellValueFactory(new PropertyValueFactory<TestObj,String>("B"));
        cCol.setCellValueFactory(new PropertyValueFactory<TestObj,String>("C"));

        //Sets table data
        tvTest.setItems(testObjList);

        //Test to confirm
        System.out.println(testObjList.size());//Confirms 3 items in list
        System.out.println(tvTest.getItems().size());//Confirms 3 items in table

        //Make sure data is correct in list
        System.out.println("_____________________");
        for(int i = 0; i< testObjList.size(); i++){
            System.out.println(testObjList.get(i).getKey()+"|"+ testObjList.get(i).getA()+"|"+testObjList.get(i).getB()+"|"+ testObjList.get(i).getC());
        }
        System.out.println("_____________________");
    }
}

The testObj class is

public class TestObj {
    int key;
    String a;
    String b;
    String c;

    public int getKey() {
        return key;
    }

    public void setKey(int key) {
        this.key = key;
    }

    public String getA() {
        return a;
    }

    public void setA(String a) {
        this.a = a;
    }

    public String getB() {
        return b;
    }

    public void setB(String b) {
        this.b = b;
    }

    public String getC() {
        return c;
    }

    public void setC(String c) {
        this.c = c;
    }

    TestObj(int key, String A, String B, String C){
        this.key=key;
        this.a=A;
        this.b=B;
        this.c=C;
    }
}

The FXML file is

<?import javafx.scene.layout.AnchorPane?>

<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.172-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="GUI">
   <children>
      <TableView layoutX="14.0" layoutY="14.0" prefHeight="372.0" prefWidth="570.0" fx:id="tvTest">
        <columns>
          <TableColumn fx:id="keyCol" prefWidth="72.0" text="Key" />
          <TableColumn fx:id="aCol" prefWidth="166.0" text="A" />
            <TableColumn fx:id="bCol" prefWidth="166.0" text="B" />
            <TableColumn fx:id="cCol" prefWidth="166.0" text="C" />
        </columns>
      </TableView>
   </children>
</AnchorPane>

And if it helps, the Main class is

import javafx.application.Application;

public class Main {
    public static void main(String[] args) {
        Application.launch(GUI.class, args);
    }
}

I'm using maven to import openJFX which has been working with the exception of this TableView.

Again, compiling this list creates an empty TableView with placeholder text, despite my println showing that the list and tableview both contain valid data.

If it helps: in the real version of this code where the user is able to add to the tableview, additions "appear" in the list as blank but selectable entries.

Thank you so much

  • the problem is that you are running two instances of `GUI`. one is "manually" created and the other is created by `FXMLLoader`. – mr mcwolf Aug 13 '19 at 17:13
  • @mrmcwolf I've changed the code so the controller class is now separate from the application class. My application class now consists solely of the start() method and everything else is now in a testController class. The setupTable() method has been changed to initialize() which I think was another problem. I'm still not having any luck – David Pinto Aug 13 '19 at 22:10

2 Answers2

0

You don't need to initialize the @FXML annotated attributes because they will be injected by JavaFX.

Try like that:



    @FXML
    TableView tvTest;
    @FXML
    TableColumn keyCol;
    @FXML
    TableColumn aCol;
    @FXML
    TableColumn bCol;
    @FXML
    TableColumn cCol;

josev.junior
  • 409
  • 2
  • 5
  • 13
  • Thank you, however after removing them, I get a NullPointerException on the setCellValueFactory lines. I initially added those in as they would allow the program to compile. Any idea how to get around this? – David Pinto Aug 13 '19 at 04:25
0

Thanks to everyone that responded, even if you deleted your response. They helped put me on the right track and I just got this fixed.

For anyone looking through this to fix their own code, the issues were:

  • setupTable() should have been initialize()
  • Initialize was set to private
  • Controller class was the same as application class
  • Columns were initialized
  • After splitting into a controller and application, I accidentally renamed the tableView to the controller class name

The initialize() as setupTable() was, by and large, the biggest issue and thank you to @mrmcwolf for helping me look into this. Having this set to private was not allowing FXML to inject properly. These two issues were the hard reasons my code wasn't working. If you're having issues, try checking these.

The controller class was more of a bad practice but it helped for code readability and for me to see where my issue was

Initializing columns was another bad practice. Testing it out showed that it worked even without this, but it was unnecessary and cluttered the code

The last one was pretty stupid but it happens. This manifested as a NullPointerException since there was no tableview to inject

Below is the final source code if you want to build it yourself to play with and get to work

Main class:

import javafx.application.Application;

public class Main {
    public static void main(String[] args) {
        Application.launch(GUI.class, args);
    }
}

GUI class:

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;

public class GUI extends Application {
    //Sets up window
    @Override
    public void start(Stage primaryStage)throws IOException {
        primaryStage.setTitle("Table View Test");
        Parent root = FXMLLoader.load(getClass().getResource("tvTest.fxml"));
        Scene scene = new Scene(root);
        primaryStage.setResizable(true);
        primaryStage.setScene(scene);
        primaryStage.show();
    }
}

testController class:

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;

public class testController {

    //Variable initialization
    @FXML
    TableView<TestObj> tvTest;
    @FXML
    TableColumn<TestObj, Integer> keyCol;
    @FXML
    TableColumn<TestObj, String> aCol;
    @FXML
    TableColumn<TestObj, String> bCol;
    @FXML
    TableColumn<TestObj, String> cCol;

    ObservableList<TestObj> testObjs= FXCollections.observableArrayList();

    //Creates cell factories and loads up lists
    public void initialize(){
        //Cell value factory creation
        keyCol.setCellValueFactory(new PropertyValueFactory<TestObj,Integer>("key"));
        aCol.setCellValueFactory(new PropertyValueFactory<TestObj,String>("A"));
        bCol.setCellValueFactory(new PropertyValueFactory<TestObj,String>("B"));
        cCol.setCellValueFactory(new PropertyValueFactory<TestObj,String>("C"));

        //Test objects
        testObjs.add(new TestObj(1,"A1","B1","C1"));
        testObjs.add(new TestObj(2,"A2","B2","C2"));
        testObjs.add(new TestObj(3,"A3","B3","C3"));

        tvTest.setItems(testObjs);
    }
}

TestObj class:

public class TestObj {
    int key;
    String a;
    String b;
    String c;

    public int getKey() {
        return key;
    }

    public void setKey(int key) {
        this.key = key;
    }

    public String getA() {
        return a;
    }

    public void setA(String a) {
        this.a = a;
    }

    public String getB() {
        return b;
    }

    public void setB(String b) {
        this.b = b;
    }

    public String getC() {
        return c;
    }

    public void setC(String c) {
        this.c = c;
    }

    TestObj(int key, String A, String B, String C){
        this.key=key;
        this.a=A;
        this.b=B;
        this.c=C;
    }
}

tvTest.fxml:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.172-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="testController">
   <children>
      <TableView layoutX="14.0" layoutY="14.0" prefHeight="372.0" prefWidth="570.0" fx:id="tvTest">
        <columns>
          <TableColumn fx:id="keyCol" prefWidth="72.0" text="Key" />
          <TableColumn fx:id="aCol" prefWidth="166.0" text="A" />
            <TableColumn fx:id="bCol" prefWidth="166.0" text="B" />
            <TableColumn fx:id="cCol" prefWidth="166.0" text="C" />
        </columns>
      </TableView>
   </children>
</AnchorPane>

Hope this helps anyone that happens to stumble on it