0

Edited and removed all unused code

New to Javafx / scene builder using JDK 8 and eclipse.

Sql DB connection working fine and pulls to a recordset which populates a virtual Tableview, system.out prints db records etc. I am using scene builder and trying to populate a FXML defined Tableview in scenebuilder, which is fun to learn.

I just cannot get the data to the tableview.

I added static to private static ObservableList<ObservableList<String>> data; which has stopped my nullPointerException and added public void initialize(URL location, ResourceBundle resources) which tells me the ObservableList data has SOME DATA and watched way to many youtube videos.

I now have no errors but see no data in the defined tableview. When i add a column in to scenebulder without an id, i get different coloured rows, which makes me think it is doing sometihng, controller is attached in scenebuilder.

I just wanted to pull all the table columns for now just to test and then i can go on from there. Apologies for the messy code but may as well leave it in, first week.

I would be grateful for any assistance, really would.

Controller, left out imports

public class SoftwareController extends Application implements Initializable  {

    private static ObservableList<ObservableList<String>> data;
    @FXML 
    public TableView<ObservableList<String>> tblSoftware;
    public Statement st;
    public Connection conn;

    public static void main(String[] args) {
        launch(args);   
    }
    public void buildData() {
        data = FXCollections.observableArrayList();
    try {

        Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");  
        String url = "jdbc:sqlserver://IP;databaseName=CMDB";
        conn = DriverManager.getConnection(url,"cmdbadmin","cmdbadmin!1");
        System.out.print("connection successfulltttt");
        String SQL = "SELECT * from Data_CMDB_Main";

        ResultSet rs = conn.createStatement().executeQuery(SQL);

        for(int i=0 ; i<rs.getMetaData().getColumnCount(); i++) {
            final int j = i;
            TableColumn col = new TableColumn(rs.getMetaData().getColumnName(i+1)); 

            public ObservableValue<String> call(CellDataFeatures<ObservableList, String> param) {   
               return new SimpleStringProperty(param.getValue().get(j).toString());
            }
        });
           System.out.println(col);
       }
       while (rs.next()){
           ObservableList<String> row = FXCollections.observableArrayList();

          for(int i=1 ; i<=rs.getMetaData().getColumnCount(); i++) {
            row.add(rs.getString(i));
          }
          data.add(row);
          System.out.println(row);  //shows records from database
        }

    }catch (Exception e) {
        e.printStackTrace();
        System.out.println("Error building data");
    }
    }
    @Override
    public void start(Stage stage) throws Exception {   
        buildData();    
    }
    FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/fxml/Software.fxml"));
    Parent root1 = (Parent) fxmlLoader.load();
    Stage stage1 = new Stage();;
    stage1.setScene(new Scene(root1));
    stage1.show();

    }
    public Label lblTest;

    public void btnSoftwarePressed(ActionEvent event) {
        lblTest.setText("label working");
    }
    @Override
    public void initialize(URL location, ResourceBundle resources) {
        System.out.println(data);
        if(data !=null){
            System.out.println("data is not null");
            tblSoftware.getItems().addAll(data);
        }
        else System.out.println("data is null");
    }
}

FMXL

<?import java.lang.*?>
<?import java .util.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane prefHeight="368.0" prefWidth="433.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fxml.SoftwareController">
     <children>
<TableView fx:id="tblSoftware" layoutY="102.0" prefHeight="266.0" prefWidth="433.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="102.0">
             <columns>
             <TableColumn prefWidth="75.0" text="Column X" />
             </columns>
        </TableView>
         <Button fx:id="btnSoftware" layoutY="63.0" mnemonicParsing="false" onAction="#btnSoftwarePressed" text="Button" />
         <Label fx:id="lblTest" layoutX="226.0" layoutY="63.0" prefHeight="26.0" prefWidth="130.0" text="22" />
    </children>
</AnchorPane>
ItachiUchiha
  • 36,135
  • 10
  • 122
  • 176
