Using a static nested class insted of toString - javafx

I have this task:
"We do not want to rely on us Currency their toString() for how a currency is displayed in list our. We will be able to set this up ourselves.
Create a static nested class called "Currency Cell" in ValutaOversikController as extender List Cell <Value>.
Override methods updateItem (Currency and Currency, boolean empty).
Set how a currency should be presented in the list e.g. "Country - Currency Code"
Then put CellFactory for our ListView, which returns an instance of the new Currency Cell class."
I started to make the last method in Controller, but don't know if this is correct. As of now this is what I have:
public class Controller {
#FXML
private ComboBox<Valuta> listeMedValutaerEn, listeMedValutaerTo;
#FXML
private ComboBox<Sorteringen> listeMedSortering;
#FXML
private TextField textFieldValutaerEn, textFieldValutaerTo;
#FXML
private ImageView imageViewValutaerEn, imageViewValutaerTo;
#FXML
public void initialize() {
listeMedValutaerEn.setItems(DataHandler.hentValutaData());
listeMedValutaerTo.setItems(DataHandler.hentValutaData());
listeMedSortering.setItems(DataHandler.hentSorteringsData());
listeMedValutaerEn.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Valuta>() {
#Override
public void changed(ObservableValue<? extends Valuta> observableValue, Valuta gammelValuta, Valuta nyValuta) {
fyllUtValutaEn(nyValuta);
}
});
listeMedValutaerTo.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Valuta>() {
#Override
public void changed(ObservableValue<? extends Valuta> observableValue, Valuta gammelValuta, Valuta nyValuta) {
fyllUtValutaTo(nyValuta);
}
});
listeMedSortering.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Sorteringen>() {
#Override
public void changed(ObservableValue<? extends Sorteringen> observableValue, Sorteringen gammelSortering, Sorteringen nySortering) {
sortere(nySortering);
}
});
}
private void sortere(Sorteringen nySortering) {
ObservableList<Valuta> valutaSomSkalSorteres = DataHandler.hentValutaData();
CompareToValuta sortere = new CompareToValuta(nySortering.getSorteringsKode());
Collections.sort(valutaSomSkalSorteres, sortere);
listeMedValutaerEn.setItems(valutaSomSkalSorteres);
listeMedValutaerTo.setItems(valutaSomSkalSorteres);
}
private void fyllUtValutaEn(Valuta enValuta) {
if (enValuta != null) {
Image flaggEn = new Image("https://www.countryflags.io/" + enValuta.getLandskode() + "/shiny/64.png");
imageViewValutaerEn.setImage(flaggEn);
}
}
private void fyllUtValutaTo(Valuta enValuta) {
if (enValuta != null) {
Image flaggTo = new Image("https://www.countryflags.io/" + enValuta.getLandskode() + "/shiny/64.png");
imageViewValutaerTo.setImage(flaggTo);
}
}
#FXML
private void buttonBeregn(ActionEvent event) {
Integer valutaAntall = Integer.valueOf(textFieldValutaerEn.getText());
double valutaNrEn = listeMedValutaerEn.getSelectionModel().getSelectedItem().getValutakurs();
double valutaNrTo = listeMedValutaerTo.getSelectionModel().getSelectedItem().getValutakurs();
double valutaResultat = valutaAntall * (valutaNrEn / valutaNrTo);
textFieldValutaerTo.setText(String.valueOf(valutaResultat));
}
private static ListCell<Valuta> ValutaCelle() {
ListCell<Valuta> tja = new ListCell<>();
return tja;
}
}
Class DataHandler:
public class DataHandler {
private final static ObservableList<Valuta> valutaListe = FXCollections.observableArrayList();
private final static ObservableList<Sorteringen> sorteringsListe = FXCollections.observableArrayList();
public static ObservableList<Sorteringen> hentSorteringsData() {
if (sorteringsListe.isEmpty()) {
sorteringsListe.add(new Sorteringen("Sortere alfabetisk på land synkende", 1));
sorteringsListe.add(new Sorteringen("Sortere alfabetisk på land stigende", 2));
sorteringsListe.add(new Sorteringen("Sortere på valutakode, stigende", 3));
sorteringsListe.add(new Sorteringen("Sortere på valutakode, synkende", 4));
}
return sorteringsListe;
}
public static ObservableList<Valuta> hentValutaData() {
if (valutaListe.isEmpty()) {
valutaListe.addAll(genererValutaData());
}
return valutaListe;
}
private static ArrayList<Valuta> genererValutaData() {
File kilden = new File("src/no/hiof/aleksar/oblig5/valutakurser.csv");
ArrayList<Valuta> valutaerFraFiler = lesFraCSVFil(kilden);
return valutaerFraFiler;
}
private static ArrayList<Valuta> lesFraCSVFil(File filSomLesesFra) {
ArrayList<Valuta> valutaerFraFil = new ArrayList<>();
try (BufferedReader bufretLeser = new BufferedReader(new FileReader(filSomLesesFra))) {
String linje;
while( (linje = bufretLeser.readLine()) != null ){
String[] deler = linje.split(";");
Valuta enValuta = new Valuta(deler[0], deler[1], deler[2], Double.parseDouble(deler[3]));
valutaerFraFil.add(enValuta);
}
} catch (IOException e) {
System.out.println(e);
}
return valutaerFraFil;
}
}

Related

Passing values between controllers by using the view object - JavaFX

