I'm making a simple database application with JavaFX, but I can't figure out a way of making the Data class less verbose whilst still retaining the functionality of the Add Button.
Does anyone know a good way of streamlining the Data class, and keeping the Add Button, so that the user can input their own data?
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellEditEvent;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
public class DB extends Application {
private final TableView<Data> table = new TableView<>();
private final ObservableList<Data> data =
FXCollections.observableArrayList(
new Data("one", "one", "one", "one", "one", "one", "one", "one"));
private TableColumn<Data, String> [] tableCol;
private TextField [] textField;
private Button btn;
private HBox hbox;
private VBox vbox;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
Scene scene = new Scene(new Group());
stage.setTitle("Custom DB");
stage.setMaximized(true);
table.setEditable(true);
setTableCol();
setCellValue();
addToTable();
setTextField();
setBtn();
addToHBox();
addToVBox();
((Group) scene.getRoot()).getChildren().addAll(vbox);
stage.setScene(scene);
stage.show();
}
private void setTableCol()
{
tableCol = new TableColumn[8];
for(int i = 0; i<8; i++) {
tableCol[i] = new TableColumn();
tableCol[i].setMinWidth(100);
tableCol[i].setGraphic(new TextField("x"));
}
}
private void setCellValue()
{
tableCol[0].setCellValueFactory( new PropertyValueFactory<Data, String>("one"));
tableCol[1].setCellValueFactory( new PropertyValueFactory<Data, String>("two"));
tableCol[2].setCellValueFactory( new PropertyValueFactory<Data, String>("three"));
tableCol[3].setCellValueFactory( new PropertyValueFactory<Data, String>("four"));
tableCol[4].setCellValueFactory( new PropertyValueFactory<Data, String>("five"));
tableCol[5].setCellValueFactory( new PropertyValueFactory<Data, String>("six"));
tableCol[6].setCellValueFactory( new PropertyValueFactory<Data, String>("seven"));
tableCol[7].setCellValueFactory( new PropertyValueFactory<Data, String>("eight"));
}
private void addToTable()
{
table.setItems(data);
for(int i = 0; i<8; i++)
table.getColumns().addAll(tableCol[i]);
}
private void setTextField()
{
textField = new TextField[8];
for(int i = 0; i<8; i++) {
textField[i] = new TextField();
textField[i].setPromptText("Enter");
textField[i].setMaxWidth(tableCol[i].getPrefWidth());
}
}
private void setBtn()
{
btn = new Button("Add Data");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
data.add(new Data(
textField[0].getText(),
textField[1].getText(),
textField[2].getText(),
textField[3].getText(),
textField[4].getText(),
textField[5].getText(),
textField[6].getText(),
textField[7].getText()));
}
});
}
private void addToHBox()
{
hbox = new HBox();
hbox.setSpacing(20);
for(int i = 0; i<8; i++)
hbox.getChildren().addAll(textField[i]);
hbox.getChildren().addAll(btn);
}
private void addToVBox()
{
vbox = new VBox();
vbox.setSpacing(5);
vbox.setPadding(new Insets(10, 0, 0, 10));
vbox.getChildren().addAll(table, hbox);
}
public static class Data {
private final SimpleStringProperty one;
private final SimpleStringProperty two;
private final SimpleStringProperty three;
private final SimpleStringProperty four;
private final SimpleStringProperty five;
private final SimpleStringProperty six;
private final SimpleStringProperty seven;
private final SimpleStringProperty eight;
private Data(String a, String b, String c, String d, String e, String f, String g, String h)
{
this.one = new SimpleStringProperty(a);
this.two = new SimpleStringProperty(b);
this.three = new SimpleStringProperty(c);
this.four = new SimpleStringProperty(d);
this.five = new SimpleStringProperty(e);
this.six = new SimpleStringProperty(f);
this.seven = new SimpleStringProperty(g);
this.eight = new SimpleStringProperty(h);
}
public String getOne()
{
return one.get();
}
public void setOne(String fName)
{
one.set(fName);
}
public String getTwo()
{
return two.get();
}
public void setTwo(String fName) {
two.set(fName);
}
public String getThree()
{
return three.get();
}
public void setThree(String fName)
{
three.set(fName);
}
public String getFour()
{
return four.get();
}
public void setFour(String fName)
{
four.set(fName);
}
public String getFive()
{
return five.get();
}
public void setFive(String fName)
{
five.set(fName);
}
public String getSix()
{
return six.get();
}
public void setSix(String fName)
{
six.set(fName);
}
public String getSeven()
{
return seven.get();
}
public void setSeven(String fName)
{
seven.set(fName);
}
public String getEight()
{
return eight.get();
}
public void setEight(String fName)
{
eight.set(fName);
}
}
}
Related
I have written this little example application:
package application;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.CellEditEvent;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Main extends Application {
public class Person {
private StringProperty firstName = new SimpleStringProperty();
private StringProperty lastName = new SimpleStringProperty();
public Person(String firstName, String lastName) {
this.firstName.set(firstName);
this.lastName.set(lastName);
}
public String getFirstName() {
return firstName.get();
}
public String getLastName() {
return lastName.get();
}
public StringProperty firstNameProperty() {
return firstName;
}
public StringProperty lastNameProperty() {
return lastName;
}
}
#Override
public void start(Stage primaryStage) {
try {
StackPane root = new StackPane();
TableView<Person> tv = new TableView<>();
TableColumn<Person, String> col = new TableColumn<Person, String>("FirstName");
col.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName"));
tv.getColumns().add(col);
tv.setEditable(true);
col = new TableColumn<Person, String>("LastName");
col.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));
col.setCellFactory(TextFieldTableCell.forTableColumn());
col.setOnEditCommit(new EventHandler<TableColumn.CellEditEvent<Person, String>>() {
#Override
public void handle(CellEditEvent<Person, String> event) {
System.out.println(tv.getItems().get(1).getLastName());
}
});
tv.getColumns().add(col);
for (int i = 0; i < 30; i++) {
tv.getItems().add(new Person("Test" + i, "Test" + i));
}
root.getChildren().add(tv);
Scene scene = new Scene(root, 400, 200);
primaryStage.setScene(scene);
primaryStage.show();
tv.addEventFilter(MouseEvent.MOUSE_RELEASED, event -> {
// ...
});
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
I want to perform action when the ScrollBar has reached the bottom. Then I want to reload more datas from the database. But only then, when the user has seen all the already loaded datas (= scrollbar on the bottom). Do you have nice suggestions to solve this issue?
My first idea was to catch the MOUSE_RELEASED event (when the users drags the bar) of the TableView and then to check the position of the ScrollBar:
- getValue() gets the position of the bar
- getMax() the maximum value (=bottom).
But I can't find a way (without using the css-selector via this method) to get the ScrollBar from a given TableView. So I can't check the position of it in a certain TableView.
Do you have any ideas??
I am excited. Thanks for your help.
The only way to get the scroll bar is via a lookup, which is a bit of a hack, but it will work as long as you do it after the table has been rendered on the scene. You need
ScrollBar verticalBar = (ScrollBar) table.lookup(".scroll-bar:vertical");
Note that there's no need to mess with user events: you can just observe the scroll bar's value property directly:
verticalBar.valueProperty().addListener((obs, oldValue, newValue) -> {
if (newValue.doubleValue() >= verticalBar.getMax()) {
// add more data...
}
});
SSCCE:
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.ScrollBar;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class AddMoreTableDataOnScrollToBottom extends Application {
#Override
public void start(Stage primaryStage) {
TableView<Item> table = new TableView<>();
table.getColumns().add(column("Item", Item::nameProperty));
table.getColumns().add(column("Value", Item::valueProperty));
addMoreData(table, 20);
Scene scene = new Scene(new BorderPane(table), 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
ScrollBar verticalBar = (ScrollBar) table.lookup(".scroll-bar:vertical");
verticalBar.valueProperty().addListener((obs, oldValue, newValue) -> {
if (newValue.doubleValue() >= verticalBar.getMax()) {
addMoreData(table, 20);
}
});
}
private void addMoreData(TableView<Item> table, int numItems) {
Task<List<Item>> dataRetrieveTask = new Task<List<Item>>() {
#Override
public List<Item> call() throws Exception {
// mimic connect to db:
Thread.sleep(500);
List<Item> items = new ArrayList<>();
int nextItem = table.getItems().size() + 1 ;
for (int i = nextItem; i < nextItem + numItems; i++ ){
items.add(new Item("Item "+i, i));
}
return items ;
}
};
dataRetrieveTask.setOnSucceeded(e -> table.getItems().addAll(dataRetrieveTask.getValue()));
new Thread(dataRetrieveTask).start();
}
private <S,T> TableColumn<S,T> column(String title, Function<S, ObservableValue<T>> prop) {
TableColumn<S,T> col = new TableColumn<>(title);
col.setCellValueFactory(cellData -> prop.apply(cellData.getValue()));
return col ;
}
public static class Item {
private final StringProperty name = new SimpleStringProperty();
private final IntegerProperty value = new SimpleIntegerProperty();
public Item(String name, int value) {
setName(name);
setValue(value);
}
public final StringProperty nameProperty() {
return this.name;
}
public final String getName() {
return this.nameProperty().get();
}
public final void setName(final String name) {
this.nameProperty().set(name);
}
public final IntegerProperty valueProperty() {
return this.value;
}
public final int getValue() {
return this.valueProperty().get();
}
public final void setValue(final int value) {
this.valueProperty().set(value);
}
}
public static void main(String[] args) {
launch(args);
}
}
I created a program with a column that calculate the seconds (seconden). Now i want to convert the type into a double instead of integer, because it gets me the wrong answer (for example (25-2000/160)*60 should give me 750 instead of 780 seconds in my countdown timer. How can i convert it ?
Class RuniteOre:
import java.util.regex.Pattern;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.beans.property.IntegerProperty;
import javafx.collections.ListChangeListener.Change;
import javafx.animation.Timeline;
import javafx.animation.KeyFrame;
import javafx.util.Duration;
public class RuniteOre extends Application {
Stage window;
TableView<Product> table;
TextField rockInput, worldInput, aantalSpelers;
int seconden;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
table = new TableView<>();
window = primaryStage;
window.setTitle("Runite Ore - Calculator");
//Rock column
TableColumn<Product, String> rockColumn = new TableColumn<>("Rock");
rockColumn.setMinWidth(100);
rockColumn.setCellValueFactory(new PropertyValueFactory<>("rock"));
//World column
TableColumn<Product, Integer> worldColumn = new TableColumn<>("World");
worldColumn.setMinWidth(100);
worldColumn.setCellValueFactory(new PropertyValueFactory<>("world"));
//Aantal spelers column
TableColumn<Product, Integer> aantalSpelersColumn = new TableColumn<>("Aantal Spelers");
aantalSpelersColumn.setMinWidth(100);
aantalSpelersColumn.setCellValueFactory(new PropertyValueFactory<>("aantalSpelers"));
TableColumn<Product, Integer> secondenColumn = new TableColumn<>("Seconden");
secondenColumn.setCellValueFactory(cellData -> cellData.getValue().secondsProperty().asObject());
table.getItems().addListener((Change<? extends Product> c) -> {
while (c.next()) {
if (c.wasAdded()) {
for (Product item : c.getAddedSubList()) {
int startValue = item.getSeconden() ;
Timeline countdown = new Timeline(new KeyFrame(Duration.seconds(1), e ->
item.setSeconden(item.getSeconden() - 1)
));
countdown.setCycleCount(startValue);
countdown.play();
}
}
}
});
//Rock input
rockInput = new TextField();
rockInput.setPromptText("Rocks");
rockInput.setMinWidth(100);
//World input
worldInput= new TextField();
worldInput.setPromptText("World");
//Aantal spelers input
aantalSpelers = new TextField();
aantalSpelers.setPromptText("Aantal Spelers");
//Button
Button addButton = new Button("Add");
addButton.setOnAction(e -> addButtonClicked());
Button deleteButton = new Button("Delete");
deleteButton.setOnAction(e -> deleteButtonClicked());
HBox hBox = new HBox();
hBox.setPadding(new Insets(10,10,10,10));
hBox.setSpacing(10);
hBox.getChildren().addAll(rockInput, worldInput, aantalSpelers, addButton, deleteButton);
table.getColumns().addAll(rockColumn, worldColumn, aantalSpelersColumn,secondenColumn);
VBox vBox = new VBox();
vBox.getChildren().addAll(table, hBox);
Scene scene = new Scene(vBox);
window.setScene(scene);
window.show();
}
//Add button clicked
public void addButtonClicked(){
Product product = new Product();
product.setRock(rockInput.getText());
product.setWorld(Integer.parseInt(worldInput.getText()));
product.setAantalSpelers(Integer.parseInt(aantalSpelers.getText()));
seconden=(25-((Integer.parseInt(aantalSpelers.getText()))/160))*60;
//seconden=(Integer.parseInt(aantalSpelers.getText()));
product.setSeconden(seconden);
table.getItems().add(product);
rockInput.clear();
worldInput.clear();
aantalSpelers.clear();
}
//Delete button clicked
public void deleteButtonClicked(){
ObservableList<Product> productSelected, allProducts;
allProducts = table.getItems();
productSelected = table.getSelectionModel().getSelectedItems();
productSelected.forEach(allProducts::remove);
}
}
Class Product:
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
public class Product {
private String rock;
private int world;
private int aantalSpelers;
//private int seconden;
private int timer;
private final IntegerProperty seconden = new SimpleIntegerProperty() ;
public Product(){
this.rock = "";
this.world = 0;
this.aantalSpelers = 0;
}
public Product(String rock, int world, int aantalSpelers){
this.rock = rock;
this.world = world;
this.aantalSpelers = aantalSpelers;
}
public String getRock() {
return rock;
}
public void setRock(String rock) {
this.rock = rock;
}
public int getWorld() {
return world;
}
public void setWorld(int world) {
this.world = world;
}
public int getAantalSpelers() {
return aantalSpelers;
}
public void setAantalSpelers(int aantalSpelers) {
this.aantalSpelers = aantalSpelers;
}
public final int getSeconden() {
return secondsProperty().get();
}
public final void setSeconden(int seconden) {
secondsProperty().set(seconden);
}
// public int getTimer() {
// return timer;
//}
//public void setTimer(int timer) {
// this.timer = timer;
// }
public Product(int seconden) {
setSeconden(seconden);
}
public IntegerProperty secondsProperty() {
return seconden ;
}
}
I might be missing something. Why don't you just change the type to double?
double seconden=(25-((Double.parseDouble(aantalSpelers.getText()))/160))*60;
Update: If you don't want to change your seconden attribute to double, then you need to cast
int seconden= (int)((25-((Double.parseDouble(aantalSpelers.getText()))/160))*60);
The key here is that your keep your data to double during the division (aantalSpelers.getText()))/160) , otherwise it would truncate your result. Later you could safely cast back to integer
Try this
double seconden=(25-((Double.parseDouble(aantalSpelers.getText()))/160))*(double)60;
Also
Change the parameters of your setSeconden(int seconden){...} method in order to accept double data types setSeconden(double seconden){...}
,
`public final int getSeconden() {....}` to `public final double getSeconden() {...}`
And
public IntegerProperty secondsProperty(){.....} to public DoubleProperty secondsProperty(){...}
I am struggling to make a countdown timer in javaFX. I want the value of secondenColumn to be used as a timer. So for example when i add row with 'seconden'=200. The timer has to run for 200 seconds (until 0). I don't know how to begin with the code for the timer. This is what i have at the moment...
import java.util.regex.Pattern;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.beans.property.IntegerProperty;
import javafx.collections.ListChangeListener.Change;
import javafx.animation.Timeline;
import javafx.animation.KeyFrame;
import javafx.util.Duration;
public class RuniteOre extends Application {
Stage window;
TableView<Product> table;
TextField rockInput, worldInput, aantalSpelers;
int seconden;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
window = primaryStage;
window.setTitle("Runite Ore - Calculator");
//Rock column
TableColumn<Product, String> rockColumn = new TableColumn<>("Rock");
rockColumn.setMinWidth(200);
rockColumn.setCellValueFactory(new PropertyValueFactory<>("rock"));
//World column
TableColumn<Product, Integer> worldColumn = new TableColumn<>("World");
worldColumn.setMinWidth(100);
worldColumn.setCellValueFactory(new PropertyValueFactory<>("world"));
//Aantal spelers column
TableColumn<Product, Integer> aantalSpelersColumn = new TableColumn<>("Aantal Spelers");
aantalSpelersColumn.setMinWidth(100);
aantalSpelersColumn.setCellValueFactory(new PropertyValueFactory<>("aantalSpelers"));
//Seconden column
//TableColumn<Product, Integer> secondenColumn = new TableColumn<>("Seconden");
//secondenColumn.setMinWidth(200);
//secondenColumn.setCellValueFactory(new PropertyValueFactory<>("seconden"));
TableView<Product> table = new TableView<>();
TableColumn<Product, Integer> secondenColumn = new TableColumn<>("Seconden");
table.getColumns().add(secondenColumn);
secondenColumn.setCellValueFactory(cellData -> cellData.getValue().secondsProperty().asObject());
table.getItems().addListener((Change<? extends Product> c) -> {
while (c.next()) {
if (c.wasAdded()) {
for (Product item : c.getAddedSubList()) {
int startValue = item.getSeconden() ;
Timeline countdown = new Timeline(new KeyFrame(Duration.seconds(1), e ->
item.setSeconden(item.getSeconden() - 1)
));
countdown.setCycleCount(startValue);
countdown.play();
}
}
}
});
//Rock input
rockInput = new TextField();
rockInput.setPromptText("Rocks");
rockInput.setMinWidth(100);
//World input
worldInput= new TextField();
worldInput.setPromptText("World");
//Aantal spelers input
aantalSpelers = new TextField();
aantalSpelers.setPromptText("Aantal Spelers");
//Button
Button addButton = new Button("Add");
addButton.setOnAction(e -> addButtonClicked());
Button deleteButton = new Button("Delete");
deleteButton.setOnAction(e -> deleteButtonClicked());
HBox hBox = new HBox();
hBox.setPadding(new Insets(10,10,10,10));
hBox.setSpacing(10);
hBox.getChildren().addAll(rockInput, worldInput, aantalSpelers, addButton, deleteButton);
table = new TableView<>();
table.getColumns().addAll(rockColumn, worldColumn, aantalSpelersColumn,secondenColumn);
VBox vBox = new VBox();
vBox.getChildren().addAll(table, hBox);
Scene scene = new Scene(vBox);
window.setScene(scene);
window.show();
}
//Add button clicked
public void addButtonClicked(){
Product product = new Product();
product.setRock(rockInput.getText());
product.setWorld(Integer.parseInt(worldInput.getText()));
product.setAantalSpelers(Integer.parseInt(aantalSpelers.getText()));
//TESTBEREKENING seconden=(Integer.parseInt(aantalSpelers.getText())*10);
seconden=(Integer.parseInt(aantalSpelers.getText())*10);
product.setSeconden(seconden);
table.getItems().add(product);
rockInput.clear();
worldInput.clear();
aantalSpelers.clear();
}
//Delete button clicked
public void deleteButtonClicked(){
ObservableList<Product> productSelected, allProducts;
allProducts = table.getItems();
productSelected = table.getSelectionModel().getSelectedItems();
productSelected.forEach(allProducts::remove);
}
}
and this is the code from class Product:
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
public class Product {
private String rock;
private int world;
private int aantalSpelers;
//private int seconden;
private int timer;
private final IntegerProperty seconden = new SimpleIntegerProperty() ;
public Product(){
this.rock = "";
this.world = 0;
this.aantalSpelers = 0;
}
public Product(String rock, int world, int aantalSpelers){
this.rock = rock;
this.world = world;
this.aantalSpelers = aantalSpelers;
}
public String getRock() {
return rock;
}
public void setRock(String rock) {
this.rock = rock;
}
public int getWorld() {
return world;
}
public void setWorld(int world) {
this.world = world;
}
public int getAantalSpelers() {
return aantalSpelers;
}
public void setAantalSpelers(int aantalSpelers) {
this.aantalSpelers = aantalSpelers;
}
public final int getSeconden() {
return secondsProperty().get();
}
public final void setSeconden(int seconden) {
secondsProperty().set(seconden);
}
public int getTimer() {
return timer;
}
public void setTimer(int timer) {
this.timer = timer;
}
public Product(int seconden) {
setSeconden(seconden);
}
public IntegerProperty secondsProperty() {
return seconden ;
}
}
Just create a Timeline and decrease the value once per second every time a new row is added to the table:
public void start(Stage primaryStage) throws Exception {
// existing code...
// this just needs to be executed before any rows are added to the table:
table.getItems().addListener((Change<? extends Product> c) -> {
while (c.next()) {
if (c.wasAdded()) {
for (Product p : c.getAddedSubList()) {
int startValue = p.getSeconden();
Timeline countdown = new Timeline(new KeyFrame(Duration.seconds(1),
e -> p.setSeconden(p.getSeconden() - 1)));
countdown.setCycleCount(startValue);
countdown.play();
}
}
}
});
}
This assumes your Product class follows the JavaFX properties pattern, i.e. it has a public IntegerProperty secondenProperty() { ... } method.
Here is a SSCCE:
import java.util.regex.Pattern;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.collections.ListChangeListener.Change;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class CountdownTable extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
TableView<Item> table = new TableView<>();
TableColumn<Item, Integer> secondsCol = new TableColumn<>("Seconds");
table.getColumns().add(secondsCol);
secondsCol.setCellValueFactory(cellData -> cellData.getValue().secondsProperty().asObject());
table.getItems().addListener((Change<? extends Item> c) -> {
while (c.next()) {
if (c.wasAdded()) {
for (Item item : c.getAddedSubList()) {
int startValue = item.getSeconds() ;
Timeline countdown = new Timeline(new KeyFrame(Duration.seconds(1), e ->
item.setSeconds(item.getSeconds() - 1)
));
countdown.setCycleCount(startValue);
countdown.play();
}
}
}
});
TextField textField = new TextField();
textField.setPromptText("Type a time in seconds and press enter");
Pattern integerPattern = Pattern.compile("\\d*");
TextFormatter<Integer> formatter = new TextFormatter<Integer>( (TextFormatter.Change c) -> {
String newText = c.getControlNewText();
if (integerPattern.matcher(newText).matches()) {
return c ;
} else {
return null ;
}
});
textField.setTextFormatter(formatter);
textField.setOnAction(e -> {
if (! textField.getText().isEmpty())
table.getItems().add(new Item(Integer.parseInt(textField.getText())));
textField.clear();
});
BorderPane root = new BorderPane(table, null, null, textField, null);
primaryStage.setScene(new Scene(root, 600, 600));
primaryStage.show();
}
public static class Item {
private final IntegerProperty seconds = new SimpleIntegerProperty() ;
public Item(int seconds) {
setSeconds(seconds);
}
public IntegerProperty secondsProperty() {
return seconds ;
}
public final int getSeconds() {
return secondsProperty().get();
}
public final void setSeconds(int seconds) {
secondsProperty().set(seconds);
}
}
public static void main(String[] args) { launch(args); }
}
I have this combo box which inserts list of objects into combo box:
private List<ListGroupsObj> lisGroups;
public static class ListGroupsObj
{
private int groupId;
private String groupName;
public static ListGroupsObj newInstance()
{
return new ListGroupsObj();
}
public ListGroupsObj()
{
}
public ListGroupsObj groupId(int groupId)
{
this.groupId = groupId;
return this;
}
public ListGroupsObj groupName(String groupName)
{
this.groupName = groupName;
return this;
}
public int getGroupId()
{
return groupId;
}
public String getGroupName()
{
return groupName;
}
// #Override
// public String toString()
// {
// return serverName;
// }
}
ListGroupsObj ob = ListGroupsObj.newInstance().groupId(12).groupName("Group12");
ListGroupsObj osb = ListGroupsObj.newInstance().groupId(13).groupName("Group13");
ListGroupsObj oa = ListGroupsObj.newInstance().groupId(14).groupName("Group14");
ListGroupsObj oz = ListGroupsObj.newInstance().groupId(15).groupName("Group15");
final ComboBox<ListGroupsObj> listGroups = new ComboBox();
listGroups.getItems().addAll(ob, osb, oa, oz);
I would like to do something like this:
listGroups.getItems().addAll(listGroups);
How I can insert the list of the object into the combo box?
Updated
My Bad, missed the javaFX tag and jumped to conclusions...
What you "should" be able to do is something like...
final ComboBox<ListGroupsObj> listGroups = new ComboBox();
listGroups.getItems().addAll(ob, osb, oa, oz);
final ComboBox<ListGroupsObj> otherGroups = new ComboBox(listGroups.getItems());
This will pass the items of one combobox to other.
But you should also be able to do something like...
List<ListGroupsObj> listOfObjects = new ArrayList<>(5);
listOfObjects.add(ListGroupsObj.newInstance().groupId(12).groupName("Group12"));
listOfObjects.add(ListGroupsObj.newInstance().groupId(12).groupName("Group13"));
listOfObjects.add(ListGroupsObj.newInstance().groupId(12).groupName("Group14"));
listOfObjects.add(ListGroupsObj.newInstance().groupId(12).groupName("Group15"));
ObservableList<ListGroupsObj> observableListOfObjects = FXCollections.observableList(listOfObjects);
final ComboBox<ListGroupsObj> listGroups = new ComboBox(observableListOfObjects);
final ComboBox<ListGroupsObj> otherGroups = new ComboBox(observableListOfObjects);
Or
final ComboBox<ListGroupsObj> listGroups = new ComboBox();
listGroups.setItems(observableListOfObjects);
Or
final ComboBox<ListGroupsObj> listGroups = new ComboBox();
listGroups.getItems().addAll(observableListOfObjects);
This of course, will need to be tested ;)
Take a look at ComboBox JavaDocs for more details
Updated with runnable example
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class TestComboBox extends Application {
#Override
public void start(Stage primaryStage) {
Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Hello World!");
}
});
ListGroupsObj ob = ListGroupsObj.newInstance().groupId(12).groupName("Group12");
ListGroupsObj osb = ListGroupsObj.newInstance().groupId(13).groupName("Group13");
ListGroupsObj oa = ListGroupsObj.newInstance().groupId(14).groupName("Group14");
ListGroupsObj oz = ListGroupsObj.newInstance().groupId(15).groupName("Group15");
final ComboBox<ListGroupsObj> listGroups = new ComboBox();
listGroups.getItems().addAll(ob, osb, oa, oz);
final ComboBox<ListGroupsObj> otherGroups = new ComboBox(listGroups.getItems());
List<ListGroupsObj> listOfObjects = new ArrayList<>(5);
listOfObjects.add(ListGroupsObj.newInstance().groupId(12).groupName("Group12"));
listOfObjects.add(ListGroupsObj.newInstance().groupId(12).groupName("Group13"));
listOfObjects.add(ListGroupsObj.newInstance().groupId(12).groupName("Group14"));
listOfObjects.add(ListGroupsObj.newInstance().groupId(12).groupName("Group15"));
ObservableList<ListGroupsObj> observableListOfObjects = FXCollections.observableList(listOfObjects);
listGroups.setItems(observableListOfObjects);
otherGroups.getItems().addAll(observableListOfObjects);
VBox root = new VBox();
root.getChildren().add(btn);
root.getChildren().add(listGroups);
root.getChildren().add(otherGroups);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* The main() method is ignored in correctly deployed JavaFX application.
* main() serves only as fallback in case the application can not be launched
* through deployment artifacts, e.g., in IDEs with limited FX support.
* NetBeans ignores main().
*
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
public static class ListGroupsObj {
private int groupId;
private String groupName;
public static ListGroupsObj newInstance() {
return new ListGroupsObj();
}
public ListGroupsObj() {
}
public ListGroupsObj groupId(int groupId) {
this.groupId = groupId;
return this;
}
public ListGroupsObj groupName(String groupName) {
this.groupName = groupName;
return this;
}
public int getGroupId() {
return groupId;
}
public String getGroupName() {
return groupName;
}
// #Override
// public String toString()
// {
// return serverName;
// }
}
}
I'm trying to insert data into a Javafx TableView, actually I did it, but it fills the row with the following String:
IntegerProperty [value: 72] and etc...
How can I show only the value fill in my rows??
My TableView code:
#FXML TableView tableView = new TableView<MetaDadosInfo>();
#FXML javafx.scene.control.TableColumn instituicaoCol;
#FXML javafx.scene.control.TableColumn anoCol;
#FXML javafx.scene.control.TableColumn tamanhoCol;
#FXML javafx.scene.control.TableColumn tipoCol;
#FXML javafx.scene.control.TableColumn nomeCol;
final ObservableList<MetaDadosInfo> data = FXCollections.observableArrayList(
new MetaDadosInfo(codigoInstituicao, ano, size, type, name));
instituicaoCol.setCellValueFactory(
new PropertyValueFactory<MetaDadosInfo, String>("codigoInstituicao"));
anoCol.setCellValueFactory(
new PropertyValueFactory<MetaDadosInfo, String>("ano"));
tamanhoCol.setCellValueFactory(
new PropertyValueFactory<MetaDadosInfo, String>("size"));
tipoCol.setCellValueFactory(
new PropertyValueFactory<MetaDadosInfo, String>("type"));
nomeCol.setCellValueFactory(
new PropertyValueFactory<MetaDadosInfo, String>("name"));
tableView.setItems(data);
MetaDadosInfo class:
public class MetaDadosInfo {
private SimpleIntegerProperty codigoInstituicao;
private SimpleIntegerProperty ano;
private SimpleLongProperty size;
private SimpleStringProperty type;
private SimpleStringProperty name;
public MetaDadosInfo(int codigoInstituicao, int ano, long size, String type, String name) {
this.codigoInstituicao = new SimpleIntegerProperty (codigoInstituicao);
this.ano = new SimpleIntegerProperty (ano);
this.size = new SimpleLongProperty (size);
this.type = new SimpleStringProperty (type);
this.name = new SimpleStringProperty (name);
}
public SimpleIntegerProperty getCodigoInstituicao() {
return codigoInstituicao;
}
public void setCodigoInstituicao(SimpleIntegerProperty codigoInstituicao) {
this.codigoInstituicao = codigoInstituicao;
}
public SimpleIntegerProperty getAno() {
return ano;
}
public void setAno(SimpleIntegerProperty ano) {
this.ano = ano;
}
public SimpleLongProperty getSize() {
return size;
}
public void setSize(SimpleLongProperty size) {
this.size = size;
}
public SimpleStringProperty getType() {
return type;
}
public void setType(SimpleStringProperty type) {
this.type = type;
}
public SimpleStringProperty getName() {
return name;
}
public void setName(SimpleStringProperty name) {
this.name = name;
}
}
The error was in getters and setters from my MetaDadosInfo class, the right way is:
public class MetaDadosInfo {
private SimpleIntegerProperty codigoInstituicao;
private SimpleIntegerProperty ano;
private SimpleLongProperty size;
private SimpleStringProperty type;
private SimpleStringProperty name;
public MetaDadosInfo(int codigoInstituicao, int ano, long size, String type, String name) {
this.codigoInstituicao = new SimpleIntegerProperty (codigoInstituicao);
this.ano = new SimpleIntegerProperty (ano);
this.size = new SimpleLongProperty (size);
this.type = new SimpleStringProperty (type);
this.name = new SimpleStringProperty (name);
}
public int getCodigoInstituicao() {
return codigoInstituicao.get();
}
public void setCodigoInstituicao(int codigoInstituicao) {
this.codigoInstituicao.set(codigoInstituicao);
}
public int getAno() {
return ano.get();
}
public void setAno(int ano) {
this.ano.set(ano);
}
public Long getSize() {
return size.get();
}
public void setSize(long size) {
this.size.set(size);
}
public String getType() {
return type.get();
}
public void setType(String type) {
this.type.set(type);
}
public String getName() {
return name.get();
}
public void setName(String name) {
this.name.set(name);
}
}
After wasting my day i finally able to find the solution in very easy way
package test;
import java.util.HashMap;
import java.util.Map;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.MapValueFactory;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javafx.util.Callback;
import javafx.util.StringConverter;
public class Test extends Application {
public static final String Column1MapKey = "A";
public static final String Column2MapKey = "B";
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
Scene scene = new Scene(new Group());
stage.setTitle("Table View Sample");
stage.setWidth(300);
stage.setHeight(500);
final Label label = new Label("Student IDs");
label.setFont(new Font("Arial", 20));
TableColumn<Map, String> firstDataColumn = new TableColumn<>("Class A");
TableColumn<Map, String> secondDataColumn = new TableColumn<>("Class B");
firstDataColumn.setCellValueFactory(new MapValueFactory(Column1MapKey));
firstDataColumn.setMinWidth(130);
secondDataColumn.setCellValueFactory(new MapValueFactory(Column2MapKey));
secondDataColumn.setMinWidth(130);
TableView table_view = new TableView<>();
table_view.setItems(generateDataInMap());
table_view.setEditable(true);
table_view.getSelectionModel().setCellSelectionEnabled(true);
table_view.getColumns().setAll(firstDataColumn, secondDataColumn);
// Callback<TableColumn<Map, String>, TableCell<Map, String>> cellFactoryForMap = new Callback<TableColumn<Map, String>, TableCell<Map, String>>() {
// #Override
// public TableCell call(TableColumn p) {
// return new TextFieldTableCell(new StringConverter() {
// #Override
// public String toString(Object t) {
// return t.toString();
// }
//
// #Override
// public Object fromString(String string) {
// return string;
// }
// });
// }
// };
// firstDataColumn.setCellFactory(cellFactoryForMap);
// secondDataColumn.setCellFactory(cellFactoryForMap);
final VBox vbox = new VBox();
vbox.setSpacing(5);
vbox.setPadding(new Insets(10, 0, 0, 10));
vbox.getChildren().addAll(label, table_view);
((Group) scene.getRoot()).getChildren().addAll(vbox);
stage.setScene(scene);
stage.show();
}
private ObservableList<Map> generateDataInMap() {
int max = 10;
ObservableList<Map> allData = FXCollections.observableArrayList();
for (int i = 1; i < max; i++) {
Map<String, String> dataRow = new HashMap<>();
String value1 = "A" + i;
String value2 = "B" + i;
dataRow.put(Column1MapKey, value1);
dataRow.put(Column2MapKey, value2);
allData.add(dataRow);
}
return allData;
}
}
just try to change and use it in your way it can also be used directly in resultset
Happy Coding, Happy Innovation
This doesn't work with PropertyValueFactory because you have not declared your JavaFX beans with the expected naming conventions for the properties you have defined in your data model.
Refer to this post for how to use PropertyValueFactory correctly: How to use the PropertyValueFactory correctly?