JavaFX: Strange case with DataView fill operation - javafx

I have a very strange problem with my test application. I need to fill the JavaFX TableView element with some data. Here is the code:
fxmldocumentController.java
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.TableView; //A
import javafx.scene.control.TableColumn; //B
import javafx.scene.control.cell.PropertyValueFactory; //C
public class fxmldocumentController implements Initializable
{
#FXML
private TableView<employees> mainTableView;
#FXML
private TableColumn<employees, Integer> age;
#FXML
private TableColumn<employees, String> userName, companyName;
#Override
public void initialize(URL url, ResourceBundle rb)
{
// TODO:
mainTableView.getItems().
add(new employees("Yuri P. Bodrov", "VMware", 35));
mainTableView.getItems().
add(new employees("Ivan Y. Bodrov", "VMware", 5));
mainTableView.getItems().
add(new employees("Peter Y. Bodrov", "VMware", 2));
// A problem starts here:
age.setCellValueFactory(new PropertyValueFactory<>("age"));
userName.setCellValueFactory(new PropertyValueFactory<>("userName"));
companyName.
setCellValueFactory(new PropertyValueFactory<>("companyName"));
}
}
fxmldocument.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="300.0" prefWidth="400.0" style="-fx-
background-color: white;"
xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="sampletableviewapp00.fxmldocumentController">
<children>
<Label fx:id="testLabel" layoutX="14.0" layoutY="14.0" style="-fx-
background-color: white;" text="Employees. TableView." textFill="#505050">
<font>
<Font size="14.0" />
</font>
</Label>
<TableView fx:id="mainTableView" layoutX="12.0" layoutY="50.0"
prefHeight="200.0" prefWidth="377.0">
<columns>
<TableColumn prefWidth="90.0" text="UserName" />
<TableColumn prefWidth="119.0" text="CompanyName" />
<TableColumn prefWidth="84.0" text="Age" />
</columns>
</TableView>
</children>
</AnchorPane>
Sampletableviewapp00.java
package sampletableviewapp00;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Sampletableviewapp00 extends Application
{
#Override
public void start(Stage stage) throws Exception
{
Parent root = FXMLLoader.load(getClass().
getClassLoader().getResource("fxmldocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args)
{
launch(args);
}
}
employees.java
package sampletableviewapp00;
public class employees
{
String userName, companyName;
int age;
// Generate Properties. Getters:
public int GetAge()
{
return age;
}
public String GetUserName()
{
return userName;
}
public String GetCompanyName()
{
return companyName;
}
// Generate Properties. Setters:
public void SetAge(int age)
{
this.age = age;
}
public void SetUserName(String userName)
{
this.userName = userName;
}
public void SetCompanyName(String companyName)
{
this.companyName = companyName;
}
// Generate Constructor of Employees class:
public employees(String userName, String companyName, int age)
{
this.userName = userName;
this.companyName = companyName;
this.age = age;
}
}
When I run this application the NetBeans IDE 8.2 returns this stack of exceptions/errors: see outputError.png as attachment
outputError.png
outputError02.PNG
Dear colleagues! Do you have any ideas to resolve this problem? Could you try to write this code by yourself and run? Thanks in advance! :-)

You have fxmldocument.xml but tried to load "fxmldocument.fxml".
Rename the file to have fxml extension.
Also make sure you put the fxml file under /resources/yourpackagepath/ folder and load as:
Sampletableviewapp00.class.getResource("fxmldocument.fxml")

This line is triggering the exception:
Parent root = FXMLLoader.load(getClass().
getClassLoader().getResource("fxmldocument.fxml"));
Your fxml document's extension is xml in your project and you are trying to load it as .fxml in the above line.
Rename fxmldocument.xml to fxmldocument.fxml.

Related

Share the same reusable FXML component in multiple views

I have a FXML view that contains a TabView with multiple tabs.
Every Tab has it's own FXML component + controller.
I would like all tabs to report progress via a component defined defined in the main view.
I know that I can inject child controllers into the main controller via FXML.
But to my current understanding, I need to access the parent controller inside my child controllers since the component is located in the main view.
I can also access the child controllers inside the initialize method of my main view. If I follow this path, I would need to modify the child controllers to set the shared component.
This is suboptimal, since the child components would be dependent on a main view that is performing those changes.
I created a MWE to illustrate the dilemma.
The question in short:
How can I report progress of Service1 and Service2 to the progressAndStatusGrid in the main view?
Callenge in short:
Make this application not throw a NPE and report progress to the progress component ;)
MWE:
Launcher:
package org.example;
public class Launcher {
public static void main(final String[] args) {
SimpleApplication.main(args);
}
}
Application:
package org.example;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class SimpleApplication extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/fxml/MainView.fxml"));
#SuppressWarnings("unused")
MainViewController controller = fxmlLoader.getController();
final Parent root = fxmlLoader.load();
final Scene scene = new Scene(root);
primaryStage.setTitle("Hello World");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
MainController:
package org.example;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.layout.GridPane;
import java.net.URL;
import java.util.ResourceBundle;
public class MainViewController implements Initializable {
#FXML
GridPane progressAndStatusGrid;
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
}
}
MainView:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane prefHeight="150.0" prefWidth="350.0" xmlns="http://javafx.com/javafx/17.0.2-ea"
xmlns:fx="http://javafx.com/fxml/1" fx:controller="org.example.MainViewController">
<padding>
<Insets top="4" right="4" bottom="4" left="4"/>
</padding>
<top>
</top>
<center>
<TabPane>
<Tab text="tab1" closable="false">
<fx:include fx:id="tab1" source="Tab1View.fxml"/>
</Tab>
<Tab text="tab2" closable="false">
<fx:include fx:id="tab2" source="Tab2View.fxml"/>
</Tab>
</TabPane>
</center>
<bottom>
<fx:include fx:id="progressAndStatusGrid"
source="ProgressAndStatusGridComponent.fxml"/>
</bottom>
</BorderPane>
"Shared" componentController:
package org.example;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.HBox;
import java.net.URL;
import java.util.ResourceBundle;
public class ProgressAndStatusGridComponentController implements Initializable {
#FXML
ProgressBar progressBar;
#FXML
HBox progressStatusBox;
#FXML
Label progressLabel;
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
}
}
"Shared" componentView:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ProgressBar?>
<?import javafx.scene.layout.*?>
<GridPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="org.example.ProgressAndStatusGridComponentController"
hgap="4" vgap="4">
<padding>
<Insets top="4" right="4" bottom="4" left="4"/>
</padding>
<fx:define>
<ColumnConstraints fx:id="colConstraints2" percentWidth="100"/>
</fx:define>
<columnConstraints>
<fx:reference source="colConstraints2"/>
<fx:reference source="colConstraints2"/>
</columnConstraints>
<ProgressBar fx:id="progressBar" GridPane.columnIndex="0" GridPane.rowIndex="0"/>
<HBox fx:id="progressStatusBox" alignment="CENTER" spacing="4" GridPane.columnIndex="1" GridPane.rowIndex="0">
<padding>
<Insets top="4" right="4" bottom="4" left="4"/>
</padding>
<Label fx:id="progressLabel"/>
</HBox>
</GridPane>
Tab1Controller:
package org.example;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import java.net.URL;
import java.util.ResourceBundle;
public class Tab1Controller implements Initializable {
#FXML
Button button1;
Service1 service1 = new Service1();
// How to get a reference, that is already initialized?
#FXML
ProgressAndStatusGridComponentController progressAndStatusGridComponentController;
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
button1.disableProperty().bind(service1.runningProperty());
}
public void handleButtonClick(ActionEvent actionEvent) {
service1.cancel();
service1.reset();
progressAndStatusGridComponentController.progressBar.progressProperty().bind(service1.progressProperty());
progressAndStatusGridComponentController.progressLabel.textProperty().bind(service1.messageProperty());
service1.start();
}
}
Tab1View:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="org.example.Tab1Controller">
<center>
<Button fx:id="button1" text="Start Background Progress #1" onAction="#handleButtonClick"/>
</center>
</BorderPane>
Tab2Controller:
package org.example;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import java.net.URL;
import java.util.ResourceBundle;
public class Tab2Controller implements Initializable {
#FXML
Button button2;
Service2 service2 = new Service2();
// How to get a reference, that is already initialized?
#FXML
ProgressAndStatusGridComponentController progressAndStatusGridComponentController;
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
button2.disableProperty().bind(service2.runningProperty());
}
public void handleButtonClick(ActionEvent actionEvent) {
service2.cancel();
service2.reset();
progressAndStatusGridComponentController.progressBar.progressProperty().bind(service2.progressProperty());
progressAndStatusGridComponentController.progressLabel.textProperty().bind(service2.messageProperty());
service2.start();
}
}
Tab2View:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.BorderPane?>
<BorderPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="org.example.Tab2Controller">
<center>
<Button fx:id="button2" text="Start Background Progress #2" onAction="#handleButtonClick"/>
</center>
</BorderPane>
Service1:
package org.example;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
public class Service1 extends Service<Void> {
static final int workLoad = 100;
#Override
protected Task<Void> createTask() {
return new Task<>() {
#Override
protected Void call() throws Exception {
updateMessage("Starting Task #1..");
for (int i = 0; i < workLoad; i++) {
Thread.sleep(200);
updateProgress(i, workLoad);
updateMessage(i + " elements done");
}
updateMessage("Task #1 done!");
return null;
}
};
}
}
Service2:
package org.example;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
public class Service2 extends Service<Void> {
static final int workLoad = 100;
#Override
protected Task<Void> createTask() {
return new Task<>() {
#Override
protected Void call() throws Exception {
updateMessage("Starting Task #2..");
for (int i = 0; i < workLoad; i++) {
Thread.sleep(200);
updateProgress(i, workLoad);
updateMessage(i + " elements done");
}
updateMessage("Task #2 done!");
return null;
}
};
}
}

