Javafx dynamically populate table rows and columnheads from sql query [duplicate] - javafx

I've been trying to load a TableView with data queried from a database, but can't seem to get it to work.
This is my first attempt at trying to populate a TableView with database query items – in case my code seems mungled and far from good.
The FXML was done via JavaFX SceneBuilder.
This is the database query class:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.TableView;
public class StudentInfo {
static String JDBC_DRIVER = "org.h2.Driver";
static String DB_URL = "jdbc:h2:file:C:/WAKILI/WAKILIdb";
// Database credentials
static final String USER = "sa";
static final String PASS = "";
public static Connection conn = null;
#FXML
private TableView<StudentInfo> lovelyStudents;
private ObservableList data;
// Public static ObservableList<COA> getAllCOA(){
public void getAllstudentInfo() {
Statement st = null;
ResultSet rs;
String driver = "org.h2.Driver";
try {
Class.forName(driver);
conn = DriverManager.getConnection(DB_URL, USER, PASS);
st = conn.createStatement();
String recordQuery = ("SELECT id, KIWI FROM KIWI");
rs = st.executeQuery(recordQuery);
while (rs.next()) {
ObservableList row = FXCollections.observableArrayList();
for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
row.add(rs.getString(i));
System.out.println(row);
}
data.add(row);
}
lovelyStudents.setItems(data);
} catch (ClassNotFoundException | SQLException ex) {
// CATCH SOMETHING
}
}
}
This is the FXML script generated via JavaFX scene builder:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="700.0" xmlns:fx="http://javafx.com/fxml" fx:controller="wakiliproject.SampleController">
<children>
<TableView prefHeight="400.0" prefWidth="700.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<columns>
<TableColumn prefWidth="75.0" text="Column X" />
</columns>
</TableView>
</children>
</AnchorPane>

Here is the best solution for the filling data to the tableView From the database.
import java.sql.Connection;
import java.sql.ResultSet;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.scene.control.TableView;
import javafx.stage.Stage;
import javafx.util.Callback;
/**
*
* #author Narayan
*/
public class DynamicTable extends Application{
//TABLE VIEW AND DATA
private ObservableList<ObservableList> data;
private TableView tableview;
//MAIN EXECUTOR
public static void main(String[] args) {
launch(args);
}
//CONNECTION DATABASE
public void buildData(){
Connection c ;
data = FXCollections.observableArrayList();
try{
c = DBConnect.connect();
//SQL FOR SELECTING ALL OF CUSTOMER
String SQL = "SELECT * from CUSTOMer";
//ResultSet
ResultSet rs = c.createStatement().executeQuery(SQL);
/**********************************
* TABLE COLUMN ADDED DYNAMICALLY *
**********************************/
for(int i=0 ; i<rs.getMetaData().getColumnCount(); i++){
//We are using non property style for making dynamic table
final int j = i;
TableColumn col = new TableColumn(rs.getMetaData().getColumnName(i+1));
col.setCellValueFactory(new Callback<CellDataFeatures<ObservableList,String>,ObservableValue<String>>(){
public ObservableValue<String> call(CellDataFeatures<ObservableList, String> param) {
return new SimpleStringProperty(param.getValue().get(j).toString());
}
});
tableview.getColumns().addAll(col);
System.out.println("Column ["+i+"] ");
}
/********************************
* Data added to ObservableList *
********************************/
while(rs.next()){
//Iterate Row
ObservableList<String> row = FXCollections.observableArrayList();
for(int i=1 ; i<=rs.getMetaData().getColumnCount(); i++){
//Iterate Column
row.add(rs.getString(i));
}
System.out.println("Row [1] added "+row );
data.add(row);
}
//FINALLY ADDED TO TableView
tableview.setItems(data);
}catch(Exception e){
e.printStackTrace();
System.out.println("Error on Building Data");
}
}
#Override
public void start(Stage stage) throws Exception {
//TableView
tableview = new TableView();
buildData();
//Main Scene
Scene scene = new Scene(tableview);
stage.setScene(scene);
stage.show();
}
}
Here is the Reference
Thanks..