user1483767
  • 1
  • 1
  • 5
  • The indentation seems messed up and it's hard to read but I don't see you adding columns to the table anywhere. In your metaData loop you'll need `tblSoftware.getColumns.add(col);` You can't add them in FXML if you don't know what they are. – brian May 21 '15 at 23:15
  • @brian That won't work in the metaData loop, though, because that loop is called from the `start` method, and in the instance that invokes `start(...)` the injected field `tblSoftware` is `null`... – James_D May 22 '15 at 00:16
  • 2
    I've seen a couple of people post code with the style you use here, where the controller is defined to be the same class as the `Application` subclass (the one with the `start(...)` method). I really recommend not doing this. While it can be made (forced?) to work, it's too confusing to keep track of what's going on. The `launch()` method, creates an instance of `SoftwareController`, and calls `start(...)` on that instance. From `start(...)`, you load the FXML, which creates an instance of the controller, and calls `initialize()` on that instance. Create a separate class for the controller. – James_D May 22 '15 at 00:19
  • Also, clean up all the code. It will help you see what's going on, and make it easier for people to help you. – James_D May 22 '15 at 00:20
  • See if [this example](http://stackoverflow.com/questions/25651641/javafx-mysql-connection-example-please) helps. It doesn't use FXML, but you could easily replace the `start()` method with something that loaded an FXML file, and then move the rest of the functionality from `start()` to a controller's `initialize()` method, etc. – James_D May 22 '15 at 00:54
  • I have removed the unsued code to help anyone else reading this. I will have a look at that example and try and get my head round it. – user1483767 May 22 '15 at 06:05

1 Answers1

0

I wanted to try and see how it worked without using a separate controller and application file.

Note that I had to call buildData in the initialize method like James_D mentioned.

This expects you have H2 as a library somewhere but I think your connection was ok, so just delete the H2 part and uncomment your connection.

package fxml;

import java.net.URL;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ResourceBundle;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.stage.Stage;

public class SoftwareController extends Application implements Initializable  {

    private static ObservableList<ObservableList<String>> data;

    @FXML public TableView<ObservableList<String>> tblSoftware;

    public void buildData() throws Exception{
        data = FXCollections.observableArrayList();
        DriverManager.registerDriver(new org.h2.Driver());
        Connection conn = DriverManager.getConnection("jdbc:h2:mem:");
        Statement stmt = conn.createStatement();
        String sql = "CREATE TABLE Data_CMDB_Main (name VARCHAR(255), address VARCHAR(255))";
        stmt.executeUpdate(sql);
        for (int i = 0; i < 10; i++) {
            sql = "INSERT INTO Data_CMDB_Main VALUES ("
                    + "'1st string in row " + i + "','2nd string in row " + i + "')";
            stmt.executeUpdate(sql);
        }

//        Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
//        String url = "jdbc:sqlserver://IP;databaseName=CMDB";
//        Connection conn = DriverManager.getConnection(url, "cmdbadmin", "cmdbadmin!1");
//        System.out.print("connection successfulltttt");
        String SQL = "SELECT * from Data_CMDB_Main";

        ResultSet rs = conn.createStatement().executeQuery(SQL);

        for(int i=0 ; i<rs.getMetaData().getColumnCount(); i++) {
            final int j = i;
            TableColumn<ObservableList<String>, String> col = new TableColumn(rs.getMetaData().getColumnName(i+1));
            col.setCellValueFactory(p -> new ReadOnlyStringWrapper(p.getValue().get(j)));
            tblSoftware.getColumns().add(col);
        }

        while (rs.next()) {
            ObservableList<String> row = FXCollections.observableArrayList();
            for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
                row.add(rs.getString(i));
            }
            data.add(row);
        }
        tblSoftware.setItems(data);
    }

    @Override
    public void start(Stage stage) throws Exception {   
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/fxml/Software.fxml"));
        Parent root1 = (Parent) fxmlLoader.load();
        stage.setScene(new Scene(root1));
        stage.show();
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        try {
            buildData();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    @FXML private void btnSoftwarePressed(){}

    public static void main(String[] args) { launch(args);}    

}
brian
  • 10,619
  • 4
  • 21
  • 79
  • Guys thats fantastic, Brian thankyou for letting me see this working, being new I spent a while searching for a solution and i can now play with scene builder and learn while selecting what i want from the DB. The example James gave i have started on as something to learn "may need assistance later ;) ", it indicates a connection pool is the way to go, which sounds quicker when reading up on that? Can i also ask the "Person" example is this the route most would use when pulling data? Again thank you both for taking the time to help, really really appreciated. – user1483767 May 23 '15 at 18:23