My question is about JavaFX-9.
I am trying to handle two table view in one FXML Controller class. But it is giving me a Null pointer exception. How to solve this?
The first TableView (studentTable) is working and second table(rTable) is not working.
home.java:
package Home;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class home extends Application{
public void start(Stage stage)throws Exception{
Parent root=(Parent) FXMLLoader.load(getClass().getResource("Home.fxml"));
Scene scene=new Scene(root);
stage.setScene(scene);
stage.setTitle("Result Analysis System");
stage.show();
}
public static void main(String[] args){
launch(args);
}
}
homeController.java
package Home;
/*_____________________
Error in this file
_____________________*/
import dbUtils.dbConnection;
//import Home.rControl;
//import Home.resultData;
import javafx.collections.FXCollections;
import javafx.collections.ObservableArray;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
//import javafx.scene.control.DatePicker;
import javafx.scene.control.cell.PropertyValueFactory;
//import Home.resultData;
import java.net.URL;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.ResourceBundle;
public class homeController /*extends resultController*/ implements Initializable{
//Student tab
#FXML
private TextField usn;
#FXML
private TextField name;
#FXML
protected TableView<studentData> studentTable;
#FXML
protected TableColumn<studentData,String> USNcolumn;
#FXML
protected TableColumn<studentData,String> Namecolumn;
//Result tab
#FXML
private TextField rusn;
#FXML
private ComboBox<option> rSelectSem;
#FXML
private TextField rSub1;
#FXML
private TextField rSub2;
#FXML
private TextField rSub3;
#FXML
private TextField rSub4;
#FXML
private TextField rSub5;
#FXML
private TextField rSub6;
#FXML
private TextField rSub7;
#FXML
private TextField rSub8;
#FXML
private Button rAdd;
#FXML
private Button rLoad;
#FXML
private Button rClear;
#FXML
private ComboBox<option> rSelectSem1;
#FXML
private Button rLoad1;
#FXML
private TableView<resultData> rTable;
#FXML
private TableColumn<resultData,String> rColusn;
#FXML
private TableColumn<resultData,String> rColname;
#FXML
private TableColumn<resultData,Integer> rColsub1;
#FXML
private TableColumn<resultData,Integer> rColsub2;
#FXML
private TableColumn<resultData,Integer> rColsub3;
#FXML
private TableColumn<resultData,Integer> rColsub4;
#FXML
private TableColumn<resultData,Integer> rColsub5;
#FXML
private TableColumn<resultData,Integer> rColsub6;
#FXML
private TableColumn<resultData,Integer> rColsub7;
#FXML
private TableColumn<resultData,Integer> rColsub8;
#FXML
private TableColumn<resultData,Integer> rColtotal;
//Analyze tab
#FXML
private ComboBox<option> aSelectSem;
#FXML
private Button aHighmarks;
#FXML
private Button aPassedstudent;
#FXML
private Button aFailedstudent;
#FXML
private Button aListallstudent;
#FXML
private Button adistiction;
#FXML
private Button aFirstclass;
#FXML
private Button aSecondclass;
#FXML
private TableView<analysisData> aTable;
#FXML
private TableColumn<analysisData,String> aColusn;
#FXML
private TableColumn<analysisData,String> aColname;
#FXML
private TableColumn<analysisData,Integer> aColsub1;
#FXML
private TableColumn<analysisData,Integer> aColsub2;
#FXML
private TableColumn<analysisData,Integer> aColsub3;
#FXML
private TableColumn<analysisData,Integer> aColsub4;
#FXML
private TableColumn<analysisData,Integer> aColsub5;
#FXML
private TableColumn<analysisData,Integer> aColsub6;
#FXML
private TableColumn<analysisData,Integer> aColsub7;
#FXML
private TableColumn<analysisData,Integer> aColsub8;
#FXML
private TableColumn<analysisData,Integer> aColtotal;
protected dbConnection dc;
protected ObservableList<studentData> data;
//private ObservableList<resultData> list;
protected String sql = "SELECT * FROM studentDet";
#Override
public void initialize(URL url, ResourceBundle rb){
this.dc = new dbConnection();
this.rSelectSem.setItems(FXCollections.observableArrayList(option.values()));
this.rSelectSem1.setItems(FXCollections.observableArrayList(option.values()));
this.aSelectSem.setItems(FXCollections.observableArrayList(option.values()));
// rTable.setItems(list);
}
//Load student data in student tab
//This is working
#FXML
private void loadStudentData(ActionEvent event) throws SQLException{
try {
Connection conn = dbConnection.getConnection();
this.data = FXCollections.observableArrayList();
ResultSet rs = conn.createStatement().executeQuery(sql);
while (rs.next()){
this.data.add(new studentData(rs.getString(1),rs.getString(2)));
}
}
catch (SQLException e){
System.err.println("error" + e);
}
this.USNcolumn.setCellValueFactory(new PropertyValueFactory<studentData,String>("USN"));
this.Namecolumn.setCellValueFactory(new PropertyValueFactory<studentData,String>( "Name"));
this.studentTable.setItems(null);
this.studentTable.setItems(this.data);
}
//This is working
//Add student in student tab
#FXML
private void addStudent(ActionEvent actionEvent) {
String sqlInsert="INSERT INTO studentDet(USN,Name) VALUES(?,?)";
try {
//here the name is same but it doesn't matter because this is a local variable
Connection conn=dbConnection.getConnection();
PreparedStatement statement=conn.prepareStatement(sqlInsert);
statement.setString(1,this.usn.getText());
statement.setString(2,this.name.getText());
statement.execute();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
//This is working
//Clear feilds in Student tab
#FXML
private void clearFields(ActionEvent actionEvent)
{
this.usn.setText("");
this.name.setText("");
}
#FXML
private void rclearFields(ActionEvent actionEvent)
{
this.rusn.setText("");
this.rSub1.setText("");
this.rSub2.setText("");
this.rSub3.setText("");
this.rSub4.setText("");
this.rSub5.setText("");
this.rSub6.setText("");
this.rSub7.setText("");
this.rSub8.setText("");
}
//This is working
//Add marks to sem in Result tab
#FXML
private void addSemMarks(ActionEvent actionEvent)
{
String sqlInsert;
try {
switch (((option) this.rSelectSem.getValue()).toString()) {
case "SEM1":
sqlInsert="INSERT INTO SEM1(USN,SUB1E,SUB2E,SUB3E,SUB4E,SUB5E,SUB6E,SUB7E,SUB8E) VALUES(?,?,?,?,?,?,?,?,?)";
semMarksAdd(sqlInsert);
break;
case "SEM2":
sqlInsert="INSERT INTO SEM2(USN,SUB1E,SUB2E,SUB3E,SUB4E,SUB5E,SUB6E,SUB7E,SUB8E) VALUES(?,?,?,?,?,?,?,?,?)";
semMarksAdd(sqlInsert);
break;
case "SEM3":
sqlInsert="INSERT INTO SEM3(USN,SUB1E,SUB2E,SUB3E,SUB4E,SUB5E,SUB6E,SUB7E,SUB8E) VALUES(?,?,?,?,?,?,?,?,?)";
semMarksAdd(sqlInsert);
break;
case "SEM4":
sqlInsert="INSERT INTO SEM4(USN,SUB1E,SUB2E,SUB3E,SUB4E,SUB5E,SUB6E,SUB7E,SUB8E) VALUES(?,?,?,?,?,?,?,?,?)";
semMarksAdd(sqlInsert);
break;
case "SEM5":
sqlInsert="INSERT INTO SEM5(USN,SUB1E,SUB2E,SUB3E,SUB4E,SUB5E,SUB6E,SUB7E,SUB8E) VALUES(?,?,?,?,?,?,?,?,?)";
semMarksAdd(sqlInsert);
break;
case "SEM6":
sqlInsert="INSERT INTO SEM6(USN,SUB1E,SUB2E,SUB3E,SUB4E,SUB5E,SUB6E,SUB7E,SUB8E) VALUES(?,?,?,?,?,?,?,?,?)";
semMarksAdd(sqlInsert);
break;
case "SEM7":
sqlInsert="INSERT INTO SEM7(USN,SUB1E,SUB2E,SUB3E,SUB4E,SUB5E,SUB6E,SUB7E,SUB8E) VALUES(?,?,?,?,?,?,?,?,?)";
semMarksAdd(sqlInsert);
break;
case "SEM8":
sqlInsert="INSERT INTO SEM8(USN,SUB1E,SUB2E,SUB3E,SUB4E,SUB5E,SUB6E,SUB7E,SUB8E) VALUES(?,?,?,?,?,?,?,?,?)";
semMarksAdd(sqlInsert);
break;
}
}
catch (Exception ex){
ex.printStackTrace();
}
}
private void semMarksAdd(String sqlinsert){
//String sqlInsert="INSERT INTO SEM1(USN,SUB1E,SUB2E,SUB3E,SUB4E,SUB5E,SUB6E,SUB7E,SUB8E) VALUES(?,?,?,?,?,?,?,?,?)";
try {
//here the name is same but it doesn't matter because this is a local variable
Connection conn=dbConnection.getConnection();
PreparedStatement statement=conn.prepareStatement(sqlinsert);
statement.setString(1,this.rusn.getText());
statement.setString(2,this.rSub1.getText());
statement.setString(3,this.rSub2.getText());
statement.setString(4,this.rSub3.getText());
statement.setString(5,this.rSub4.getText());
statement.setString(6,this.rSub5.getText());
statement.setString(7,this.rSub6.getText());
statement.setString(8,this.rSub7.getText());
statement.setString(9,this.rSub8.getText());
statement.execute();
conn.close();
}
catch (SQLException e) {
e.printStackTrace();
}
}
//#########################################################Stable upto here
//From here it is giving error
//TO LOAD STUDENT MARKS DATA IN RESULT TABLE
/*#FXML
private void loadResultData(ActionEvent actionEvent){
String sqlLoad;
try {
switch (((option) this.rSelectSem.getValue()).toString()) {
case "SEM1":
sqlLoad = "SELECT USN,SUB1E,SUB2E,SUB3E,SUB4E,SUB5E,SUB6E,SUB7E,SUB8E,TOTAL FROM SEM1";
loadRdata(sqlLoad);
break;
case "SEM2":
sqlLoad = "SELECT USN,SUB1E,SUB2E,SUB3E,SUB4E,SUB5E,SUB6E,SUB7E,SUB8E,TOTAL FROM SEM2";
loadRdata(sqlLoad);
break;
case "SEM3":
sqlLoad = "SELECT USN,SUB1E,SUB2E,SUB3E,SUB4E,SUB5E,SUB6E,SUB7E,SUB8E,TOTAL FROM SEM3";
loadRdata(sqlLoad);
break;
case "SEM4":
sqlLoad = "SELECT USN,SUB1E,SUB2E,SUB3E,SUB4E,SUB5E,SUB6E,SUB7E,SUB8E,TOTAL FROM SEM4";
loadRdata(sqlLoad);
break;
case "SEM5":
sqlLoad = "SELECT USN,SUB1E,SUB2E,SUB3E,SUB4E,SUB5E,SUB6E,SUB7E,SUB8E,TOTAL FROM SEM5";
loadRdata(sqlLoad);
break;
case "SEM6":
sqlLoad = "SELECT USN,SUB1E,SUB2E,SUB3E,SUB4E,SUB5E,SUB6E,SUB7E,SUB8E,TOTAL FROM SEM6";
loadRdata(sqlLoad);
break;
case "SEM7":
sqlLoad = "SELECT USN,SUB1E,SUB2E,SUB3E,SUB4E,SUB5E,SUB6E,SUB7E,SUB8E,TOTAL FROM SEM7";
loadRdata(sqlLoad);
break;
case "SEM8":
sqlLoad = "SELECT USN,SUB1E,SUB2E,SUB3E,SUB4E,SUB5E,SUB6E,SUB7E,SUB8E,TOTAL FROM SEM8";
loadRdata(sqlLoad);
break;
}
}
catch (Exception ex){
ex.printStackTrace();
}
}*/
#FXML
public void loadResultData(ActionEvent actionEvent) {
String sqlLoad = "SELECT USN,SUB1E,SUB2E,SUB3E,SUB4E,SUB5E,SUB6E,SUB7E,SUB8E,TOTAL FROM SEM1";
loadRdata(sqlLoad); //Error here
}
/*private void loadResultData(ActionEvent actionEvent) {
String sqlLoad = "SELECT USN,SUB1E,SUB2E,SUB3E,SUB4E,SUB5E,SUB6E,SUB7E,SUB8E,TOTAL FROM SEM1";
rc.loadRdata(sqlLoad);
}*/
private ObservableList<resultData> list = FXCollections.observableArrayList();
private void loadRdata(String sqlLoad) {
try {
Connection conn = dbConnection.getConnection();
this.list = FXCollections.observableArrayList();
//System.out.println("Hello"); //working
ResultSet rs = conn.createStatement().executeQuery(sqlLoad);
while (rs.next()) {
//System.out.println(rs.getString(1)); //Working
this.list.add(new resultData(rs.getString(1), rs.getInt(2), rs.getInt(3), rs.getInt(4), rs.getInt(5), rs.getInt(6), rs.getInt(7), rs.getInt(8), rs.getInt(9), rs.getInt(10)));
}
// this.rColusn.setCellValueFactory("Helloworld"); //working
this.rColusn.setCellValueFactory(new PropertyValueFactory<resultData, String>("rColUsn"));
this.rColsub1.setCellValueFactory(new PropertyValueFactory<resultData, Integer>("rColSub1"));
this.rColsub2.setCellValueFactory(new PropertyValueFactory<resultData, Integer>("rColSub2"));
this.rColsub3.setCellValueFactory(new PropertyValueFactory<resultData, Integer>("rColSub3"));
this.rColsub4.setCellValueFactory(new PropertyValueFactory<resultData, Integer>("rColSub4"));
this.rColsub5.setCellValueFactory(new PropertyValueFactory<resultData, Integer>("rColSub5"));
this.rColsub6.setCellValueFactory(new PropertyValueFactory<resultData, Integer>("rColSub6"));
this.rColsub7.setCellValueFactory(new PropertyValueFactory<resultData, Integer>("rColSub7"));
this.rColsub8.setCellValueFactory(new PropertyValueFactory<resultData, Integer>("rColSub8"));
this.rColtotal.setCellValueFactory(new PropertyValueFactory<resultData, Integer>("rColTotal"));
System.out.println("after block1");
list.clear();
System.out.println("after block2");
rTable.setItems(list);// CAUSING NULL POINTER EXCEPTION
System.out.println("after block3");//NOT PRINTING
}
catch (Exception e) {//System.out.println(" "+e);
System.err.println("error" + e);
}
}
}
resultData.java
package Home;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class resultData {
private final StringProperty rColUsn;
//private final StringProperty rColName;
private final IntegerProperty rColSub1;
private final IntegerProperty rColSub2;
private final IntegerProperty rColSub3;
private final IntegerProperty rColSub4;
private final IntegerProperty rColSub5;
private final IntegerProperty rColSub6;
private final IntegerProperty rColSub7;
private final IntegerProperty rColSub8;
private final IntegerProperty rColTotal;
public resultData(String usn,Integer sub1,Integer sub2,Integer sub3,Integer sub4,Integer sub5,Integer sub6,Integer sub7,Integer sub8,Integer total){
System.out.println("result data");// TWO TIMES IT WORKS,BUT THE THERE ARE 10 COLUMNS AND IT SHOULD PRINT 10 TIMES.
rColUsn = new SimpleStringProperty(usn);
//this.rColName = new SimpleStringProperty(name);
rColSub1 = new SimpleIntegerProperty(sub1);
rColSub2 = new SimpleIntegerProperty(sub2);
rColSub3 = new SimpleIntegerProperty(sub3);
rColSub4 = new SimpleIntegerProperty(sub4);
rColSub5 = new SimpleIntegerProperty(sub5);
rColSub6 = new SimpleIntegerProperty(sub6);
rColSub7 = new SimpleIntegerProperty(sub7);
rColSub8 = new SimpleIntegerProperty(sub8);
rColTotal = new SimpleIntegerProperty(total);
}
public String getrColUsn() {
return rColUsn.get();
}
public StringProperty rColUsnProperty() {
return rColUsn;
}
public void setrColUsn(String rColUsn) {
this.rColUsn.set(rColUsn);
}
public int getrColSub1() {
return rColSub1.get();
}
public IntegerProperty rColSub1Property() {
return rColSub1;
}
public void setrColSub1(int rColSub1) {
this.rColSub1.set(rColSub1);
}
public int getrColSub2() {
return rColSub2.get();
}
public IntegerProperty rColSub2Property() {
return rColSub2;
}
public void setrColSub2(int rColSub2) {
this.rColSub2.set(rColSub2);
}
public int getrColSub3() {
return rColSub3.get();
}
public IntegerProperty rColSub3Property() {
return rColSub3;
}
public void setrColSub3(int rColSub3) {
this.rColSub3.set(rColSub3);
}
public int getrColSub4() {
return rColSub4.get();
}
public IntegerProperty rColSub4Property() {
return rColSub4;
}
public void setrColSub4(int rColSub4) {
this.rColSub4.set(rColSub4);
}
public int getrColSub5() {
return rColSub5.get();
}
public IntegerProperty rColSub5Property() {
return rColSub5;
}
public void setrColSub5(int rColSub5) {
this.rColSub5.set(rColSub5);
}
public int getrColSub6() {
return rColSub6.get();
}
public IntegerProperty rColSub6Property() {
return rColSub6;
}
public void setrColSub6(int rColSub6) {
this.rColSub6.set(rColSub6);
}
public int getrColSub7() {
return rColSub7.get();
}
public IntegerProperty rColSub7Property() {
return rColSub7;
}
public void setrColSub7(int rColSub7) {
this.rColSub7.set(rColSub7);
}
public int getrColSub8() {
return rColSub8.get();
}
public IntegerProperty rColSub8Property() {
return rColSub8;
}
public void setrColSub8(int rColSub8) {
this.rColSub8.set(rColSub8);
}
public int getrColTotal() {
return rColTotal.get();
}
public IntegerProperty rColTotalProperty() {
return rColTotal;
}
public void setrColTotal(int rColTotal) {
this.rColTotal.set(rColTotal);
}
}
studentData.java
package Home;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class studentData{
private final StringProperty USN;
private final StringProperty Name;
public studentData(String usn,String name){
this.USN=new SimpleStringProperty(usn);
this.Name=new SimpleStringProperty(name);
}
public String getUSN() {
return USN.get();
}
public StringProperty USNProperty() {
return USN;
}
public void setUSN(String USN) {
this.USN.set(USN);
}
public String getName() {
return Name.get();
}
public StringProperty nameProperty() {
return Name;
}
public void setName(String name) {
this.Name.set(name);
}
}
Commnd Line Output:
"C:\Program Files\Java\jdk-9.0.1\bin\java" "-javaagent:C:\Program
Files\JetBrains\IntelliJ IDEA 2017.2.5\lib\idea_rt.jar=55700:C:\Program
Files\JetBrains\IntelliJ IDEA 2017.2.5\bin" -Dfile.encoding=UTF-8 -
/* WHEN CLICKING TABLE DISPLAY BUTTON FIRST TIME */
result data
result data
after block1
after block2
errorjava.lang.NullPointerException
/* WHEN CLICKING TABLE DISPLAY BUTTON SECOND TIME*/
errorjava.lang.NullPointerException
result data
result data
after block1
after block2
You need to set a value into the table.
This is not going to work (remove from your loadRdata method):
this.rTable.setItems(null); // giving error here:Null pointer Exception
this.rTable.setItems(this.list);
Initialize your ObservableList first:
private ObservableList<resultData> list = FXCollections.observableArrayList();
Then in your method loadRdata clear the values rather than initializing like you are now.
list.clear();
At the end of you initialize() method you can add the values
rTable.setItems(list);
I'm working with Javafx and I'm struggling to get a sorted table in place when using background Tasks to update. In the code here, which can be run standalone, I update a table in background.
What I'd like to do is that this table gets updated, and stays sorted in chronological order, so older train times appear at the top, and later ones at the bottom. The example produces times that are the opposite order on purpose, to see if sorting works.
I run some tests before I added concurrent update to the table, and the way I would do it is by calling:
private final ObservableList<StationBoardLine> data = FXCollections.observableArrayList(
new StationBoardLine("RE", "17:14", "Basel Bad Bf", "Basel SBB", "+3", "RE 5343"));
SortedList<StationBoardLine> sorted = new SortedList<>(data, new DelayComparator());
table.setItems(sorted);
However, now I'm not setting the items, but using the background task together with ReadOnlyObjectProperty and ReadOnlyObjectWrapper to append to it.
So, my question is, how can I make sure that as items are added, the list remains ordered? I've tried to see if I could reorder the list inside the call to Platform.runLater but didn't seem to work.
The link between the task updating the table and the table is set is here:
table.itemsProperty().bind(task.partialResultsProperty());
Thanks for help,
Galder
The way I would do it is by updating an ObservableList by the background task and use it as a "source" to create a SortedList. This SortedList would then act as the source of "items" to the TableView.
A general structure would be :
public class MyClass {
private TableView<T> tableView = new TableView;
private ObservableList<T> sourceList = FXCollections.observableArrayList();
public MyClass() {
...
SortedList<T> sortedList = new SortedList<>(sourceList, new MyComparator());
tableView.setItems(sortedList);
...
new Task<Void> {
protected Void call() {
... // Some background data fetch
Platform.runLater(() -> sourceList.add(data));
return null;
}
};
}
}
For your scenario, I would go with something that you already have. Therefore, instead of creating a new ObservableList to be used as a source for your SortedList, I would use the list returned by Task#getPartialResults().
The DelayComparator uses the value of the delay to compare and show the data in the TableView.
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.SortedList;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import java.util.Comparator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class App extends Application {
private TableView<StationBoardLine> table = new TableView<>();
private final ExecutorService exec = Executors.newSingleThreadExecutor();
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
BorderPane root = new BorderPane();
Scene scene = new Scene(root, 800, 600);
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
table.setEditable(true);
TableColumn typeCol = getTableCol("Type", 10, "type");
TableColumn departureCol = getTableCol("Departure", 30, "departure");
TableColumn stationCol = getTableCol("Station", 200, "station");
TableColumn destinationCol = getTableCol("Destination", 200, "destination");
TableColumn delayCol = getTableCol("Delay", 20, "delay");
TableColumn trainName = getTableCol("Train Name", 50, "trainName");
table.getColumns().addAll(
typeCol, departureCol, stationCol, destinationCol, delayCol, trainName);
root.setCenter(table);
PartialResultsTask task = new PartialResultsTask();
SortedList<StationBoardLine> sorted = new SortedList<>(task.getPartialResults(), new DelayComparator());
table.setItems(sorted);
exec.submit(task);
stage.setTitle("Swiss Transport Delays Board");
stage.setScene(scene);
stage.show();
}
private TableColumn getTableCol(String colName, int minWidth, String fieldName) {
TableColumn<StationBoardLine, String> typeCol = new TableColumn<>(colName);
typeCol.setMinWidth(minWidth);
typeCol.setCellValueFactory(new PropertyValueFactory<>(fieldName));
return typeCol;
}
static final class DelayComparator implements Comparator<StationBoardLine> {
#Override
public int compare(StationBoardLine o1, StationBoardLine o2) {
return o1.getDelay().compareTo(o2.getDelay());
}
}
public class PartialResultsTask extends Task<Void> {
private ObservableList<StationBoardLine>partialResults = FXCollections.observableArrayList();
public final ObservableList<StationBoardLine> getPartialResults() {
return partialResults;
}
#Override protected Void call() throws Exception {
System.out.println("Creating station board entries...");
for (int i=5; i >= 1; i--) {
Thread.sleep(1000);
if (isCancelled()) break;
StationBoardLine l = new StationBoardLine(
"ICE", "16:" + i, "Basel Bad Bf", "Chur", String.valueOf(i), "ICE 75");
Platform.runLater(() -> partialResults.add(l));
}
return null;
}
}
public static final class StationBoardLine {
private final SimpleStringProperty type;
private final SimpleStringProperty departure;
private final SimpleStringProperty station;
private final SimpleStringProperty destination;
private final SimpleStringProperty delay;
private final SimpleStringProperty trainName;
StationBoardLine(String type,
String departure,
String station,
String destination,
String delay,
String trainName) {
this.type = new SimpleStringProperty(type);
this.departure = new SimpleStringProperty(departure);
this.station = new SimpleStringProperty(station);
this.destination = new SimpleStringProperty(destination);
this.delay = new SimpleStringProperty(delay);
this.trainName = new SimpleStringProperty(trainName);
}
public String getType() {
return type.get();
}
public SimpleStringProperty typeProperty() {
return type;
}
public void setType(String type) {
this.type.set(type);
}
public String getDeparture() {
return departure.get();
}
public SimpleStringProperty departureProperty() {
return departure;
}
public void setDeparture(String departure) {
this.departure.set(departure);
}
public String getStation() {
return station.get();
}
public SimpleStringProperty stationProperty() {
return station;
}
public void setStation(String station) {
this.station.set(station);
}
public String getDestination() {
return destination.get();
}
public SimpleStringProperty destinationProperty() {
return destination;
}
public void setDestination(String destination) {
this.destination.set(destination);
}
public String getDelay() {
return delay.get();
}
public SimpleStringProperty delayProperty() {
return delay;
}
public void setDelay(String delay) {
this.delay.set(delay);
}
public String getTrainName() {
return trainName.get();
}
public SimpleStringProperty trainNameProperty() {
return trainName;
}
public void setTrainName(String trainName) {
this.trainName.set(trainName);
}
}
}
How do I get the name of the column of a textfield inside a javaFX table?
I need this to check the value of the cells only in the "text2" column. I tried it with textfield.parent() but I didn't get a useful result.Edit: I just removed some unnessary log, which was not helpful for understanding.Now it is more convenient.
Here is my Code:
import java.util.ArrayList;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TextArea;
import javafx.util.Callback;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
/*interface inside_table
{
public String get_column_name
}*/
public class Supermain extends Application {
#Override
public void start(Stage primaryStage) {
ArrayList myindizes=new ArrayList();
final TableView<myTextRow> table = new TableView<>();
table.setEditable(true);
table.setStyle("-fx-text-wrap: true;");
//Table columns
TableColumn<myTextRow, String> clmID = new TableColumn<>("ID");
clmID.setMinWidth(160);
clmID.setCellValueFactory(new PropertyValueFactory<>("ID"));
TableColumn<myTextRow, String> clmtext = new TableColumn<>("Text");
clmtext.setMinWidth(160);
clmtext.setCellValueFactory(new PropertyValueFactory<>("text"));
clmtext.setCellFactory(new TextFieldCellFactory());
TableColumn<myTextRow, String> clmtext2 = new TableColumn<>("Text2");
clmtext2.setMinWidth(160);
clmtext2.setCellValueFactory(new PropertyValueFactory<>("text2"));
clmtext2.setCellFactory(new TextFieldCellFactory());
//Add data
final ObservableList<myTextRow> data = FXCollections.observableArrayList(
new myTextRow(5, "Lorem","bla"),
new myTextRow(2, "Ipsum","bla")
);
table.getColumns().addAll(clmID, clmtext,clmtext2);
table.setItems(data);
HBox hBox = new HBox();
hBox.setSpacing(5.0);
hBox.setPadding(new Insets(5, 5, 5, 5));
Button btn = new Button();
btn.setText("Get Data");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
for (myTextRow data1 : data) {
System.out.println("data:" + data1.getText2());
}
}
});
hBox.getChildren().add(btn);
BorderPane pane = new BorderPane();
pane.setTop(hBox);
pane.setCenter(table);
primaryStage.setScene(new Scene(pane, 640, 480));
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
public static class TextFieldCellFactory
implements Callback<TableColumn<myTextRow, String>, TableCell<myTextRow, String>> {
#Override
public TableCell<myTextRow, String> call(TableColumn<myTextRow, String> param) {
TextFieldCell textFieldCell = new TextFieldCell();
return textFieldCell;
}
public static class TextFieldCell extends TableCell<myTextRow, String> {
private TextArea textField;
private StringProperty boundToCurrently = null;
private String last_text;
public TextFieldCell() {
textField = new TextArea();
textField.setWrapText(true);
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
last_text="";
this.setGraphic(textField);
textField.focusedProperty().addListener((obs, wasFocused, isNowFocused) -> {
//only if textfield is in the text2 column
if(isNowFocused){last_text=textField.getText(); System.out.println("NOW focus "+last_text);}
if (! isNowFocused && ! isValid(textField.getText())) {
textField.setText(last_text);
textField.selectAll();
System.out.println("blur");
}
});
}
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (!empty) {
// Show the Text Field
this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
// myindizes.add(getIndex());
// Retrieve the actual String Property that should be bound to the TextField
// If the TextField is currently bound to a different StringProperty
// Unbind the old property and rebind to the new one
ObservableValue<String> ov = getTableColumn().getCellObservableValue(getIndex());
SimpleStringProperty sp = (SimpleStringProperty) ov;
if (this.boundToCurrently == null) {
this.boundToCurrently = sp;
this.textField.textProperty().bindBidirectional(sp);
} else if (this.boundToCurrently != sp) {
this.textField.textProperty().unbindBidirectional(this.boundToCurrently);
this.boundToCurrently = sp;
this.textField.textProperty().bindBidirectional(this.boundToCurrently);
}
double height = real_lines_height(textField.getText(), this.getWidth(), 30, 22);
textField.setPrefHeight(height);
textField.setMaxHeight(height);
textField.setMaxHeight(Double.MAX_VALUE);
// if height bigger than the biggest height in the row
//-> change all heights of the row(textfields ()typeof textarea) to this height
// else leave the height as it is
//System.out.println("item=" + item + " ObservableValue<String>=" + ov.getValue());
//this.textField.setText(item); // No longer need this!!!
} else {
this.setContentDisplay(ContentDisplay.TEXT_ONLY);
}
}//update
private boolean isValid(String s){
if(s.length()<7){return true;}
return false;
}
}
}
public class myTextRow {
private final SimpleIntegerProperty ID;
private final SimpleStringProperty text;
private final SimpleStringProperty text2;
public myTextRow(int ID, String text,String text2) {
this.ID = new SimpleIntegerProperty(ID);
this.text = new SimpleStringProperty(text);
this.text2 = new SimpleStringProperty(text2);
}
//setter
public void setID(int id) {
this.ID.set(id);
}
public void setText(String text) {
this.text.set(text);
}
public void setText2(String text) {
this.text2.set(text);
}
//getter
public int getID() {
return ID.get();
}
public String getText() {
return text.get();
}
public String getText2() {
return text2.get();
}
//properties
public StringProperty textProperty() {
return text;
}
public StringProperty text2Property() {
return text2;
}
public IntegerProperty IDProperty() {
return ID;
}
}
private static double real_lines_height(String s, double width, double heightCorrector, double widthCorrector) {
HBox h = new HBox();
Label l = new Label("Text");
h.getChildren().add(l);
Scene sc = new Scene(h);
l.applyCss();
double line_height = l.prefHeight(-1);
int new_lines = s.replaceAll("[^\r\n|\r|\n]", "").length();
// System.out.println("new lines= "+new_lines);
String[] lines = s.split("\r\n|\r|\n");
// System.out.println("line count func= "+ lines.length);
int count = 0;
//double rest=0;
for (int i = 0; i < lines.length; i++) {
double text_width = get_text_width(lines[i]);
double plus_lines = Math.ceil(text_width / (width - widthCorrector));
if (plus_lines > 1) {
count += plus_lines;
//rest+= (text_width / (width-widthCorrector)) - plus_lines;
} else {
count += 1;
}
}
//count+=(int) Math.ceil(rest);
count += new_lines - lines.length;
return count * line_height + heightCorrector;
}
private static double get_text_width(String s) {
HBox h = new HBox();
Label l = new Label(s);
l.setWrapText(false);
h.getChildren().add(l);
Scene sc = new Scene(h);
l.applyCss();
return l.prefWidth(-1);
}
}
There are probably (way) better ways to organize this, but probably the cleanest fix is just to define a boolean validate parameter to the constructor of your cell implementation. (You really don't want the logic to be "if the title of the column is equal to some specific text, then validate". You would be utterly screwed when your boss came in to the office and asked you to internationalize the application, or even just change the title of the column, for example.)
Using an entire inner class just to implement the callback seems completely redundant, but keeping that you would have to pass the parameter through it:
public static class TextFieldCellFactory
implements Callback<TableColumn<myTextRow, String>, TableCell<myTextRow, String>> {
private final boolean validate ;
public TextFieldCellFactory(boolean validate) {
this.validate = validate ;
}
#Override
public TableCell<myTextRow, String> call(TableColumn<myTextRow, String> param) {
TextFieldCell textFieldCell = new TextFieldCell(validate);
return textFieldCell;
}
public static class TextFieldCell extends TableCell<myTextRow, String> {
private TextArea textField;
private StringProperty boundToCurrently = null;
private String last_text;
public TextFieldCell(boolean validate) {
textField = new TextArea();
textField.setWrapText(true);
textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
last_text="";
this.setGraphic(textField);
if (validate) {
textField.focusedProperty().addListener((obs, wasFocused, isNowFocused) -> {
//only if textfield is in the text2 column
if(isNowFocused){last_text=textField.getText(); System.out.println("NOW focus "+last_text);}
if (! isNowFocused && ! isValid(textField.getText())) {
textField.setText(last_text);
textField.selectAll();
System.out.println("blur");
}
});
}
}
// ...
}
Then of course you just do
TableColumn<myTextRow, String> clmtext = new TableColumn<>("Text");
clmtext.setMinWidth(160);
clmtext.setCellValueFactory(new PropertyValueFactory<>("text"));
clmtext.setCellFactory(new TextFieldCellFactory(false));
TableColumn<myTextRow, String> clmtext2 = new TableColumn<>("Text2");
clmtext2.setMinWidth(160);
clmtext2.setCellValueFactory(new PropertyValueFactory<>("text2"));
clmtext2.setCellFactory(new TextFieldCellFactory(true));
(To properly answer your question, you can get the text of the column from within the cell to which it is attached with getTableColumn().getText(), but as I pointed out, actually basing the logic on the value displayed in a column header will make your code completely unmaintainable.)
And I guess for completeness, I should also mention that your TextFieldCellFactory class looks like it is not really serving any purpose. I would remove it entirely and just have the TextFieldCell class, and do
TableColumn<myTextRow, String> clmtext = new TableColumn<>("Text");
clmtext.setMinWidth(160);
clmtext.setCellValueFactory(new PropertyValueFactory<>("text"));
clmtext.setCellFactory(c -> new TextFieldCell(false));
TableColumn<myTextRow, String> clmtext2 = new TableColumn<>("Text2");
clmtext2.setMinWidth(160);
clmtext2.setCellValueFactory(new PropertyValueFactory<>("text2"));
clmtext2.setCellFactory(c -> new TextFieldCell(true));