If Database contains different types of data, not only String, then column type assigning is better to make dynamic:
package sample;
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
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.sql.*;
import java.util.ArrayList;
import java.util.TimeZone;
//Author: Yerbol
//SQL database "sqlbase_schema" contains a Table "sqlbase_table" with 3 columns: "id" (Integer(INT(11))), "name" (String(VARCHAR(45))), "married" (Boolean(TINYINT(1)));
public class Main extends Application {
private TableView<Person> tableView = new TableView<>();
#Override
public void start(Stage primaryStage) throws SQLException, ClassNotFoundException {
//Show window
buildData();
Parent root = tableView;
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
public void buildData() throws ClassNotFoundException, SQLException {
Connection dbConnection;
//SQL Database connection params
String dbHost = "localhost";
String dbPort = "3306";
String dbUser = "root";
String dbPassword = "12345";
String dbName = "sqlbase_schema";
String dbTableName = "sqlbase_table";
String select = "SELECT * FROM " + dbTableName;
String connectionString = "jdbc:mysql://" + dbHost + ":" + dbPort +"/" + dbName+"?useLegacyDatetimeCode=false&amp&serverTimezone=" + TimeZone.getDefault().getID();
Class.forName("com.mysql.cj.jdbc.Driver");
//Connecting to Database
dbConnection = DriverManager.getConnection(connectionString, dbUser, dbPassword);
//Extracting data from Databasee
ResultSet resultSet = null;
try {
PreparedStatement preparedStatement = dbConnection.prepareStatement(select);
resultSet = preparedStatement.executeQuery();
} catch (SQLException e) {
e.printStackTrace();
}
ObservableList dbData = FXCollections.observableArrayList(dataBaseArrayList(resultSet));
//Giving readable names to columns
for(int i=0 ; i<resultSet.getMetaData().getColumnCount(); i++) {
TableColumn column = new TableColumn<>();
switch (resultSet.getMetaData().getColumnName(i+1)) {
case "id":
column.setText("ID #");
break;
case "name":
column.setText("Person Name");
break;
case "married":
column.setText("Marital Status");
break;
default: column.setText(resultSet.getMetaData().getColumnName(i+1)); //if column name in SQL Database is not found, then TableView column receive SQL Database current column name (not readable)
break;
}
column.setCellValueFactory(new PropertyValueFactory<>(resultSet.getMetaData().getColumnName(i+1))); //Setting cell property value to correct variable from Person class.
tableView.getColumns().add(column);
}
//Filling up tableView with data
tableView.setItems(dbData);
}
public class Person {
IntegerProperty id = new SimpleIntegerProperty(); //variable names should be exactly as column names in SQL Database Table. In case if you want to use <int> type instead of <IntegerProperty>, then you need to use getter/setter procedures instead of xxxProperty() below
StringProperty name = new SimpleStringProperty();
BooleanProperty married = new SimpleBooleanProperty();
public IntegerProperty idProperty() { //name should be exactly like this [IntegerProperty variable name (id) + (Property) = idProperty] (case sensitive)
return id;
}
public StringProperty nameProperty() {
return name;
}
public BooleanProperty marriedProperty() {
return married;
}
public Person(int idValue, String nameValue, boolean marriedValue) {
id.set(idValue);
name.set(nameValue);
married.set(marriedValue);
}
Person(){}
}
//extracting data from ResulSet to ArrayList
private ArrayList dataBaseArrayList(ResultSet resultSet) throws SQLException {
ArrayList<Person> data = new ArrayList<>();
while (resultSet.next()) {
Person person = new Person();
person.id.set(resultSet.getInt("id"));
person.name.set(resultSet.getString("name"));
person.married.set(resultSet.getBoolean("married"));
data.add(person);
}
return data;
}
public static void main(String[] args) {
launch(args);
}
}
In this example SQL database "sqlbase_schema" contains a Table "sqlbase_table" with 3 columns: "id" (Integer(INT(11))), "name" (String(VARCHAR(45))), "married (Boolean(TINYINT(1)));

public TableView queryToTable(String sql) {
TableView result = new TableView();
ObservableList data = FXCollections.observableArrayList();
jdbcTemplate.query(sql, (rs)->{
for(int i=0 ; i<rs.getMetaData().getColumnCount(); i++){
final int j = i;
TableColumn col = new TableColumn(rs.getMetaData().getColumnName(i+1));
col.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<ObservableList,String>,ObservableValue<String>>(){
public ObservableValue<String> call(TableColumn.CellDataFeatures<ObservableList, String> param) {
return new SimpleStringProperty(param.getValue().get(j).toString());
}
});
result.getColumns().addAll(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);
}
return null;
});
return result;
}

Related

JavaFX8 How to request focus on graphic nodes in a tableview while traversing with TAB or other key?