How to add TableView footer in JavaFx TableView

I am stuck on how to add table footer or column footer in JavaFX TableView. I am looking to add a TableView which will show purchased items with quantities and sells price in columns and total items count and total sum at the TableView footer. I looked at various resources, but could not find footer property associated with TableView. Any idea how to do it?
Model Class
package javafxapplication8;
public class TestModel {
private String itemName = null;
private int pricePerUnit = 0;
private double quantity = 0.0;
private double amount = 0.0;
public TestModel() {
}
public TestModel(String argitemName, int argpricePerUnit, double argquantity, double argamount) {
itemName = argitemName;
pricePerUnit = argpricePerUnit;
quantity = argquantity;
amount = argamount;
}
public void setItemName(String argitemName) {
itemName = argitemName;
}
public void setPricePerUnit(int argpricePerUnit) {
pricePerUnit = argpricePerUnit;
}
public void setQuantity(double argquantity) {
quantity = argquantity;
}
public void setAmount(double argamount) {
amount = argamount;
}
public String getItemName() {
return itemName;
}
public int getPricePerUnit() {
return pricePerUnit;
}
public double getQuantity() {
return quantity;
}
public double getAmount() {
return amount;
}
#Override
public String toString() {
return this.itemName + "" + this.pricePerUnit + "" + this.quantity + "" + this.amount;
}
}
XML Code
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<AnchorPane id="AnchorPane" fx:id="anchor" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxapplication8.TVCTestModel">
<children>
<VBox prefHeight="564.0" prefWidth="857.0">
<children>
<HBox alignment="BOTTOM_LEFT" prefHeight="100.0" prefWidth="1613.0" spacing="20.0" />
<BorderPane prefHeight="695.0" prefWidth="1618.0">
<center>
<VBox prefHeight="544.0" prefWidth="772.0">
<children>
<HBox prefHeight="65.0" prefWidth="1618.0" />
<HBox prefHeight="426.0" prefWidth="857.0">
<children>
<HBox alignment="CENTER" prefHeight="225.0" prefWidth="857.0">
<children>
<TableView fx:id="myTableView" prefHeight="419.0" prefWidth="816.0">
<columns>
<TableColumn fx:id="itemName" prefWidth="200.0" text="Item Name" />
<TableColumn fx:id="pricePerUnit" prefWidth="200.0" text="Price Per Unit" />
<TableColumn fx:id="quantity" prefWidth="200.0" text="Quantity" />
<TableColumn fx:id="amount" prefWidth="200.0" text="Amount" />
</columns>
</TableView>
</children>
</HBox>
</children>
</HBox>
</children>
</VBox>
</center>
<bottom>
</bottom>
</BorderPane>
</children>
</VBox>
</children>
</AnchorPane>
Controller Class
package javafxapplication8;
import java.net.URL;
import java.util.ResourceBundle;
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;
import javafx.scene.layout.AnchorPane;
public class TVCTestModel implements Initializable {
#FXML
private TableColumn<TestModel, String> itemName;
#FXML
private TableColumn<TestModel, Integer> pricePerUnit;
#FXML
private TableColumn<TestModel, Double> quantity;
#FXML
private TableColumn<TestModel, Double> amount;
#FXML
private TableView<TestModel> myTableView;
public ObservableList<TestModel> objList = FXCollections.observableArrayList();
#FXML
private AnchorPane anchor;
private static TestModel curTestModel;
#Override
public void initialize(URL url, ResourceBundle rb) {
this.itemName.setCellValueFactory(new PropertyValueFactory<>("itemName"));
this.pricePerUnit.setCellValueFactory(new PropertyValueFactory<>("pricePerUnit"));
this.quantity.setCellValueFactory(new PropertyValueFactory<>("quantity"));
this.amount.setCellValueFactory(new PropertyValueFactory<>("amount"));
objList.add(new TestModel("Item 1", 10, 4, 400));
objList.add(new TestModel("Item 2", 20, 5, 1000));
objList.add(new TestModel("Item 3", 30, 6, 1800));
objList.add(new TestModel("Item 4", 400, 7, 2800));
System.out.println(objList.size());
myTableView.setItems(objList);
}
}
MainMethod Class
package javafxapplication8;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class JavaFXApplication8 extends Application {
#Override
public void start(Stage primaryStage) {
try {
Parent root = FXMLLoader.load(getClass().getResource("TVCTestModel.fxml"));
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
} catch (IOException ex) {
Logger.getLogger(JavaFXApplication8.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void main(String[] args) {
launch(args);
}
}
Your updated question was reopened, and the image provided suggests that, instead of a footer, you want two summary fields. As your table is not editable, a simple approximation is illustrated here—add two labels to the view, and iterate the table's model in the controller to establish the localized result:
TVCTestModel.fxml:
…
<bottom>
<HBox alignment="CENTER_RIGHT" style="-fx-spacing: 5px;">
<children>
<Label fx:id="labelQ"/>
<Label fx:id="labelA"/>
</children>
</HBox>
</bottom>
…
TVCTestModel.java
#FXML private Label labelQ;
#FXML private Label labelA;
#Override
public void initialize(URL url, ResourceBundle rb) {
…
double sumQuantity = 0;
double sumAmout = 0;
for (TestModel o : objList) {
sumQuantity += o.getQuantity();
sumAmout += o.getAmount();
}
labelQ.setText("Quantity: "
+ NumberFormat.getNumberInstance().format(sumQuantity));
labelA.setText("Amount: "
+ NumberFormat.getCurrencyInstance().format(sumAmout));
}
If you later decide to make your table editable, as shown here, you should consider these modifications:
Migrate to observable properties in your model class, as shown here.
Create your ObservableList model with an extractor, as shown here and here; your extractor would include properties for quantity and amount; your controller could then update the summary field in a ListChangeListener.

JavaFX Wrapping an editable TextFieldTableCell

I'm trying to get a TableView TextFieldTableCell to be both wrapping the text and adjusting the cell height and also be editable at the same time.
So i'm able to make it wrapped or editable, but not at the same time.
I have been following this Thread and trying about a 100 different permutations and possibilities. I'm sure it is possible, but i'm reaching full fustration quickly. So any help would be highly appreciated!
I'm using SceneBuilder and importing the handles. MainFX.fxml: -->
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.StackPane?>
<StackPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="wrappingEditableCellProject.Controller">
<children>
<AnchorPane prefHeight="200.0" prefWidth="200.0">
<children>
<TableView fx:id="tableView" prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<columns>
<TableColumn fx:id="id" prefWidth="75.0" text="id" />
<TableColumn fx:id="name" prefWidth="75.0" text="name" />
</columns>
</TableView>
</children>
</AnchorPane>
</children>
</StackPane>
My Main class:
package wrappingEditableCellProject;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
public static void main (String[] args) {
// TODO Auto-generated method stub
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("MainFX.fxml"));
primaryStage.setTitle("mainFx");
primaryStage.setScene(new Scene(root, 900, 600));
primaryStage.show();
}
}
My data entry class:
package wrappingEditableCellProject;
public class TableEntry {
private int id;
private String name;
public TableEntry (int id, String name){
this.id=id;
this.name=name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
My Controller class:
package wrappingEditableCellProject;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.collections.transformation.SortedList;
import javafx.fxml.FXML;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.util.converter.IntegerStringConverter;
public class Controller {
#FXML TableView<TableEntry> tableView;
#FXML TableColumn<TableEntry, Integer> id;
#FXML TableColumn<TableEntry, String> name;
private ObservableList<TableEntry> dataList = FXCollections.observableArrayList();
#SuppressWarnings({ "rawtypes", "unchecked" })
public void initialize(){
// Set editable
tableView.setEditable(true);
// Configure columns
id.setCellValueFactory(new PropertyValueFactory<>("id"));
id.setCellFactory(TextFieldTableCell.<TableEntry, Integer>forTableColumn(new IntegerStringConverter()));
id.setStyle("-fx-alignment: CENTER-LEFT;");
id.setEditable(false);
id.setSortable(false);
name.setCellValueFactory(new PropertyValueFactory<>("name"));
name.setCellFactory(WrappingTextFieldTableCell.<TableEntry>forTableColumn());
name.setStyle("-fx-alignment: CENTER-LEFT;");
name.setSortable(false);
name.setOnEditCommit(evt -> {
System.out.println("Edit comitted");
evt.getRowValue().setName(evt.getNewValue());
});
TableColumn[] tableColumns = {id,name};
tableView.getColumns().clear();
tableView.getColumns().addAll(tableColumns);
// add data to the table
dataList.clear();
dataList.add(new TableEntry(1, "Steve Upperton Stevenson"));
dataList.add(new TableEntry(2, "Peter May Parker"));
dataList.add(new TableEntry(3, "Tony Stark the machinist"));
dataList.add(new TableEntry(4, "Pepper Pots the CEO of Stark industies"));
FilteredList<TableEntry> dataFiltered = new FilteredList<>(dataList, b -> true);
SortedList<TableEntry> dataSorted = new SortedList<>(dataFiltered);
dataSorted.comparatorProperty().bind(tableView.comparatorProperty());
tableView.setItems(dataSorted);
}
}
Here is my custom cell class WrappingTextFieldTableCell:
package wrappingEditableCellProject;
import javafx.scene.control.Control;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.text.Text;
import javafx.util.converter.DefaultStringConverter;
public class WrappingTextFieldTableCell<S> extends TextFieldTableCell<S, String> {
private final Text cellText;
public WrappingTextFieldTableCell() {
super(new DefaultStringConverter());
setPrefHeight(Control.USE_COMPUTED_SIZE);
this.cellText = createText();
}
#Override
public void cancelEdit() {
super.cancelEdit();
setGraphic(cellText);
}
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (!isEmpty() && !isEditing()) {
setGraphic(cellText);
}
}
private Text createText() {
Text text = new Text();
text.wrappingWidthProperty().bind(widthProperty());
text.textProperty().bind(itemProperty());
return text;
}
}
This solution allows me to edit the cell(I know there are easier ways for this), but the wrapping is not taking.
As mentioned i have tried 100 different ways to approach this challenge, but i think this would be the easiest to relate to for any assistance.
Thanks for any support!

How to add data to tableView even if the textfield is empty?

I'm trying to make a program which gets data from textfield, adds it to tableview and then to DB. The problem is, that I also need a tableview to accept an empty textfield value.
This is how I add values to the tableview:
public void pievButtonClicked() {
int kods = Integer.parseInt(kodsT.getText());
String nosaukums = nosaukumsT.getText();
int inventars = Integer.parseInt(iegadesT.getText());
double uzskaite = Double.parseDouble(uzskaitesT.getText());
double iegade = Double.parseDouble(iegadesT.getText());
data.addAll(new Interjers(kods, nosaukums, inventars, uzskaite, iegade));
}
Maybe I need to change "Interijers" class or I need to change setCellValueFactory is some way. I really don't know.
I don't know what do want exactly ! but i made this example for you ,it seems explain your need
Model class:
package javafxapplication4;
public class Model {
String name;
String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public Model(String name, String age) {
this.name = name;
this.age = age;
}
public void setAge(String age) {
this.age = age;
}
}
Fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.net.URL?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" styleClass="mainFxmlClass" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.111" fx:controller="javafxapplication4.HomeController">
<stylesheets>
<URL value="#home.css" />
</stylesheets>
<children>
<TextField fx:id="nameField" layoutY="30.0" />
<TextField fx:id="ageField" layoutX="226.0" layoutY="30.0" />
<Button layoutX="451.0" layoutY="30.0" mnemonicParsing="false" onAction="#addLine" text="Button" />
<TableView fx:id="view" layoutX="52.0" layoutY="100.0" prefHeight="200.0" prefWidth="506.0">
<columns>
<TableColumn fx:id="nameCo" prefWidth="75.0" text="Name" />
<TableColumn fx:id="ageCo" prefWidth="75.0" text="Age" />
</columns>
</TableView>
</children>
</AnchorPane>
Controller class :
package javafxapplication4;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
/**
* FXML Controller class
*
* #author Ala_Eddine
*/
public class HomeController implements Initializable {
/**
* Initializes the controller class.
*/
#FXML
public TableView<Model> view;
#FXML
public TableColumn<Model, String> nameCo;
#FXML
public TableColumn<Model, String> ageCo;
#FXML
public TextField nameField;
#FXML
public TextField ageField;
#Override
public void initialize(URL url, ResourceBundle rb) {
nameCo.setCellValueFactory(new PropertyValueFactory<>("name"));
ageCo.setCellValueFactory(new PropertyValueFactory<>("age"));
}
#FXML
public void addLine() {
String name = nameField.getText();
String age = ageField.getText();
Model model = new Model(name, age);
view.getItems().add(model);
}
}
Main class:
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package javafxapplication4;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
/**
*
* #author Ala_Eddine
*/
public class JavaFXApplication4 extends Application {
#Override
public void start(Stage primaryStage) throws IOException {
Stage stage=new Stage();
Parent root = FXMLLoader.load(getClass().getResource("Home.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Result

Is it possible combine fx:include and afterburner

I currently using afterburner.fx to tailor together components of JavaFX based application.
Right now I trying move components in separate fxml files for more comfortable maintenance.
To load such components I using fx:include directive which allow load nested components automatically.
Problem is that with automatic load I loosing possibility get presenter from nested view.
Is there a way to combine automatic load and in same time, be able work with nested components from parent root?
These two seem to work fine together.
Afterburner works by setting a controller factory on the FXML loader, which takes care of instantiating the presenter class and injecting values into it.
The <fx:include> element will propagate the controller factory when loading the included FXML, so you can also inject values into the controller defined in the included FXML. Because afterburner effectively uses a singleton scope for injection, the same instance of injected fields will be used. This means you can readily share your data model between the different presenter classes.
If you want access to the presenter associated with the included FXML, just use the standard technique for "nested controllers".
So, for example:
main.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.cell.PropertyValueFactory?>
<?import javafx.geometry.Insets?>
<BorderPane xmlns:fx="http://javafx.com/fxml" fx:controller="application.MainPresenter">
<center>
<TableView fx:id="table">
<columns>
<TableColumn text="First Name" prefWidth="150">
<cellValueFactory>
<PropertyValueFactory property="firstName" />
</cellValueFactory>
</TableColumn>
<TableColumn text="Last Name" prefWidth="150">
<cellValueFactory>
<PropertyValueFactory property="lastName" />
</cellValueFactory>
</TableColumn>
<TableColumn text="Email" prefWidth="200">
<cellValueFactory>
<PropertyValueFactory property="email" />
</cellValueFactory>
</TableColumn>
</columns>
</TableView>
</center>
<bottom>
<fx:include source="Editor.fxml" fx:id="editor">
<padding>
<Insets top="5" bottom="5" left="5" right="5"/>
</padding>
</fx:include>
</bottom>
</BorderPane>
editor.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.control.Button?>
<GridPane xmlns:fx="http://javafx.com/fxml" hgap="5" vgap="10" fx:controller="application.EditorPresenter">
<Label GridPane.rowIndex="0" GridPane.columnIndex="0" text="First Name:"/>
<TextField fx:id="firstNameTextField" GridPane.rowIndex="0" GridPane.columnIndex="1"/>
<Label GridPane.rowIndex="1" GridPane.columnIndex="0" text="Last Name"/>
<TextField fx:id="lastNameTextField" GridPane.rowIndex="1" GridPane.columnIndex="1"/>
<Label GridPane.rowIndex="2" GridPane.columnIndex="0" text="Email"/>
<TextField fx:id="emailTextField" GridPane.rowIndex="2" GridPane.columnIndex="1"/>
<HBox GridPane.rowIndex="3" GridPane.columnIndex="0" GridPane.columnSpan="2">
<Button fx:id="addEditButton" onAction="#addEdit" />
</HBox>
</GridPane>
MainPresenter.java:
package application;
import javax.inject.Inject;
import javafx.fxml.FXML;
import javafx.scene.control.TableView;
public class MainPresenter {
#FXML
private TableView<Person> table ;
// This is the controller (presenter) for the included fxml
// It is injected by the FXMLLoader; the rule is that "Controller" needs to be
// appended to the fx:id attribute of the <fx:include> tag.
// This is not used in this example but is here to demonstrate how to access it
// if needed.
#FXML
private EditorPresenter editorController ;
#Inject
private DataModel dataModel ;
public void initialize() {
table.setItems(dataModel.getPeople());
table.getSelectionModel().selectedItemProperty().addListener(
(obs, oldPerson, newPerson) -> dataModel.setCurrentPerson(newPerson));
dataModel.currentPersonProperty().addListener((obs, oldPerson, newPerson) -> {
if (newPerson == null) {
table.getSelectionModel().clearSelection();
} else {
table.getSelectionModel().select(newPerson);
}
});
dataModel.getPeople().addAll(
new Person("Jacob", "Smith", "jacob.smith#example.com"),
new Person("Isabella", "Johnson", "isabella.johnson#example.com"),
new Person("Ethan", "Williams", "ethan.williams#example.com"),
new Person("Emma", "Jones", "emma.jones#example.com"),
new Person("Michael", "Brown", "michael.brown#example.com")
);
}
}
EditorPresenter.java:
package application;
import javafx.beans.binding.Bindings;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javax.inject.Inject;
public class EditorPresenter {
#FXML
private TextField firstNameTextField ;
#FXML
private TextField lastNameTextField ;
#FXML
private TextField emailTextField ;
#FXML
private Button addEditButton ;
#Inject
private DataModel dataModel ;
public void initialize() {
addEditButton.textProperty().bind(
Bindings.when(Bindings.isNull(dataModel.currentPersonProperty()))
.then("Add")
.otherwise("Update")
);
dataModel.currentPersonProperty().addListener((obs, oldPerson, newPerson) -> {
if (newPerson == null) {
firstNameTextField.setText("");
lastNameTextField.setText("");
emailTextField.setText("");
} else {
firstNameTextField.setText(newPerson.getFirstName());
lastNameTextField.setText(newPerson.getLastName());
emailTextField.setText(newPerson.getEmail());
}
});
}
#FXML
private void addEdit() {
Person person = dataModel.getCurrentPerson();
String firstName = firstNameTextField.getText();
String lastName = lastNameTextField.getText();
String email = emailTextField.getText();
if (person == null) {
dataModel.getPeople().add(new Person(firstName, lastName, email));
} else {
person.setFirstName(firstName);
person.setLastName(lastName);
person.setEmail(email);
}
}
}
MainView.java:
package application;
import com.airhacks.afterburner.views.FXMLView;
public class MainView extends FXMLView {
}
Main.java (application class):
package application;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
import com.airhacks.afterburner.injection.Injector;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
MainView mainView = new MainView();
Scene scene = new Scene(mainView.getView(), 600, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
#Override
public void stop() throws Exception {
Injector.forgetAll();
}
public static void main(String[] args) {
launch(args);
}
}
DataModel.java:
package application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public class DataModel {
private final ObservableList<Person> people = FXCollections.observableArrayList();
private final ObjectProperty<Person> currentPerson = new SimpleObjectProperty<>(this, "currentPerson");
public ObservableList<Person> getPeople() {
return people ;
}
public final Person getCurrentPerson() {
return currentPerson.get();
}
public final void setCurrentPerson(Person person) {
this.currentPerson.set(person);
}
public ObjectProperty<Person> currentPersonProperty() {
return currentPerson ;
}
}
And the usual Person.java example:
package application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class Person {
private final StringProperty firstName = new SimpleStringProperty(this, "firstName");
public final String getFirstName() {
return firstName.get();
}
public final void setFirstName(String firstName) {
this.firstName.set(firstName);
}
public StringProperty firstNameProperty() {
return firstName ;
}
private final StringProperty lastName = new SimpleStringProperty(this, "lastName");
public final String getLastName() {
return lastName.get();
}
public final void setLastName(String lastName) {
this.lastName.set(lastName);
}
public StringProperty lastNameProperty() {
return lastName ;
}
private final StringProperty email = new SimpleStringProperty(this, "email");
public final String getEmail() {
return email.get();
}
public final void setEmail(String email) {
this.email.set(email);
}
public StringProperty emailProperty() {
return email ;
}
public Person(String firstName, String lastName, String email) {
setFirstName(firstName);
setLastName(lastName);
setEmail(email);
}
}

Resources