When generating a multi view project with Gluon plugin for Ecplise, Netbeans or Intellij. It will be generating a view-class and a presenter-class. The view class looks like this for example:
public class ModelsView {
public View getView() {
try {
View view = FXMLLoader.load(ModelsView.class.getResource("models.fxml"));
return view;
} catch (IOException e) {
System.out.println("IOException: " + e);
return new View();
}
}
}
Is there some way I can access all the private fields in this controller models.fxml by just creating a code line like this:
View view = new ModelsView().getView(); // Here I am inside another controller
Can I access for example the getter method from the presenter-class by using the view object ? The view object is static as I can see it because there is no new before FXMLLoader.load(URL location)
public class ModelsPresenter {
#FXML
private View models;
#FXML
private #Getter TableView<String> tableView;
public void initialize() {
}
}
Heretic I am not using JavaFX from Gluon my configuration is jdk1.8.0_191 with derby in Netbeans 8.2 The code I am posting is my Model class PWData and the TableViewController just grabs the data from the derby DB The real important code is the initialize section of the TableViewController
public class PWData {
private final StringProperty ID;
private final StringProperty website;
private final StringProperty un;
private final StringProperty pw;
private final StringProperty sq;
private final StringProperty sans;
private final StringProperty notes;
public PWData(String ID,String website,String un,String pw,String sq,String sans,String notes) {
this.ID = new SimpleStringProperty(ID);
this.website = new SimpleStringProperty(website);
this.un = new SimpleStringProperty(un);
this.pw = new SimpleStringProperty(pw);
this.sq = new SimpleStringProperty(sq);
this.sans = new SimpleStringProperty(sans);
this.notes = new SimpleStringProperty(notes);
}
public String getID() {// 0
return ID.get();
}
public void setID(String ID){// 0
this.ID.set(ID);
}
public StringProperty IDProperty(){// 0
return ID;
}
public String getWebSite() {// 1
return website.get();
}
public void setwebsite(String website){// 1
this.website.set(website);
}
public StringProperty websiteProperty(){// 1
return website;
}
public String getUNName() {// 2
return un.get();
}
public void setun(String un){// 2
this.un.set(un);
}
public StringProperty unProperty(){// 2
return un;
}
public String getPW() {// 3
return pw.get();
}
public void setpw(String pw){// 3
this.pw.set(pw);
}
public StringProperty pwProperty(){// 3
return pw;
}
public String getSQName() {// 4
return sq.get();
}
public void setsq(String sq){// 4
this.sq.set(sq);
}
public StringProperty sqProperty(){// 4
return sq;
}
public String getSANS() {// 5
return sans.get();
}
public void setsans(String sans){// 5
this.sans.set(sans);
}
public StringProperty sansProperty(){// 5
return sans;
}
public String getNotes() {// 6
return notes.get();
}
public void setnotes(String notes){// 6
this.notes.set(notes);
}
public StringProperty notesProperty(){// 6
return notes;
}
public class TableViewController implements Initializable {
#FXML Pane tableviewPane,signinPane,detailviewPane;
#FXML private TableView<PWData> table;// NOTE CONSTRUCTION see Observable Value
#FXML private TableColumn<PWData,String> IDCol;
#FXML private TableColumn<PWData,String> websiteCol;
#FXML private TableColumn<PWData,String> unCol;
#FXML private TableColumn<PWData,String> pwCol;
String SQL_PWDataTable = "create table PWData ("
+ "ID int not null generated always as identity "
+ " (start with 100,increment by 1),"
+ "website varchar(50) not null, un varchar(40) not null, "
+ "pw varchar(40) not null, sq varchar(80) not null, "
+ "sans varchar(80) not null, notes varchar(260) not null,"
+ "primary key (ID) )";
String dbName="PWKeep";
public Stage stage;
String conURL = "jdbc:derby:C:/A_DerbyPWKeeper/DBName/" + dbName;
public static String strID;
KeyCode kc;
#FXML
private void onPress(KeyEvent ev) throws IOException{
kc = ev.getCode();
if(kc == KeyCode.ESCAPE){
onBack(null);
}
}
private void MakeTable() throws SQLException, IOException{
if (!tableExists( SignInController.con, "PWData")){
//System.out.println ("Creating table PWData");
SignInController.stmnt = SignInController.con.createStatement();
SignInController.stmnt.execute(SQL_PWDataTable );
SignInController.stmnt.close();
}else{
//System.out.println("PWData already created");
}
ReadFromDB();
}
// Does the table EXISTS
private static boolean tableExists ( Connection con, String table ) {
int numRows = 0;
try {
DatabaseMetaData dbmd = con.getMetaData();
// Note the args to getTables are case-sensitive!
ResultSet rs = dbmd.getTables( null, "APP", table.toUpperCase(), null);
while( rs.next()) ++numRows;
}catch(SQLException e){
String theError = e.getSQLState();
System.out.println("Can't query DB metadata: " + theError );
System.exit(1);
}
return numRows > 0;
}
private void ReadFromDB() throws SQLException{
SignInController.stmnt = SignInController.con.createStatement();
ObservableList<PWData> TableData = FXCollections.observableArrayList();
try (ResultSet rs = SignInController.stmnt.executeQuery("SELECT * FROM PWData") // Get all DB data
//int rowCount = 0;
) {
while (rs.next()){// Add data to observableArrayList TableData
//rowCount++;
TableData.add(new PWData(rs.getString("ID"),rs.getString("website")
,rs.getString("un"),rs.getString("pw"),rs.getString("sq"),rs.getString("sans"),rs.getString("notes")));
} //System.out.println("Row Count "+rowCount);// Useful for Printing for further development
PropertyValueFactory<PWData, String> IDCellValueFactory = new PropertyValueFactory<>("ID");
IDCol.setCellValueFactory(IDCellValueFactory);
PropertyValueFactory<PWData, String> WebSiteCellValueFactory = new PropertyValueFactory<>("website");
websiteCol.setCellValueFactory(WebSiteCellValueFactory);
PropertyValueFactory<PWData, String> UNCellValueFactory = new PropertyValueFactory<>("un");
unCol.setCellValueFactory(UNCellValueFactory);
PropertyValueFactory<PWData, String> PWCellValueFactory = new PropertyValueFactory<>("pw");
pwCol.setCellValueFactory(PWCellValueFactory);
Collections.sort(TableData, (p1, p2)-> p1.getWebSite().compareToIgnoreCase(p2.getWebSite()));
// Line of Code above Sorts websiteCol alpha
if(TableData.size() < 14) {// Format TableView to display Vertical ScrollBar
table.setPrefWidth(838);
}else {
table.setPrefWidth(855);
} table.setItems(TableData);
SignInController.stmnt.close();
}
}
#FXML
private void onBack(ActionEvent e) throws IOException{
stage = (Stage)tableviewPane.getScene().getWindow();
signinPane = FXMLLoader.load(getClass().getResource("signin.fxml"));
Scene scene = new Scene(signinPane);
scene.getStylesheets().add(getClass().getResource("pwkeeper.css").toExternalForm());
stage.setScene(scene);
stage.show();
stage.sizeToScene();
stage.centerOnScreen();
}
#FXML
private void onAdd(ActionEvent e) throws IOException{
stage = (Stage)tableviewPane.getScene().getWindow();
detailviewPane = FXMLLoader.load(getClass().getResource("detailview.fxml"));
Scene scene = new Scene(detailviewPane);
scene.getStylesheets().add(getClass().getResource("pwkeeper.css").toExternalForm());
stage.setScene(scene);
stage.show();
stage.sizeToScene();
stage.centerOnScreen();
}
private void MakeConn() throws SQLException, IOException{
SignInController.con = DriverManager.getConnection(conURL);
}
#FXML // This DROPS the MasterPW TABLE when the Reset Password is selected
private void onDrop(ActionEvent e) throws SQLException, IOException{
SignInController.stmnt = SignInController.con.createStatement();
SignInController.stmnt.executeUpdate("DROP TABLE MasterPW");
SignInController.stmnt.close();
onBack(null);
}
private void showTableDataDetails(PWData info) throws IOException{
if (info != null) {
info = (PWData) table.getSelectionModel().getSelectedItem();
strID = info.getID();
onAdd(null);
}
}
#Override
public void initialize(URL url, ResourceBundle rb) {
try {
MakeTable();
} catch (SQLException | IOException ex) {
Logger.getLogger(TableViewController.class.getName()).log(Level.SEVERE, null, ex);
}
table.getSelectionModel().selectedItemProperty().addListener((ObservableValue<? extends PWData>
observable,PWData oldValue, PWData newValue) -> {
try {
showTableDataDetails((PWData) newValue); // When a row of the table is Selected call
// Proper Construction // showTableDataDetails method
} catch (IOException ex) {
Logger.getLogger(TableViewController.class.getName()).log(Level.SEVERE, null, ex);
}
});
}
I am a little unsure of what you are trying to do but I would suggest you focus on the use of ObservableValue and Listeners You can download the entire code
At GitHub HERE

javafx: display hyperlink in table cell

I am new to JAVAFX and am trying to display the hyperlink in table cell. I could able to display as a hyperlink but not able to open the link.
Please find the logic for the same.
Main method goes here::
public class Main extends Application {
private BorderPane root;
private TableView<Item> table;
private Scene scene;
private TableColumn<Item, String> nameColumn;
private TableColumn<Item, Hyperlink> urlColumn;
private ObservableList<Item> websiteList;
#Override
public void start(Stage primaryStage) {
root = new BorderPane();
//scene = new Scene(root, 400, 400);
table = new TableView<Item>();
//root.setCenter(table);
nameColumn = new TableColumn<>("Name");
nameColumn.setCellValueFactory(new PropertyValueFactory<>("websiteName"));
urlColumn = new TableColumn<>("Address");
urlColumn.setCellValueFactory(new PropertyValueFactory<>("hyperlink"));
urlColumn.setCellFactory(new HyperlinkCell());
table.getColumns().add(nameColumn);
table.getColumns().add(urlColumn);
websiteList = FXCollections.observableArrayList();
websiteList.add(new Item("Google", "https://www.google.co.in/"));
websiteList.add(new Item("Facebook", "www.facebook.com"));
websiteList.add(new Item("Superglobals", "www.superglobals.net"));
Hyperlink hyperlink = new Hyperlink("Go to Eclipse home page");
hyperlink.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
getHostServices().showDocument("https://www.google.co.in/");
}
});
root.getChildren().addAll(hyperlink);
// root.setBottom(hyperlink);
table.setItems(websiteList);
root.setCenter(table);
scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Item.java::
public class Item {
private String websiteName;
private Hyperlink hyperlink;
public Item(String websiteName, String websiteUrl) {
this.websiteName = websiteName;
this.hyperlink = new Hyperlink(websiteUrl);
}
public String getWebsiteName() {
return websiteName;
}
public void setWebsiteName(String websiteName) {
this.websiteName = websiteName;
}
public Hyperlink getHyperlink() {
return hyperlink;
}
public void setHyperlink(String websiteUrl) {
this.hyperlink = new Hyperlink(websiteUrl);
}
}
HyperlinkCell.java::
public class HyperlinkCell implements Callback<TableColumn<Item, Hyperlink>, TableCell<Item, Hyperlink>> {
private static HostServices hostServices ;
public static HostServices getHostServices() {
return hostServices ;
}
#Override
public TableCell<Item, Hyperlink> call(TableColumn<Item, Hyperlink> arg) {
TableCell<Item, Hyperlink> cell = new TableCell<Item, Hyperlink>() {
#Override
protected void updateItem(Hyperlink item, boolean empty) {
super.updateItem(item, empty);
setGraphic(empty ? null : item);
}
};
return cell;
}
}
Output is displaying like this but am not able to open the hyperlink. Please help us on this.
Thanks.
Just update the onAction handler of the hyperlink in the updateItem() method:
TableCell<Item, Hyperlink> cell = new TableCell<Item, Hyperlink>() {
#Override
protected void updateItem(Hyperlink item, boolean empty) {
super.updateItem(item, empty);
setGraphic(empty ? null : item);
if (! empty) {
item.setOnAction(e -> {
// handle event here...
});
}
}
};
Note that it's really not a good idea to use UI elements (such as Hyperlink) in your data classes (such as Item). I recommend you refactor this so that Item only holds the data:
public class Item {
private String websiteName;
private String url;
public Item(String websiteName, String websiteUrl) {
this.websiteName = websiteName;
this.url = websiteUrl;
}
public String getWebsiteName() {
return websiteName;
}
public void setWebsiteName(String websiteName) {
this.websiteName = websiteName;
}
public String getUrl() {
return url;
}
public void setUrl(String websiteUrl) {
this.url = websiteUrl;
}
}
And then:
private TableColumn<Item, String> urlColumn;
// ...
urlColumn = new TableColumn<>("Address");
urlColumn.setCellValueFactory(new PropertyValueFactory<>("url"));
urlColumn.setCellFactory(new HyperlinkCell());
Somewhere in start() you need to do
HyperlinkCell.setHostServices(getHostServices());
and finally define the Hyperlink in the cell. That way there is only one Hyperlink instance per cell, instead of one for every item in the table.
public class HyperlinkCell implements Callback<TableColumn<Item, Hyperlink>, TableCell<Item, Hyperlink>> {
private static HostServices hostServices ;
public static HostServices getHostServices() {
return hostServices ;
}
public static void setHostServices(HostServices hostServices) {
HyperlinkCell.hostServices = hostServices ;
}
#Override
public TableCell<Item, String> call(TableColumn<Item, String> arg) {
TableCell<Item, Hyperlink> cell = new TableCell<Item, Hyperlink>() {
private final Hyperlink hyperlink = new Hyperlink();
{
hyperlink.setOnAction(event -> {
String url = getItem();
hostServices.showDocument(url);
});
}
#Override
protected void updateItem(String url, boolean empty) {
super.updateItem(url, empty);
if (empty) {
setGraphic(null);
} else {
hyperlink.setText(url);
setGraphic(hyperlink);
}
}
};
return cell;
}
}

Closing or hiding a stage with animation?

Ok, so I'm building this tiny JavaFX app and one of the things that have
bugged me was that while some of my stages would have that "enlarge-then-fade-out" animation on triggering close().
The close in particular is the last line of code in this code block:
#FXML
public void logout() throws SQLException {
Stage stage = ((Stage) logout_button.getScene().getWindow());
stage.close();
Main.loginStage.show();
}
Main.loginStage.close();
Here is that method's class
public class ListController {
#FXML private ImageView profImg;
#FXML private Button logout_button;
#FXML private TableView<Child> table;
#FXML private TableColumn col_name;
#FXML private TableColumn col_picture;
//TO BE MOVED TO EXTERNAL CLASS
private static Database db;
#FXML
public void initialize() {
db = new Database();
try {
initTable();
} catch (SQLException e){
System.out.println("loading failed");
}
initAvatar();
disableReorder();
}
private void initAvatar() {
profImg.setClip(ImageUtils.getAvatarCircle());
Image value = new Image("file:///" + GlobalInfo.getCurrProfImg().getAbsolutePath());
profImg.setImage(value);
}
public void initTable() throws SQLException {
db.init();
table.setRowFactory(new Callback<TableView<Child>, TableRow<Child>>() {
#Override
public TableRow<Child> call(TableView<Child> param) {
TableRow<Child> row = new TableRow<>();
row.setOnMouseClicked(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
System.out.println(row.getItem().getId());
}
});
return row;
}});
table.setItems(db.getChildren());
col_picture.setCellValueFactory(new PropertyValueFactory<Child, File>("image"));
col_picture.setCellFactory(new Callback<TableColumn<Child, File>, TableCell<Child, File>>() {
#Override
public TableCell call(TableColumn param) {
return new TableCell<Child, File>() {
ImageView imageView = new ImageView();
Image childImage;
#Override
protected void updateItem(File item, boolean empty) {
if (item != null) {
childImage = new Image("file:///" + item.getAbsolutePath());
imageView.setImage(childImage);
imageView.setClip(ImageUtils.getAvatarCircle());
imageView.setFitHeight(65);
imageView.setFitWidth(65);
HBox hBox = new HBox(imageView);
hBox.setAlignment(Pos.CENTER);
setGraphic(hBox);
}
}
};
}
});
col_name.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Child, String>, ObservableValue>() {
#Override
public ObservableValue call(TableColumn.CellDataFeatures<Child, String> param) {
Child child = param.getValue();
String firstName = child.getfName();
String lastName = child.getlName();
String nickname = child.getNickname();
String placeholder = "PLACEHOLDER"; //Place holder for adding nickname if exists
String complete = firstName + placeholder + lastName;
//place nickname between first and last name if exists
if (nickname.length() != 0){
String nicknameString = " \"" + nickname + "\" ";
complete = complete.replace(placeholder, nicknameString);
//if nickname does not exist
} else {
complete = complete.replace(placeholder, "");
}
return new SimpleStringProperty(complete);
}
});
col_name.setCellFactory(new Callback<TableColumn<Child, String>, TableCell<Child, String>>() {
#Override
public TableCell call(TableColumn<Child, String> param) {
return new TableCell<Child, String>() {
#Override
protected void updateItem(String item, boolean empty) {
setText(item);
setAlignment(Pos.CENTER);
}
};
}
});
}
private void disableReorder() {
table.widthProperty().addListener((observable, oldValue, newValue) -> {
TableHeaderRow row = ((TableHeaderRow) table.lookup("TableHeaderRow"));
row.reorderingProperty().addListener((observable1, oldValue1, newValue1) -> row.setReordering(false));
}); //Fuck you oracle
}
#FXML
public void logout() throws SQLException {
Stage stage = ((Stage) logout_button.getScene().getWindow());
stage.close();
Main.loginStage.show();
}
#FXML
public void showSettings() throws IOException {
Parent root = FXMLLoader.load(getClass().getResource("/fxml/settings.fxml"));
SettingsStage stage = new SettingsStage();
stage.setOnHidden((event) -> {
SettingsStage settingsStage = ((SettingsStage) event.getSource());
if (settingsStage.getChange()) {
initialize();
}
});
Scene scene = new Scene(root, 600, 400);
stage.setScene(scene);
stage.setTitle("Settings");
stage.initModality(Modality.APPLICATION_MODAL);
stage.showAndWait();
}
#FXML
public void showChildForm(ActionEvent actionEvent) throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/childForm.fxml"));
Parent root = loader.load();
ChildFormController controller = loader.getController();
controller.setListController(this);
Scene scene = new Scene(root, 575, 675);
scene.getStylesheets().add(getClass().getResource("/css/persistent-prompt.css").toExternalForm());
Stage stage = new Stage();
stage.setResizable(false);
stage.setScene(scene);
stage.setTitle("Add child");
stage.initModality(Modality.APPLICATION_MODAL);
stage.showAndWait();
}
}
However, I have some form stages which do not display this "animation" upon calling close() instead they simply disappear from the window, which I have found jarring.
Here is the code run to close one of these faulty stages, with its respective class further below:
#FXML
public void cancel(ActionEvent actionEvent) {
Stage stage = ((Stage) submitBtn.getScene().getWindow());
stage.close();
}
public class ChildFormController extends FormHelper {
#FXML
private ImageView childImage;
#FXML
private Label imageName;
#FXML
private PersistentPromptTextField firstNameInput;
#FXML
private PersistentPromptTextField lastNameInput;
#FXML
private PersistentPromptTextField nickNameInput;
#FXML
private PersistentPromptTextField birthPlaceInput;
#FXML
private PersistentPromptTextField referrerInput;
#FXML
private DatePicker birthDateInput;
#FXML
private DatePicker admissionDateInput;
#FXML
private Button submitBtn;
#FXML
private ComboBox childStatus;
//TWO SCOOPS TWO GENDERS TWO TERMS
#FXML
private ToggleGroup genderToggleGroup;
#FXML
private TextArea childDescInput;
#FXML
private Label warnEmptyLabel;
private FileInputStream slctdImgStrm;
private String pathRef;
private Parent nextParent;
private ChildParentsController childParentsController;
private ListController listController;
#FXML
public void initialize() throws FileNotFoundException {
//Init gender choice buttons and scene ref
//OMG MY PATRIARCHY
genderToggleGroup.getToggles().get(0).setSelected(true);
childStatus.getSelectionModel().selectFirst();
//Init default image for child
File defaultFile = new File("src\\main\\resources\\imgs\\default_avatar.png");
updateChosenImage(defaultFile);
//Init submit/next btn
initNextBtn();
childStatus.getSelectionModel().selectedIndexProperty().addListener((observable, oldValue, newValue) -> {
if (newValue.intValue() == 2) {
initSubmitBtn();
} else if (newValue.intValue() != 2 && oldValue.intValue() == 2) {
initNextBtn();
}
});
birthDateInput.valueProperty().addListener((observable, oldValue, newValue) -> {
if (admissionDateInput.getValue() != null) {
if (newValue.isAfter(admissionDateInput.getValue())) {
birthDateInput.setValue(admissionDateInput.getValue());
}
}
});
admissionDateInput.valueProperty().addListener(((observable, oldValue, newValue) -> {
if (birthDateInput.getValue() != null) {
if (admissionDateInput.getValue().isBefore(birthDateInput.getValue())) {
admissionDateInput.setValue(birthDateInput.getValue());
}
}
}));
}
private void initNextBtn() {
submitBtn.setText("Next");
submitBtn.getStyleClass().remove("submit");
submitBtn.getStyleClass().add("default");
submitBtn.setOnAction(event -> initParentForm());
}
private void initParentForm() {
if (formIsIncomplete())
return;
try {
if (nextParent == null) {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/childParentsForm.fxml"));
Parent root = loader.load();
childParentsController = loader.getController();
setNextParent(root);
}
submitBtn.getScene().setRoot(nextParent);
childParentsController.setPrevRoot(submitBtn.getParent());
childParentsController.setChildFormController(this);
} catch (IOException e) {
e.printStackTrace();
DialogUtils.displayExceptionError(e, "Severe error!");
}
}
private void initSubmitBtn() {
submitBtn.setText("Submit");
submitBtn.getStyleClass().remove("default");
submitBtn.getStyleClass().add("submit");
submitBtn.setOnAction(event -> submit(true));
}
#FXML
public void cancel(ActionEvent actionEvent) {
Stage stage = ((Stage) submitBtn.getScene().getWindow());
stage.close();
}
/**
* Submits the child with all of its respecitve information
* #param active if this controller's scene is active
* #return id of child submitted, negative number if submission has failed
*/
public int submit(boolean active) {
if (formIsIncomplete())
return -1;
//Fetch first part of user input
String firstName = firstNameInput.getText();
String lastName = lastNameInput.getText();
String nickName = nickNameInput.getText();
String place_of_birth = birthPlaceInput.getText();
String childDesc = childDescInput.getText();
String referrer = referrerInput.getText();
int gender = genderToggleGroup.getToggles().indexOf(genderToggleGroup.getSelectedToggle());
int status = childStatus.getSelectionModel().getSelectedIndex();
//Get child's birthdate and admission_date date
LocalDate birthDate = birthDateInput.getValue();
LocalDate admissionDate = admissionDateInput.getValue();
//Fire up db helper and insert new child record
Database db = new Database();
//Retrieve record's ID for later use
int id;
try {
//Add record for child and retrieve its id
db.init();
db.addNewChild(firstName, lastName, nickName, place_of_birth, birthDate, childDesc, gender, referrer, status, admissionDate);
//Retrieve id for use in storing img
id = db.getChildIDOf(firstName, lastName, nickName, place_of_birth, birthDate, childDesc, gender, referrer, status, admissionDate);
if (id == -89) throw new SQLException();
File strgReg = new File(pathRef.replace("id", String.valueOf(id)));
//Store img file for child avatar
if (!(strgReg.exists() && strgReg.isFile())) {
strgReg.getParentFile().mkdirs();
strgReg.createNewFile();
}
Files.copy(slctdImgStrm, Paths.get(strgReg.getPath()), StandardCopyOption.REPLACE_EXISTING);
db.updateImageOf(id, strgReg.getPath(), table_children.name);
} catch (SQLException e) {
e.printStackTrace();
DialogUtils.displayError("Error saving child data", "There was an error in saving all child data. Please try again!");
return -1;
} catch (IOException e) {
e.printStackTrace();
DialogUtils.displayError("Error saving image", "There was an error saving the image of the child. " +
"All other data besides the image has been saved. Please attempt to add the child image in its own page.");
return -1;
}
refreshList();
if (active) {
firstNameInput.getScene().getWindow().hide();
}
return id;
}
private boolean formIsIncomplete() {
//Clear warning labels
warnEmptyLabel.setStyle("-fx-text-fill: transparent");
//Indicates that form is incomplete
boolean incomplete = false;
//Fetches textfield nodes from root
try {
List<Node> textFields = NodeUtils.getAllNodesOf(childImage.getParent(), new ArrayList<>(),
"javafx.scene.control.TextInputControl");
//Go mark each incomplete form
for (Node n : textFields) {
TextInputControl text = ((TextInputControl) n);
String[] ids;
if (text.getId() == null) {
ids = new String[] {"birthDateWarning", "admissionDateWarning"};
} else {
ids = new String[] {text.getId().replace("Input", "Warning")};
}
//Manipulate warning label if current node is NOT nickname textfield
if (!ids[0].contains("nick")) {
for (int i = 0; i < ids.length; i++) {
Label warning = ((Label) childImage.getParent().lookup("#" + ids[i]));
if (text.getText().isEmpty()) {
warning.setStyle("-fx-text-fill: red");
incomplete = true;
} else {
warning.setStyle("-fx-text-fill: transparent ");
}
}
}
}
//Notify user that form is incomplete
if (incomplete) warnEmptyLabel.setStyle("-fx-text-fill: red");
} catch (ClassNotFoundException e) {
e.printStackTrace();
DialogUtils.displayExceptionError(e, "An error has occurred! Please contact the developer for assistance!");
}
return incomplete;
}
#FXML
public void changeChildImg(ActionEvent actionEvent) {
FileChooser chooser = new FileChooser();
File chosen = chooser.showOpenDialog(firstNameInput.getScene().getWindow());
if (chosen == null) return;
try {
updateChosenImage(chosen);
} catch (IOException e) {
DialogUtils.displayError("File error", "There was an error selecting your chosen file, please try again");
e.printStackTrace();
}
}
private void updateChosenImage(File chosen) throws FileNotFoundException {
slctdImgStrm = new FileInputStream(chosen);
childImage.setImage(new Image(slctdImgStrm));
imageName.setText(chosen.getName());
pathRef = GlobalInfo.getChildrenImgDir() + "\\"+ chosen.getName();
slctdImgStrm = new FileInputStream(chosen);
}
private void refreshList() {
try {
listController.initTable();
} catch (SQLException e) {
DialogUtils.displayError("Synchronization error!", "There was an error synchronizing the data of the new child!");
e.printStackTrace();
}
}
public void setNextParent(Parent nextParent) {
this.nextParent = nextParent;
}
public void setListController(ListController listController) {
this.listController = listController;
}
Does anybody have any idea on what's causing this problem? Any searches on SO yield questions about fading the stage in and out which is not what I want.

JavaFx Create Table Cell Accepts numbers only?

I have TableView with column inside it that must only accept numbers.
and I added onMouseClickListener to enter edit mode on the mouse click instead of double click on the cell
I want a way to not allowing the user to enter any character except numbers. My code is:
Callback<TableColumn<DailyDetails, String>, TableCell<DailyDetails, String>> defaultCellFactory
= TextFieldTableCell.<DailyDetails>forTableColumn();
dailyCredit.setCellFactory(column -> {
TableCell<DailyDetails, String> cell = defaultCellFactory.call(column);
cell.setOnMouseClicked(e -> {
if (!cell.isEditing() && !cell.isEmpty()) {
cell.getTableView().edit(cell.getIndex(), column);
}
});
return cell;
});
I implemented Table cell from the scratch:
class NumberCell extends TableCell<DailyDetails, String> {
private TextField textField;
public NumberCell() {
}
#Override
public void startEdit() {
super.startEdit();
if (textField == null) {
createTextField();
}
setGraphic(textField);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
textField.selectAll();
}
#Override
public void cancelEdit() {
super.cancelEdit();
setText(String.valueOf(getItem()));
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
if (isEditing()) {
if (textField != null) {
textField.setText(getString());
}
setGraphic(textField);
setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
} else {
setText(getString());
setContentDisplay(ContentDisplay.TEXT_ONLY);
}
}
}
private void createTextField() {
textField = new TextField(getString());
//textField.setMinWidth(this.getWidth() - this.getGraphicTextGap() * 2);
textField.lengthProperty().addListener(new ChangeListener<Number>(){
#Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
if (newValue.intValue() > oldValue.intValue()) {
char ch = textField.getText().charAt(oldValue.intValue());
// Check if the new character is the number or other's
if (!(ch >= '0' && ch <= '9' )) {
// if it's not number then just setText to previous one
textField.setText(textField.getText().substring(0,textField.getText().length()-1));
}
}
}
});
}
private String getString() {
return getItem() == null ? "" : getItem().toString();
}
}
Callback<TableColumn<DailyDetails, String>,
TableCell<DailyDetails, String>> cellFactory
= (TableColumn<DailyDetails, String> p) -> new NumberCell();
dailyDebit.setCellFactory(cellFactory);
the problem is i lost the on mouse listener cell.setOnMouseClicked!!!
how do i get the cell again to assign the listener ???
Just for driving the new api into everybody's brain: a full example with a slightly different TextFormatter (than in the other answer) that is Locale-aware and (dirtily!) hooked into core TextFieldTableCell, can be used in any custom editing TableCell as well:
/**
* Example of how-to use a TextFormatter in a editing TableCell.
*/
public class CellFormatting extends Application {
private Parent getContent() {
ObservableList<IntData> data = FXCollections.observableArrayList(
new IntData(1), new IntData(2), new IntData(3)
);
TableView<IntData> table = new TableView<>(data);
table.setEditable(true);
TableColumn<IntData, Integer> column = new TableColumn<>("Data");
column.setCellValueFactory(new PropertyValueFactory("data"));
// core default: will throw exception on illegal values
// column.setCellFactory(TextFieldTableCell.forTableColumn(new IntegerStringConverter()));
NumberFormat format = NumberFormat.getIntegerInstance();
UnaryOperator<TextFormatter.Change> filter = c -> {
if (c.isContentChange()) {
ParsePosition parsePosition = new ParsePosition(0);
// NumberFormat evaluates the beginning of the text
format.parse(c.getControlNewText(), parsePosition);
if (parsePosition.getIndex() == 0 ||
parsePosition.getIndex() < c.getControlNewText().length()) {
// reject parsing the complete text failed
return null;
}
}
return c;
};
column.setCellFactory(c -> new ValidatingTextFieldTableCell<>(
// note: each cell needs its own formatter
// see comment by #SurprisedCoconut
new TextFormatter<Integer>(
// note: should use local-aware converter instead of core!
new IntegerStringConverter(), 0,
filter)));
table.getColumns().add(column);
VBox box = new VBox(table);
return box;
}
/**
* TextFieldTableCell that validates input with a TextFormatter.
* <p>
* Extends TextFieldTableCell, accesses super's private field reflectively.
*
*/
public static class ValidatingTextFieldTableCell<S, T> extends TextFieldTableCell<S, T> {
private TextFormatter<T> formatter;
private TextField textAlias;
public ValidatingTextFieldTableCell() {
this((StringConverter<T>)null);
}
public ValidatingTextFieldTableCell(StringConverter<T> converter) {
super(converter);
}
public ValidatingTextFieldTableCell(TextFormatter<T> formatter) {
super(formatter.getValueConverter());
this.formatter = formatter;
}
/**
* Overridden to install the formatter. <p>
*
* Beware: implementation detail! super creates and configures
* the textField lazy on first access, so have to install after
* calling super.
*/
#Override
public void startEdit() {
super.startEdit();
installFormatter();
}
private void installFormatter() {
if (formatter != null && isEditing() && textAlias == null) {
textAlias = invokeTextField();
textAlias.setTextFormatter(formatter);
}
}
private TextField invokeTextField() {
Class<?> clazz = TextFieldTableCell.class;
try {
Field field = clazz.getDeclaredField("textField");
field.setAccessible(true);
return (TextField) field.get(this);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
}
public static class IntData {
IntegerProperty data = new SimpleIntegerProperty(this, "data");
public IntData(int value) {
setData(value);
}
public void setData(int value) {
data.set(value);
}
public int getData() {
return data.get();
}
public IntegerProperty dataProperty() {
return data;
}
}
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setScene(new Scene(getContent()));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
BTW, the formatter is re-used from another question where the task at hand was to restrict input into a Spinner.
Use a TextFormatter on the TextField like this:
TextFormatter<String> formatter = new TextFormatter<String>( change -> {
change.setText(change.getText().replaceAll("[^0-9.,]", ""));
return change;
});
textField.setTextFormatter(formatter);
Works with Java8u40 upwards. Use e. g. the TableView example from the Oracle site as base.

Javafx 8 Tableview selection with checkbox

I've set up a multiselection enabled tableview and am trying to attach a listener a checkbox inserted into a column to the selection model of the table.
checkBoxTableColumn.setCellValueFactory(
cellData -> {
CheckBox checkBox = new CheckBox();
ObjectProperty<CheckBox> sop = new SimpleObjectProperty<CheckBox>();
sop.setValue(checkBox);
sop.getValue().setText("");
sop.getValue().selectedProperty().addListener(
(obsv, oldv, newv) -> {
ArrayList<Job> tempSelectionArray = new ArrayList<>();
if(newv.booleanValue()){
tempSelectionArray.addAll(jobTableView.getSelectionModel().getSelectedItems().stream().collect(Collectors.toList()));
this.jobTableView.getSelectionModel().clearSelection();
for(Job job: tempSelectionArray){
jobTableView.getSelectionModel().select(job);
}
tempSelectionArray.clear();
}
else{
tempSelectionArray.addAll(this.jobTableView.getSelectionModel().getSelectedItems().stream().collect(Collectors.toList()));
this.jobTableView.getSelectionModel().clearSelection();
tempSelectionArray.remove(getJobTableView().getFocusModel().getFocusedItem());
for(Job job: tempSelectionArray){
this.jobTableView.getSelectionModel().select(job);
}
tempSelectionArray.clear();
}
}
);
ObservableValue<CheckBox> ov = sop;
return ov;
}
But that doesn't change the table selection.
Edited as jurge stated
checkBoxTableColumn.setCellFactory(new Callback<TableColumn<Job, Boolean>, TableCell<Job, Boolean>>() {
#Override
public TableCell<Job, Boolean> call(TableColumn<Job, Boolean> param) {
return new CheckBoxCell(jobTableView);
}
});
and checkbox cell is as
class CheckBoxCell extends TableCell<Job, Boolean>{
private CheckBox checkBox;
private TableView<Job> jobTableView;
public CheckBoxCell(TableView<Job> tableView){
this.jobTableView = tableView;
}
#Override
public void updateItem(Boolean item, boolean empty) {
super.updateItem(item, empty);
checkBox = new CheckBox();
setGraphic(checkBox);
checkBox.selectedProperty().addListener(
(obsv, oldv, newv) -> {
ArrayList<Job> tempSelectionArray = new ArrayList<>();
if(newv.booleanValue()){
tempSelectionArray.addAll(jobTableView.getSelectionModel().getSelectedItems().stream().collect(Collectors.toList()));
this.jobTableView.getSelectionModel().clearSelection();
for(Job job: tempSelectionArray){
jobTableView.getSelectionModel().select(job);
}
tempSelectionArray.clear();
}
else{
tempSelectionArray.addAll(this.jobTableView.getSelectionModel().getSelectedItems().stream().collect(Collectors.toList()));
this.jobTableView.getSelectionModel().clearSelection();
tempSelectionArray.remove(jobTableView.getFocusModel().getFocusedItem());
for(Job job: tempSelectionArray){
this.jobTableView.getSelectionModel().select(job);
}
tempSelectionArray.clear();
}
}
);
}
}
The listener wouldn't work this time.....
edit-#2
in initialize method of controller:
jobTableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
checkBoxTableColumn.setEditable(true);
checkBoxTableColumn.setCellValueFactory(
new PropertyValueFactory<Job, Boolean>("isContextSelected")
);
checkBoxTableColumn.setCellFactory(
new Callback<TableColumn<Job, Boolean>, TableCell<Job, Boolean>>() {
#Override
public TableCell<Job, Boolean> call(TableColumn<Job, Boolean> param) {
return new CheckBoxTableCell<Job, Boolean>(){
{
setAlignment(Pos.CENTER);
}
#Override
public void updateItem(Boolean item, boolean empty){
if(!empty){
TableRow row = getTableRow();
if(row != null){
Integer rowNumber = row.getIndex();
TableView.TableViewSelectionModel sm = getTableView().getSelectionModel();
if(item){
sm.select(rowNumber);
}
else{
sm.clearSelection(rowNumber);
}
}
}
super.updateItem(item, empty);
}
};
}
}
);
the job class:
private BooleanProperty isContextSelected;
public BooleanProperty isContextSelectedProperty() {
return isContextSelected;
}
edit--
Ignore the unnecessary parts. The whole code as requested.:
The controller:
package BillControl.view;
import BillControl.Controller.PopulateView;
import BillControl.Controller.Validator;
import BillControl.MainApp;
import BillControl.model.Article;
import BillControl.model.Job;
import javafx.beans.property.*;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.geometry.Pos;
import javafx.scene.control.*;
import javafx.scene.control.cell.CheckBoxTableCell;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;
import javafx.util.Callback;
import java.util.ArrayList;
import java.util.TreeSet;
public class ArticleJobAssignmentController {
private Article article;
private Stage jobAssignStage;
private boolean okClicked = false;
private MainApp mainApp;
ArrayList<Job> selectedJobList = new ArrayList<>();
private ObservableList<Job> masterJobList = FXCollections.observableArrayList();
private ObservableList<Job> currentJobList = FXCollections.observableArrayList();
private ObservableList<Job> articleEngagementList = FXCollections.observableArrayList();
private TreeSet rowIndices = new TreeSet();
#FXML
private Label articleNameLabel;
#FXML
private Label noOfJobsLabel;
#FXML
private Button okButton;
#FXML
private Button cancelButton;
#FXML
private Label errorLabel;
#FXML
private TableView<Job> jobTableView;
#FXML
private TableColumn<Job, Boolean> checkBoxTableColumn;
#FXML
private TableColumn<Job, String> jobNameColumn;
#FXML
private TableColumn<Job, String> clientNameColumn;
#FXML
private TableColumn<Job, Integer> noOfArticlesColumn;
#FXML
private TableColumn<Job, String> alreadyEngagedColumn;
public ArticleJobAssignmentController(){
}
public void initialize(){
errorLabel.setVisible(false);
jobTableView.setEditable(true);
jobTableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
checkBoxTableColumn.setEditable(true);
checkBoxTableColumn.setCellValueFactory(
new PropertyValueFactory<Job, Boolean>("isContextSelected")
);
checkBoxTableColumn.setCellFactory(
new Callback<TableColumn<Job, Boolean>, TableCell<Job, Boolean>>() {
#Override
public TableCell<Job, Boolean> call(TableColumn<Job, Boolean> param) {
return new CheckBoxTableCell<Job, Boolean>(){
{
setAlignment(Pos.CENTER);
}
#Override
public void updateItem(Boolean item, boolean empty){
if(!empty){
TableRow row = getTableRow();
if(row != null){
Integer rowNumber = row.getIndex();
TableView.TableViewSelectionModel sm = getTableView().getSelectionModel();
if(item){
sm.select(rowNumber);
}
else{
sm.clearSelection(rowNumber);
}
}
}
super.updateItem(item, empty);
}
};
}
}
);
jobNameColumn.setCellValueFactory(
cellData -> cellData.getValue().nameProperty()
);
noOfArticlesColumn.setCellValueFactory(
cellData -> {
SimpleIntegerProperty sip = new SimpleIntegerProperty(cellData.getValue().numberOfArticlesProperty().getValue());
ObservableValue<Integer> ov = sip.asObject();
return ov;
}
);
alreadyEngagedColumn.setCellValueFactory(
cellData -> {
Boolean engaged = false;
for(Job job: articleEngagementList){
if(job.getNumberID().equals(cellData.getValue().getNumberID())){
engaged = true;
}
}
if(engaged){
SimpleStringProperty sbp = new SimpleStringProperty("Yes");
ObservableValue<String> ov = sbp;
return ov;
}
else {
SimpleStringProperty sbp = new SimpleStringProperty("No");
ObservableValue<String> ov = sbp;
return ov;
}
}
);
jobTableView.getSelectionModel().getSelectedItems().addListener(
new ListChangeListener<Job>() {
#Override
public void onChanged(Change<? extends Job> c) {
noOfJobsLabel.setText(String.valueOf(c.getList().size()));
}
}
);
}
public void filterMasterList(){
for(Job job : masterJobList){
if(!job.getIsCompleted()){
currentJobList.add(job);
}
}
for(Job currentJob : currentJobList){
currentJob.setIsContextSelected(false);
}
}
#FXML
public void handleOkClicked(){
if(!Validator.articleJobAssignment(this)){
for(Job job : jobTableView.getSelectionModel().getSelectedItems()){
selectedJobList.add(job);
}
okClicked = true;
jobAssignStage.close();
}
else {
errorLabel.setText("Select at least one job");
errorLabel.setVisible(true);
}
}
#FXML
public void handleCancelClicked(){
jobAssignStage.close();
}
public void setArticle(Article article) {
this.article = article;
articleNameLabel.setText(article.getName());
}
public void setJobAssignStage(Stage jobAssignStage) {
this.jobAssignStage = jobAssignStage;
}
public void setOkClicked(boolean okClicked) {
this.okClicked = okClicked;
}
public void setMainApp(MainApp mainApp) {
this.mainApp = mainApp;
setMasterJobList(mainApp.getJobObservableList());
filterMasterList();
jobTableView.setItems(currentJobList);
if(article != null){
articleEngagementList = PopulateView.articleCurrentEngagementList(articleEngagementList, article.getId(), mainApp.getClientObservableList());
}
}
public Label getArticleNameLabel() {
return articleNameLabel;
}
public Label getNoOfJobsLabel() {
return noOfJobsLabel;
}
public Button getOkButton() {
return okButton;
}
public Button getCancelButton() {
return cancelButton;
}
public TableView<Job> getJobTableView() {
return jobTableView;
}
public TableColumn<Job, String> getJobNameColumn() {
return jobNameColumn;
}
public TableColumn<Job, String> getClientNameColumn() {
return clientNameColumn;
}
public TableColumn<Job, Integer> getNoOfArticlesColumn() {
return noOfArticlesColumn;
}
public ObservableList<Job> getMasterJobList() {
return masterJobList;
}
public void setMasterJobList(ObservableList<Job> masterJobList) {
this.masterJobList = masterJobList;
}
public boolean isOkClicked() {
return okClicked;
}
public ArrayList<Job> getSelectedJobList() {
return selectedJobList;
}
}
the job class(ignore the constructors):
package BillControl.model;
import BillControl.Controller.PopulateItems;
import BillControl.GeneralUtils.DateUtil;
import javafx.beans.property.*;
import javafx.collections.ObservableList;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class Job {
private String numberID;
private StringProperty name;
private ObjectProperty<Client> client;
private StringProperty clientName;
private ObjectProperty<Date> startPeriod;
private ObjectProperty<Date> endPeriod;
private ObjectProperty<Date> startDate;
private ObjectProperty<Date> targetDate;
private BooleanProperty isDelayed;
private LongProperty remainingDays;
private LongProperty delayedDays;
private BooleanProperty isCompleted;
private ObjectProperty<Date> completionDate;
private LongProperty daysToComplete;
private StringProperty partner;
private IntegerProperty numberOfArticles;
private BooleanProperty isContextSelected;
private String clientID;
public Job(Client client){
this.numberID = null;
this.client = new SimpleObjectProperty<Client>(client);
this.clientName = new SimpleStringProperty(client.getName());
this.name = new SimpleStringProperty("");
this.partner = new SimpleStringProperty("");
this.startDate = new SimpleObjectProperty<Date>();
this.targetDate = new SimpleObjectProperty<Date>();
this.completionDate = new SimpleObjectProperty<Date>();
this.isCompleted = new SimpleBooleanProperty(false);
this.startPeriod = new SimpleObjectProperty<Date>();
this.endPeriod = new SimpleObjectProperty<Date>();
this.fillOthers(false);
// todo check fill others logic
}
public Job(ObservableList clientList, String numberID){
this.numberID = numberID;
// this.numberID = null;
this.name = new SimpleStringProperty("");
this.partner = new SimpleStringProperty("");
this.startDate = new SimpleObjectProperty<Date>();
this.targetDate = new SimpleObjectProperty<Date>();
this.completionDate = new SimpleObjectProperty<Date>();
this.isCompleted = new SimpleBooleanProperty(false);
this.startPeriod = new SimpleObjectProperty<Date>();
this.endPeriod = new SimpleObjectProperty<Date>();
this.client = new SimpleObjectProperty<Client>();
this.clientName = new SimpleStringProperty();
this.numberOfArticles = new SimpleIntegerProperty();
this.isContextSelected = new SimpleBooleanProperty(false);
PopulateItems.populateJob(this);
Client selectedClient = null;
for(Object clientObject : clientList){
Client queriedClient = (Client) clientObject;
String name = queriedClient.getName();
String queriedName = PopulateItems.clientID2NameHelper(this.getClientID());
if(name.equals(queriedName)){
selectedClient = (Client) clientObject;
break;
}
}
this.setClient(selectedClient);
this.setClientName(this.getClient().getName());
this.fillOthers(true);
}
public Job(){
this.numberID = null;
this.client = new SimpleObjectProperty<Client>();
this.clientName = new SimpleStringProperty("");
this.name = new SimpleStringProperty("");
this.partner = new SimpleStringProperty("");
this.startDate = new SimpleObjectProperty<Date>();
this.targetDate = new SimpleObjectProperty<Date>();
this.completionDate = new SimpleObjectProperty<Date>();
this.isCompleted = new SimpleBooleanProperty(false);
this.startPeriod = new SimpleObjectProperty<Date>();
this.endPeriod = new SimpleObjectProperty<Date>();
this.fillOthers(false);
}
public void fillOthers(Boolean filledJob){
if(filledJob){
DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
try {
Date startDate = this.getStartDate();
Date completionDate = this.getCompletionDate();
Date currentDate = DateUtil.getCurrentDate();
Date targetDate = this.getTargetDate();
if (this.getIsCompleted()){
// completion days
this.daysToComplete = new SimpleLongProperty();
long duration = completionDate.getTime() - startDate.getTime();
long diffInDays = TimeUnit.MILLISECONDS.toDays(duration);
this.setDaysToComplete(diffInDays);
}
else{
this.remainingDays = new SimpleLongProperty();
this.isDelayed = new SimpleBooleanProperty();
if (targetDate.after(currentDate) && !this.getIsCompleted()){
// remaining days
long duration = targetDate.getTime() - currentDate.getTime();
long diffInDays = TimeUnit.MILLISECONDS.toDays(duration);
this.setRemainingDays(diffInDays);
this.setIsDelayed(false);
}
else if (targetDate.before(currentDate) && !this.getIsCompleted()) {
// delayed days
this.delayedDays = new SimpleLongProperty();
this.setIsDelayed(true);
long duration = currentDate.getTime() - targetDate.getTime();
long diffInDays = TimeUnit.MILLISECONDS.toDays(duration);
this.setRemainingDays(0);
this.setDelayedDays(diffInDays);
}
}
}
catch (Exception e){
e.printStackTrace();
}
}
else {
//TODO client creation form job
}
}
public String getName() {
return name.get();
}
public StringProperty nameProperty() {
return name;
}
public void setName(String name) {
this.name.set(name);
}
public Client getClient() {
return client.get();
}
public ObjectProperty<Client> clientProperty() {
return client;
}
public void setClient(Client client) {
this.client.set(client);
}
public Date getStartDate() {
return startDate.get();
}
public ObjectProperty<Date> startDateProperty() {
return startDate;
}
public void setStartDate(Date startDate) {
this.startDate.set(startDate);
}
public Date getTargetDate() {
return targetDate.get();
}
public ObjectProperty<Date> targetDateProperty() {
return targetDate;
}
public void setTargetDate(Date targetDate) {
this.targetDate.set(targetDate);
}
public boolean getIsDelayed() {
return isDelayed.get();
}
public BooleanProperty isDelayedProperty() {
return isDelayed;
}
public void setIsDelayed(boolean isDelayed) {
this.isDelayed.set(isDelayed);
}
public long getRemainingDays() {
return remainingDays.get();
}
public LongProperty remainingDaysProperty() {
return remainingDays;
}
public void setRemainingDays(long remainingDays) {
this.remainingDays.set(remainingDays);
}
public long getDelayedDays() {
return delayedDays.get();
}
public LongProperty delayedDaysProperty() {
return delayedDays;
}
public void setDelayedDays(long delayedDays) {
this.delayedDays.set(delayedDays);
}
public boolean getIsCompleted() {
return isCompleted.get();
}
public BooleanProperty isCompletedProperty() {
return isCompleted;
}
public void setIsCompleted(boolean isCompleted) {
this.isCompleted.set(isCompleted);
}
public Date getCompletionDate() {
return completionDate.get();
}
public ObjectProperty<Date> completionDateProperty() {
return completionDate;
}
public void setCompletionDate(Date completionDate) {
this.completionDate.set(completionDate);
}
public long getDaysToComplete() {
return daysToComplete.get();
}
public LongProperty daysToCompleteProperty() {
return daysToComplete;
}
public void setDaysToComplete(long daysToComplete) {
this.daysToComplete.set(daysToComplete);
}
public String getPartner() {
return partner.get();
}
public StringProperty partnerProperty() {
return partner;
}
public void setPartner(String partner) {
this.partner.set(partner);
}
public Integer getNumberOfArticles() {
return numberOfArticles.get();
}
public IntegerProperty numberOfArticlesProperty() {
return numberOfArticles;
}
public void setNumberOfArticles(int numberOfArticles) {
this.numberOfArticles.set(numberOfArticles);
}
public String getNumberID() {
return numberID;
}
public String getClientName() {
return clientName.get();
}
public StringProperty clientNameProperty() {
return clientName;
}
public void setClientName(String clientName) {
this.clientName.set(clientName);
}
public Date getStartPeriod() {
return startPeriod.get();
}
public ObjectProperty<Date> startPeriodProperty() {
return startPeriod;
}
public void setStartPeriod(Date startPeriod) {
this.startPeriod.set(startPeriod);
}
public Date getEndPeriod() {
return endPeriod.get();
}
public ObjectProperty<Date> endPeriodProperty() {
return endPeriod;
}
public void setEndPeriod(Date endPeriod) {
this.endPeriod.set(endPeriod);
}
public String getClientID() {
return clientID;
}
public void setClientID(String clientID) {
this.clientID = clientID;
}
public boolean getIsContextSelected() {
return isContextSelected.get();
}
public BooleanProperty isContextSelectedProperty() {
return isContextSelected;
}
public void setIsContextSelected(boolean isContextSelected) {
this.isContextSelected.set(isContextSelected);
}
}
Ok, so this one way to do it. You'll need a BooleanProperty in your backing model to hold the value of the check box so that the table will 'remember' if that rows check box should be selected or not if the row scrolls out of view and then back again.
TableColumn<Job,Boolean> checkCol = new TableColumn<>("Check");
checkCol.setCellValueFactory( new PropertyValueFactory<Job,Boolean>( "checkBoxValue" ) );
checkCol.setCellFactory( new Callback<TableColumn<Job,Boolean>, TableCell<Job,Boolean>>()
{
#Override
public TableCell<Job,Boolean> call( TableColumn<Job,Boolean> param )
{
return new CheckBoxTableCell<Job,Boolean>()
{
{
setAlignment( Pos.CENTER );
}
#Override
public void updateItem( Boolean item, boolean empty )
{
if ( ! empty )
{
TableRow row = getTableRow();
if ( row != null )
{
int rowNo = row.getIndex();
TableViewSelectionModel sm = getTableView().getSelectionModel();
if ( item ) sm.select( rowNo );
else sm.clearSelection( rowNo );
}
}
super.updateItem( item, empty );
}
};
}
} );
checkCol.setEditable( true );
checkCol.setMaxWidth( 50 );
checkCol.setMinWidth( 50 );
You are using checkBoxTableColumn.setCellValueFactory incorrectly.
Your TableView has data items of type T, and the setCellValueFactory method on a column is there to tell the column what value it must extract out of an object of type T to display.
You however are returning an observable value containing a GUI component (CheckBox), whereas you should be returning an observable Boolean value extracted from cellData.
See here for an Oracle tutorial on TableView: http://docs.oracle.com/javafx/2/ui_controls/table-view.htm#CJAGAAEE
Adding a checkbox column to a table where changes to the table checkbox are propogated back to the model object is quite simple:
TableColumn<Job,Boolean> checkCol = new TableColumn<>("Check");
checkCol.setCellValueFactory( new PropertyValueFactory<Job,Boolean>( "checkBoxValue" ) );
checkCol.setCellFactory( CheckBoxTableCell.forTableColumn( checkCol ) );
Note that "checkBoxValue" is the partial name of a property method in Job called checkBoxValueProperty() that returns a BooleanProperty. (It doesn't have to be called checkBoxValue, you can give it a different name, but it must end with Property.)

Resources