I have a TableView which contains textual and graphical content (combo boxes, check boxes etc).
When I traverse the cells using the keyboard and arrive at a cell that contains a graphic element, I would like the graphic to be selected so that I can, for example, hit F4 and have a combo list drop down, or hit the space bar and have a toggle button change state.
However, at the moment, when I TAB (or other key) to a cell, the cell containing the graphic is selected and I'm forced to use the mouse to manipulate the graphic.
How would I go about selecting the graphic element itself, rather than the cell that contains it?
IE. This is what it's doing now when I TAB into a non-textual cell:
How can I get it to do this?
I've tried several ways of getting the cell graphic but it's always null.
UPDATE:
I've done more work and can now get to the cell graphic. It was a Java newbie error. Apologies!
However, while I can now get the graphic, I still haven't been able to select or focus on it. Could anyone tell me how to do that please? Many thanks!
Here are excerpts from my updated code using combo boxes and TABbing as an example.
Key events are trapped in a generic setOnKeyPressed handler at the TableView level. Here is the code for TAB. I've indicated the places where I'm stuck.
} else if ( event.getCode() == KeyCode.TAB ) {
tv.getSelectionModel().selectRightCell();
endOfRowCheck(tv, event, pos, firstCol, maxCols);
event.consume();
//==> IS IT BETTER TO USE THE FOCUS MODEL OR THE SELECTION MODEL? BOTH GIVE THE CELL GRAPHIC.
//==> IS THERE A BETTER WAY OF GETTING THE CELL GRAPHIC?
TablePosition<S, ?> focussedPos = tv.getFocusModel().getFocusedCell();
TableColumn tableColumn = (TableColumn<S, ?>) focussedPos.getTableColumn();
TableCell cell = (TableCell) tableColumn.getCellFactory().call(tableColumn);
Node cellGraphic = cell.getGraphic();
System.out.println(cellGraphic);
//Output: ComboBox#44cf20e7[styleClass=combo-box-base combo-box]
//==> HOW DO I NOW FOCUS ON (OR SELECT?) THE GRAPHIC?
//I tried Platform.runLater() on the requestFocus but that didn't work either.
cellGraphic.requestFocus();
} else if ...
For completeness, here's the called endOfRowCheck method:
private void endOfRowCheck(TableView tv, KeyEvent event, TablePosition pos, TableColumn col, int maxCols) {
if ( pos.getColumn() == maxCols ) {
//We're at the end of a row so position to the start of the next row
tv.getSelectionModel().select(pos.getRow()+1, col);
event.consume();
}
}
I create combo box columns as follows.
In the FXML controller:
TableColumn<TestModel, DBComboChoice> colComboBoxField = DAOGenUtil.createComboBoxColumnTEST(colComboBoxField_HEADING, TestModel::comboBoxFieldProperty, arlMasterAssetClasses);
In the DAOGenUtil class:
public <S> TableColumn<S, DBComboChoice> createComboBoxColumnTEST(String title,
Function<S, StringProperty> methodGetComboFieldProperty,
ObservableList<DBComboChoice> comboData) {
TableColumn<S, DBComboChoice> col = new TableColumn<>(title);
col.setCellValueFactory(cellData -> {
String masterCode = methodGetComboFieldProperty.apply(cellData.getValue()).get();
DBComboChoice choice = DBComboChoice.getDescriptionByMasterCode(masterCode, comboData);
return new SimpleObjectProperty<>(choice);
});
col.setCellFactory(column -> ComboBoxCell.createComboBoxCell(comboData));
return col;
}
The ComboBoxCell class, which I use to render non-editable combos as combos and not as labels.
public class ComboBoxCell<S, T> extends TableCell<S, T> {
private final ComboBox<DBComboChoice> combo = new ComboBox<>();
public ComboBoxCell(ObservableList<DBComboChoice> comboData) {
combo.getItems().addAll(comboData);
combo.setEditable(false);
setGraphic(combo);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
combo.setOnAction((ActionEvent event) -> {
try {
String masterCode = combo.getSelectionModel().getSelectedItem().getMasterCode();
S datamodel = getTableView().getItems().get(getIndex());
try {
Method mSetComboBoxField = datamodel.getClass().getMethod("setComboBoxField", (Class) String.class);
mSetComboBoxField.invoke(datamodel, masterCode);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException ex) {
System.err.println(ex);
DAOGenUtil.logError(ex.getClass().toString(), ex.getMessage(), "Call to 'setComboBoxField' failed in ComboBoxCell.setOnAction for master code '" + masterCode + "'");
}
} catch (NullPointerException ex) {
//temporary workaround for bad test data
System.out.println("caught NPE in combo.setOnAction");
}
});
}
public static <S> ComboBoxCell<S, DBComboChoice> createComboBoxCell(ObservableList<DBComboChoice> comboData) {
return new ComboBoxCell<S, DBComboChoice>(comboData);
}
#Override
protected void updateItem(T comboChoice, boolean empty) {
super.updateItem(comboChoice, empty);
if (empty) {
setGraphic(null);
} else {
combo.setValue((DBComboChoice) comboChoice);
setGraphic(combo);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
}
}
I'm using JavaFX8, NetBeans 8.2 and Scene Builder 8.3.
UPDATED AGAIN:
Here is a full test case as requested, reproducible in NetBeans. My apologies if it's not in an expected format ... I'm still relatively new to Java and don't know how to turn it into something you can run standalone.
If you click in the text field column and then TAB to the combo box column, the cell that contains the combo box gets the focus, not the combo box itself.
For my app, the combo boxes need to be non-editable and always rendered as combos. When the user reaches the end of a table row and hits TAB (or RIGHT ARROW), the focus needs to move to the start of the next row.
Here is the test case code.
The app:
package test;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Test extends Application {
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
The FXML controller:
package test;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.beans.Observable;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
public class FXMLDocumentController implements Initializable {
private DAOGenUtil DAOGenUtil = new DAOGenUtil();
public ObservableList<TestModel> olTestModel = FXCollections.observableArrayList(testmodel ->
new Observable[] {
testmodel.textFieldProperty(),
testmodel.comboBoxFieldProperty()
});
ObservableList<DBComboChoice> comboChoices = FXCollections.observableArrayList();
TableColumn<TestModel, String> colTextField = new TableColumn("text col");
TableColumn<TestModel, DBComboChoice> colComboBoxField = DAOGenUtil.createComboBoxColumn("combo col", TestModel::comboBoxFieldProperty, comboChoices);
#FXML
private TableView<TestModel> tv;
#Override
public void initialize(URL url, ResourceBundle rb) {
comboChoices.add(new DBComboChoice("F", "Female"));
comboChoices.add(new DBComboChoice("M", "Male"));
olTestModel.add(new TestModel("test row 1", "M"));
olTestModel.add(new TestModel("test row 2", "F"));
olTestModel.add(new TestModel("test row 3", "F"));
olTestModel.add(new TestModel("test row 4", "M"));
olTestModel.add(new TestModel("test row 5", "F"));
colTextField.setCellValueFactory(new PropertyValueFactory<>("textField"));
tv.getSelectionModel().setCellSelectionEnabled(true);
tv.setEditable(true);
tv.getColumns().addAll(colTextField, colComboBoxField);
tv.setItems(olTestModel);
tv.setOnKeyPressed(event -> {
TableColumn firstCol = colTextField;
TableColumn lastCol = colComboBoxField;
int firstRow = 0;
int lastRow = tv.getItems().size()-1;
int maxCols = 1;
DAOGenUtil.handleTableViewSpecialKeys(tv, event, firstCol, lastCol, firstRow, lastRow, maxCols);
});
}
}
The ComboBoxCell class:
package test;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TableCell;
public class ComboBoxCell<S, T> extends TableCell<S, T> {
private final ComboBox<DBComboChoice> combo = new ComboBox<>();
private final DAOGenUtil DAOGenUtil;
public ComboBoxCell(ObservableList<DBComboChoice> comboData) {
this.DAOGenUtil = new DAOGenUtil();
combo.getItems().addAll(comboData);
combo.setEditable(false);
setGraphic(combo);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
combo.setOnAction((ActionEvent event) -> {
String masterCode = combo.getSelectionModel().getSelectedItem().getMasterCode();
S datamodel = getTableView().getItems().get(getIndex());
try {
Method mSetComboBoxField = datamodel.getClass().getMethod("setComboBoxField", (Class) String.class);
mSetComboBoxField.invoke(datamodel, masterCode);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException ex) {
System.err.println(ex);
}
});
}
#Override
protected void updateItem(T comboChoice, boolean empty) {
super.updateItem(comboChoice, empty);
if (empty) {
setGraphic(null);
} else {
combo.setValue((DBComboChoice) comboChoice);
setGraphic(combo);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
}
}
The TableView data model:
package test;
import javafx.beans.property.StringProperty;
import javafx.beans.property.SimpleStringProperty;
public class TestModel {
private StringProperty textField;
private StringProperty comboBoxField;
public TestModel() {
this(null, null);
}
public TestModel(
String textField,
String comboBoxField
) {
this.textField = new SimpleStringProperty(textField);
this.comboBoxField = new SimpleStringProperty(comboBoxField);
}
public String getTextField() {
return textField.get().trim();
}
public void setTextField(String textField) {
this.textField.set(textField);
}
public StringProperty textFieldProperty() {
return textField;
}
public String getComboBoxField() {
return comboBoxField.get().trim();
}
public void setComboBoxField(String comboBoxField) {
this.comboBoxField.set(comboBoxField);
}
public StringProperty comboBoxFieldProperty() {
return comboBoxField;
}
}
The DBComboChoice data model:
package test;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.ObservableList;
public class DBComboChoice {
private StringProperty masterCode;
private StringProperty masterDescription;
public DBComboChoice(
String masterCode,
String masterDescription
) {
this.masterCode = new SimpleStringProperty(masterCode);
this.masterDescription = new SimpleStringProperty(masterDescription);
}
public String getMasterCode() {
return masterCode.get();
}
public StringProperty masterCodeProperty() {
return masterCode;
}
public String getMasterDescription() {
return masterDescription.get();
}
public StringProperty masterDescriptionProperty() {
return masterDescription;
}
public static DBComboChoice getDescriptionByMasterCode(String inMasterCode, ObservableList<DBComboChoice> comboData) {
for ( int i=0; i<comboData.size(); i++ ) {
if ( comboData.get(i).getMasterCode().equals(inMasterCode) ) {
return comboData.get(i);
}
}
return null;
}
#Override
public String toString() {
return this.masterDescription.get();
}
}
The DAOGenUtil class:
package test;
import java.util.function.Function;
import javafx.application.Platform;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.ObservableList;
import javafx.scene.Node;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TablePosition;
import javafx.scene.control.TableView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
public class DAOGenUtil {
public <S> TableColumn<S, DBComboChoice> createComboBoxColumn(String title,
Function<S, StringProperty> methodGetComboFieldProperty,
ObservableList<DBComboChoice> comboData) {
TableColumn<S, DBComboChoice> col = new TableColumn<>(title);
col.setCellValueFactory(cellData -> {
String masterCode = methodGetComboFieldProperty.apply(cellData.getValue()).get();
DBComboChoice choice = DBComboChoice.getDescriptionByMasterCode(masterCode, comboData);
return new SimpleObjectProperty<>(choice);
});
col.setCellFactory((TableColumn<S, DBComboChoice> param) -> new ComboBoxCell<>(comboData));
return col;
}
public <S> void handleTableViewSpecialKeys(TableView tv, KeyEvent event,
TableColumn firstCol, TableColumn lastCol,
int firstRow, int lastRow,
int maxCols) {
//NB: pos, at this point, is the cell position that the cursor is about to leave
TablePosition<S, ?> pos = tv.getFocusModel().getFocusedCell();
if (pos != null ) {
if ( event.getCode() == KeyCode.TAB ) {
tv.getSelectionModel().selectRightCell();
endOfRowCheck(tv, event, pos, firstCol, maxCols);
event.consume();
TablePosition<S, ?> focussedPos = tv.getFocusModel().getFocusedCell();
TableColumn tableColumn = (TableColumn<S, ?>) focussedPos.getTableColumn();
TableCell cell = (TableCell) tableColumn.getCellFactory().call(tableColumn);
Node cellGraphic = cell.getGraphic();
System.out.println("node cellGraphic is " + cellGraphic);
if ( cellGraphic instanceof ComboBox<?> ) {
System.out.println("got a combo");
//nbg cellGraphic.requestFocus();
Platform.runLater(() -> {
((ComboBox<?>) cellGraphic).requestFocus();
});
}
} else if ( ! event.isShiftDown() && ! event.isControlDown() ){
//edit the cell
tv.edit(pos.getRow(), pos.getTableColumn());
}
}
}
private void endOfRowCheck(TableView tv, KeyEvent event, TablePosition pos, TableColumn col, int maxCols) {
if ( pos.getColumn() == maxCols ) {
//We're at the end of a row so position to the start of the next row
tv.getSelectionModel().select(pos.getRow()+1, col);
event.consume();
}
}
}
The FXML:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="test.FXMLDocumentController">
<center>
<TableView fx:id="tv" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER" />
</center>
</BorderPane>
Your question is too broad, you are trying to tackle too many problems at once, f.i.:
change navigation sequence, that is endOfRow handling
use tab for navigation
implement a custom cell
map visual appearence of a value to something with meaning for the user
start editing (aka: "focus") on reaching a cell
The most important (IMO) misconception in your code is the last bullet: you must not by-pass the editing mechanism when changing the underlying data. So change thinking "focus the graphic" to "start edit".
Below is a stand-alone example that demonstrates how to start with core support and modify it to get nearer to what's really needed. It
configures a core ComboBoxTableCell with a (crude ;) StringConverter to do the mapping of masterCode -> masterDescription
extends that core cell to request focus in startEdit
registers a listener on the table's (actually its focusModel's) focusedCell property that starts editing the new cell
Options to proceed from here:
to show the editable control always, look at the code of ComboBoxTableCell and modify to show the combo always
re-apply the tab handling (looks fine to me)
change navigation sequence as needed
The code:
public class TableCellFocusApp extends Application {
private Parent createContent() {
ObservableList<TestModel> olTestModel = FXCollections
.observableArrayList(testmodel -> new Observable[] {
testmodel.textFieldProperty(),
testmodel.comboBoxFieldProperty() });
TableView<TestModel> table = new TableView<>();
olTestModel.add(new TestModel("test row 1", "M"));
olTestModel.add(new TestModel("test row 2", "F"));
olTestModel.add(new TestModel("test row 3", "F"));
olTestModel.add(new TestModel("test row 4", "M"));
olTestModel.add(new TestModel("test row 5", "F"));
TableColumn<TestModel, String> colTextField = new TableColumn<>("text col");
colTextField
.setCellValueFactory(cb -> cb.getValue().textFieldProperty());
TableColumn<TestModel, String> gender= new TableColumn<>("Gender");
gender.setMinWidth(100);
gender.setCellValueFactory(cb -> cb.getValue().comboBoxFieldProperty());
StringConverter<String> converter = new StringConverter<>() {
#Override
public String toString(String object) {
return "F".equals(object) ? "Female" : "Male";
}
#Override
public String fromString(String string) {
return "Female".equals(string) ? "F" : "M";
}
};
gender.setCellFactory(cb -> new ComboBoxTableCell<>(converter, "F", "M") {
#Override
public void startEdit() {
super.startEdit();
if (getGraphic() != null) {
getGraphic().requestFocus();
}
}
});
// just to see that the data is updated correctly - add a readonly column
TableColumn<TestModel, String> plainGender = new TableColumn<>("readonly");
plainGender.setCellValueFactory(cb -> cb.getValue().comboBoxFieldProperty());
plainGender.setEditable(false);
table.getFocusModel().focusedCellProperty().addListener((src, ov, nv) -> {
if (nv != null && nv.getTableColumn() == gender) {
table.edit(nv.getRow(), gender);
}
});
table.getSelectionModel().setCellSelectionEnabled(true);
table.setEditable(true);
table.getColumns().addAll(colTextField,gender, plainGender ); //, colComboBoxField );
table.setItems(olTestModel);
BorderPane content = new BorderPane(table);
return content;
}
#Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent()));
stage.setTitle(FXUtils.version());
stage.show();
}
public static void main(String[] args) {
launch(args);
}
#SuppressWarnings("unused")
private static final Logger LOG = Logger
.getLogger(TableCellFocusApp.class.getName());
}

JavaFX: TableView Print Selected Row item

I currently have a tableview that displays a bunch of info on player stored on a database. What I'm trying to do, is simply print the first name of the name to console when its row is selected. Nothing is getting printed. I will post the entire code from table view to where I'm trying to print. I'm leaving out the function that loads players to the tableview as its unrelated
//Start Right Menu
TableView<TableDisplay> table = new TableView<>();
final ObservableList<TableDisplay> data =
FXCollections.observableArrayList();
TableColumn column1 = new TableColumn("Id");
column1.setMinWidth(100);
column1.setCellValueFactory(new PropertyValueFactory<>("id"));
TableColumn column2 = new TableColumn("First Name");
column2.setMinWidth(100);
column2.setCellValueFactory(new PropertyValueFactory<>("firstName"));
TableColumn column3 = new TableColumn("Last Name");
column3.setMinWidth(100);
column3.setCellValueFactory(new PropertyValueFactory<>("lastName"));
TableColumn column4 = new TableColumn("Birthdate");
column4.setMinWidth(100);
column4.setCellValueFactory(new PropertyValueFactory<>("birthdate"));
TableColumn column5 = new TableColumn("Nationality");
column5.setMinWidth(100);
column5.setCellValueFactory(new PropertyValueFactory<>("nationality"));
TableColumn column6 = new TableColumn("Height");
column6.setMinWidth(100);
column6.setCellValueFactory(new PropertyValueFactory<>("height"));
TableColumn column7 = new TableColumn("Position");
column7.setMinWidth(100);
column7.setCellValueFactory(new PropertyValueFactory<>("Position"));
TableColumn column8 = new TableColumn("Foot");
column8.setMinWidth(100);
column8.setCellValueFactory(new PropertyValueFactory<>("foot"));
TableColumn column9 = new TableColumn("Team Id");
column9.setMinWidth(100);
column9.setCellValueFactory(new PropertyValueFactory<>("teamId"));
table.getColumns().addAll(column1, column2, column3, column4, column5, column6, column7, column8, column9);
rightEditMenu.getChildren().addAll(table);
//End Right Menu
//Start Left Menu 2
This is where I'm trying to print but not working
TableDisplay person = table.getSelectionModel().getSelectedItem();
if(table.getSelectionModel().getSelectedItem() != null) {
System.out.println(person.getFirstName());
}
As I do not see a listener of any type in your code, I am assuming you do not have one.
It seems like you are trying to print the value of a selection before the Scene has even been loaded, which means no selection has been made by the user yet.
So add the following code when setting up your TableView:
// Add a listener to print the selected item to console when selected
table.getSelectionModel().selectedItemProperty().addListener((observableValue, oldValue, newValue) -> {
if (newValue != null) {
System.out.println("Selected Person: "
+ newValue.getId() + " | "
+ newValue.getFirstName() + " " + newValue.getLastName()
);
}
});
Now whenever a row is selected, this Listener is triggered and prints the values from newValue which represents the object stored in the selected row.
Since you did not provide an MCVE of your own, see the below example. You also do not declare what type of class your TableView and TableColumn objects are meant to display; this is a poor design and should be updated as in the below example.
import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
// Simple UI
VBox root = new VBox(10);
root.setAlignment(Pos.CENTER);
root.setPadding(new Insets(10));
// Setup the TableView and columns
TableView<Person> table = new TableView<>();
TableColumn<Person, Integer> colId = new TableColumn<>("ID");
colId.setMinWidth(100);
colId.setCellValueFactory(new PropertyValueFactory<>("id"));
TableColumn<Person, String> colFirstName = new TableColumn<>("First Name");
colFirstName.setMinWidth(100);
colFirstName.setCellValueFactory(new PropertyValueFactory<>("firstName"));
TableColumn<Person, String> colLastName = new TableColumn<>("Last Name");
colLastName.setMinWidth(100);
colLastName.setCellValueFactory(new PropertyValueFactory<>("lastName"));
// Add the columns to the TableView
table.getColumns().addAll(colId, colFirstName, colLastName);
// Add a listener to print the selected item to console when selected
table.getSelectionModel().selectedItemProperty().addListener((observableValue, oldValue, newValue) -> {
if (newValue != null) {
System.out.println("Selected Person: "
+ newValue.getId() + " | "
+ newValue.getFirstName() + " " + newValue.getLastName()
);
}
});
// Sample Data
ObservableList<Person> people = FXCollections.observableArrayList();
people.addAll(
new Person(1, "John", "Smith"),
new Person(2, "William", "Scott"),
new Person(4, "Susan", "Ryder")
);
table.setItems(people);
root.getChildren().add(table);
// Show the stage
primaryStage.setScene(new Scene(root));
primaryStage.setWidth(300);
primaryStage.setHeight(300);
primaryStage.show();
}
public static class Person {
private final IntegerProperty id = new SimpleIntegerProperty();
private final StringProperty firstName = new SimpleStringProperty();
private final StringProperty lastName = new SimpleStringProperty();
Person(int id, String firstName, String lastName) {
this.id.set(id);
this.firstName.set(firstName);
this.lastName.set(lastName);
}
public int getId() {
return id.get();
}
public IntegerProperty idProperty() {
return id;
}
public String getFirstName() {
return firstName.get();
}
public StringProperty firstNameProperty() {
return firstName;
}
public String getLastName() {
return lastName.get();
}
public StringProperty lastNameProperty() {
return lastName;
}
}
}

JavaFX: Populate a tableview using map

I'm starting to learn JavaFX and I want to populate my tableview with data from my database. I've learned that I could use map to build data but it didn't work. The tableview just shows the columns' name but no rows.
Here is my code:
Main.java
package application;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.fxml.FXMLLoader;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
AnchorPane root = (AnchorPane)FXMLLoader.load(getClass().getResource("MainWindow.fxml"));
Scene scene = new Scene(root);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
MainWindowControl.java
package application;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
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.MapValueFactory;
public class MainWindowController {
#FXML
private TableView<Map<Integer, String>> tableView = new TableView<>(generateDataInMap());
final static Integer first = 1;
public void openDatabase() throws SQLException {
Connection connection = DriverManager.getConnection("jdbc:sqlite:test.db");
Statement statement = connection.createStatement();
ResultSet rSet = statement.executeQuery("select * from myTable");
int col = rSet.getMetaData().getColumnCount();
for (int i = 1; i <= col; i++) {
rSet = statement.executeQuery("select * from myTable");
Integer key = 1;
String name = rSet.getMetaData().getColumnName(i);
TableColumn<Map<Integer, String>, String> tableColumn = new TableColumn<>(name);
tableColumn.setCellValueFactory(new MapValueFactory(key));
tableView.getColumns().add(tableColumn);
}
}
private ObservableList<Map<Integer, String>> generateDataInMap(){
Connection connection = null;
ObservableList<Map<Integer, String>> alldata = FXCollections.observableArrayList();
try {
connection = DriverManager.getConnection("jdbc:sqlite:test.db");
Statement statement = connection.createStatement();
ResultSet rSet = statement.executeQuery("select * from myTable");
int col = rSet.getMetaData().getColumnCount();
while(rSet.next()) {
Map<Integer, String> dataRow = new HashMap<>();
for (int i = 1; i <= col; i++) {
String value = rSet.getString(i);
dataRow.put(i, value);
}
alldata.add(dataRow);
}
connection.close();
return alldata;
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
}
MainWindow.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="255.0" prefWidth="427.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.MainWindowController">
<children>
<TableView fx:id="tableView" layoutX="34.0" layoutY="41.0" prefHeight="200.0" prefWidth="359.0" />
<Button layoutX="186.0" layoutY="14.0" mnemonicParsing="false" onAction="#openDatabase" text="Load Data" />
</children>
</AnchorPane>
Do you know where the bugs in my code are? I'm trying to simulate the function of SQLiteStudio that when I choose a database, the data will populate the tableview.
You're creating a TableView in the initializer of the controller class. This TableView is filled with data but the instance will never be displayed in a scene since FXMLLoader creates the one from the fxml.
Do initialisations like this in the initialize() method. This method is run by FXMLLoader after all objects have been injected making the tableView instance shown on screen accessible.
Additional notes:
You pass key which is always 1 to the value factory. Instead you should use i.
You requery the db for every column always fetching every single row in the table. This is very inefficient. Just execute the query a single time. Consider using the result for both initializing rows and columns.
Consider seperating data access and view. You could do this by passing data to the controller, see Passing Parameters JavaFX FXML
#FXML
private TableView<Map<Integer, String>> tableView;
#FXML
private void initialize() throws Exception {
try (Connection connection = DriverManager.getConnection("jdbc:sqlite:test.db");
Statement statement = connection.createStatement()) {
ResultSet rSet = statement.executeQuery("select * from myTable");
openDatabase(rSet);
tableView.setItems(generateDataInMap(rSet));
}
// TODO: Exception handling???
}
private void openDatabase(ResultSet rSet) throws SQLException {
final ResultSetMetaData metadata = rSet.getMetaData();
final int col = metadata.getColumnCount();
for (int i = 1; i <= col; i++) {
String name = metadata.getColumnName(i);
TableColumn<Map<Integer, String>, String> tableColumn = new TableColumn<>(name);
tableColumn.setCellValueFactory(new MapValueFactory(i));
tableView.getColumns().add(tableColumn);
}
}
private ObservableList<Map<Integer, String>> generateDataInMap(ResultSet rSet) {
ObservableList<Map<Integer, String>> alldata = FXCollections.observableArrayList();
final int col = rSet.getMetaData().getColumnCount();
while(rSet.next()) {
Map<Integer, String> dataRow = new HashMap<>();
for (int i = 1; i <= col; i++) {
String value = rSet.getString(i);
dataRow.put(i, value);
}
alldata.add(dataRow);
}
return alldata;
}
Note that the above modified code version requires you to remove the onAction event handler but since adding the rows but not initializing the columns makes little sense I moved the call to the initialize method and modified the signature in a way that does not allow you to use it as a EventHandler anymore.

ObservableList not showing in fxml defined tableview - losing will to live ;)

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>
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);}
}

JavaFX obtaining data from table

I have trouble obtaining data from table.
Get items doesn't work, and I'm stuck because there is lack of documentation. I get that Person is table model, but how can I use getFirstName from that maybe that is an answer. I have get but can not use that. Or should I stick to Swing for time being?
Here is a code:
package imenik;
import java.awt.Panel;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
/**
*
* #author Anak1n
*/
public class Imenik extends Application {
Label ime, prezime, brojTelefona, email, mobilni;
TextField imeTxt;
TextField prezimeTxt;
TextField brojTelTxt;
TextField mobilniTxt;
TextField emailTxt;
GridPane panelImenik;
Panel tabela;
Button potvrdi, otkazi, sacuvaj, otvori;
FileChooser fc = new FileChooser();
VBox vbox;
private final TableView<Person> table = new TableView<>();
#Override
public void start(final Stage primaryStage) {
ime = new Label("Ime: ");
prezime = new Label("Prezime: ");
brojTelefona = new Label("Fixni: ");
email = new Label("e-mail: ");
imeTxt = new TextField();
prezimeTxt = new TextField();
brojTelTxt = new TextField();
emailTxt = new TextField();
mobilni = new Label("Mobilni");
mobilniTxt = new TextField();
TableColumn imeT = new TableColumn("Ime");
imeT.setCellValueFactory(
new PropertyValueFactory<Person, String>("firstName")
);
imeT.prefWidthProperty().bind(table.widthProperty().divide(4));
TableColumn prezimeT = new TableColumn("Prezime");
prezimeT.setCellValueFactory(
new PropertyValueFactory<Person, String>("lastName")
);
prezimeT.prefWidthProperty().bind(table.widthProperty().divide(4));
TableColumn brojTelefonaFix = new TableColumn("Fixni");
brojTelefonaFix.setCellValueFactory(
new PropertyValueFactory<Person, String>("fixni")
);
brojTelefonaFix.prefWidthProperty().bind(table.widthProperty().divide(4));
TableColumn brojTelefonaMob = new TableColumn("Mobilni");
brojTelefonaMob.setCellValueFactory(
new PropertyValueFactory<Person, String>("mobilni")
);
brojTelefonaMob.prefWidthProperty().bind(table.widthProperty().divide(4));
TableColumn brTel = new TableColumn("Broj telefona");
brTel.getColumns().addAll(brojTelefonaFix, brojTelefonaMob);
brTel.prefWidthProperty().bind(table.widthProperty().divide(4));
TableColumn emailT = new TableColumn("E-mail");
emailT.setCellValueFactory(
new PropertyValueFactory<Person, String>("email")
);
emailT.prefWidthProperty().bind(table.widthProperty().divide(4));
sacuvaj = new Button("Sacuvaj");
sacuvaj.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
//Set extension filter
FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("CSV files (*.csv)", "*.csv");
fc.getExtensionFilters().add(extFilter);
//Show save file dialog
File file = fc.showSaveDialog(primaryStage);
if (file != null) {
SaveFile(table.getItems().toString(), file);
}
}
});
otvori = new Button("Otvori");
vbox = new VBox();
vbox.setSpacing(5);
vbox.setPadding(new Insets(10, 0, 0, 10));
tabela = new Panel();
panelImenik = new GridPane();
panelImenik.setAlignment(Pos.TOP_CENTER);
panelImenik.setHgap(10);
panelImenik.setVgap(10);
panelImenik.setPadding(new Insets(25, 25, 25, 25));
potvrdi = new Button("Potvrdi");
potvrdi.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
// ObservableList<Person> data = table.getItems();
table.getItems().add(new Person(
imeTxt.getText(),
prezimeTxt.getText(),
emailTxt.getText(),
brojTelTxt.getText(),
mobilniTxt.getText()
));
prezimeTxt.setText("");
imeTxt.setText("");
brojTelTxt.setText("");
emailTxt.setText("");
mobilniTxt.setText("");
}
});
table.getColumns().addAll(imeT, prezimeT, brTel, emailT);
otkazi = new Button("Ponisti");
otkazi.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
prezimeTxt.setText("");
imeTxt.setText("");
brojTelTxt.setText("");
emailTxt.setText("");
mobilniTxt.setText("");
System.out.print(table.getColumns().get(0));
}
});
vbox.getChildren().addAll(table, panelImenik);
dodaj();
Scene scene = new Scene(vbox, 411, 600);
//table.setItems(data);
primaryStage.setTitle("Imenik");
scene.getStylesheets().add(Imenik.class.getResource("pozadina.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* The main() method is ignored in correctly deployed JavaFX application.
* main() serves only as fallback in case the application can not be
* launched through deployment artifacts, e.g., in IDEs with limited FX
* support. NetBeans ignores main().
*
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
private void dodaj() {
panelImenik.add(ime, 0, 0);
panelImenik.add(imeTxt, 1, 0);
panelImenik.add(prezime, 0, 1);
panelImenik.add(prezimeTxt, 1, 1);
panelImenik.add(brojTelefona, 0, 2);
panelImenik.add(brojTelTxt, 1, 2);
panelImenik.add(mobilni, 0, 3);
panelImenik.add(mobilniTxt, 1, 3);
panelImenik.add(email, 0, 4);
panelImenik.add(emailTxt, 1, 4);
panelImenik.add(potvrdi, 1, 5);
panelImenik.add(otkazi, 0, 5);
panelImenik.add(sacuvaj, 2, 5);
panelImenik.add(otvori, 3, 5);
}
private void dodajUTabelu() {
}
public class Person {
private final SimpleStringProperty ime;
private final SimpleStringProperty prezime;
private final SimpleStringProperty email;
private final SimpleStringProperty fixni;
private final SimpleStringProperty mobilni;
private Person(String ime, String prezime, String email, String fixni, String mobilni) {
this.ime = new SimpleStringProperty(ime);
this.prezime = new SimpleStringProperty(prezime);
this.email = new SimpleStringProperty(email);
this.fixni = new SimpleStringProperty(fixni);
this.mobilni = new SimpleStringProperty(mobilni);
}
public String getFirstName() {
return ime.get();
}
public void setFirstName(String fName) {
ime.set(fName);
}
public String getLastName() {
return prezime.get();
}
public void setLastName(String fName) {
prezime.set(fName);
}
public String getEmail() {
return email.get();
}
public void setEmail(String fName) {
email.set(fName);
}
public String getFixni() {
return fixni.get();
}
public void setFixni(String fName) {
fixni.set(fName);
}
public String getMobilni() {
return mobilni.get();
}
public void setMobilni(String fName) {
mobilni.set(fName);
}
}
private void SaveFile(String content, File file) {
try {
FileWriter fileWriter = null;
fileWriter = new FileWriter(file);
fileWriter.write(content);
fileWriter.close();
} catch (IOException ex) {
System.out.print("Nije moguce");
}
}
}
You get items from the table by row, in this case that would be a person object. Then you use the get methods of the Person class to access fields. I'm guessing you want to use them in SaveFile(String, File) You should change it to something like saveFile(ObservableList<Person> persons, File file). Then you write the file something like
for (Person p : persons){
fileWriter.write(p.getFirstName()+","+
p.getLastName()/*etc..*/+"\n");
}
I did something like this. Got a hint on oracle forum :)
for (Person person : table.getItems()) {
String firstName = person.getFirstName();
String lastName = person.getLastName();
String email = person.getEmail();
String broj = person.getFixni();
String mob = person.getMobilni();
When i have them i will save them easily :)

Resources