I'm trying to put a SimpleStringProperty on a TableView this is the class im using:
package com.launch.history;
import java.net.URL;
import java.util.ResourceBundle;
import com.launch.WebController;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
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.input.MouseEvent;
public class HistoryController implements Initializable {
#FXML
private TableView<HistoryClient> tableView;
#FXML
private TableColumn<HistoryClient, String> tableColumn;
#Override
public void initialize(URL location, ResourceBundle resources) {
setTableView();
}
public void setColumns() {
tableColumn.setCellValueFactory(new PropertyValueFactory<HistoryClient, String>("history"));
}
public void setTableView() {
tableView.setItems(getHistory());
setColumns();
tableView.setOnMouseClicked(new EventHandler<MouseEvent>() {
#SuppressWarnings("static-access")
#Override
public void handle(MouseEvent event) {
if(tableView.getSelectionModel().getSelectedIndex() >= 0) {
HistoryClient link = tableView.getSelectionModel().getSelectedItem();
WebController.engine.load(link.getHistory());
}
}
});
}
public ObservableList<HistoryClient> getHistory() {
ObservableList<HistoryClient> data = FXCollections.observableArrayList();
data.addAll(new HistoryClient());
return data;
}
}
And this is the the stuff about history:
public static String getHistory() {
return history.get();
}
public static void setHistory(String history) {
HistoryClient.history.set(history);
}
private static SimpleStringProperty history = new SimpleStringProperty();
But i only get 1 line on my TableView(The last link)
And this is how i set the value of history:
public static void readHistory() {
if(Files.HISTORY_FILE.exists()) {
try(BufferedReader in = new BufferedReader(new FileReader(Files.HISTORY_FILE))) {
String line;
while( (line = in.readLine()) != null) {
history.set(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
That works fine i printed out history and it was the same as in the file so i really don't see the problem because last time when i used TableView i kinda did the same thing.
And yes i did set the fx:id in scene builder.
Related
I am making a to do list with java FXML using file reader and writer and scene builder. I have been trying to add a completed task function but tried many ways and am unable to figure out something which will work for me. I tried making a separate list where I keep my completed task but its still not working out for me. At this moment I have tried a lot by myself and am willing to go for another for another method to add this function. I am using To Do Date Class which is using to do Item class.
I have tried using it as predicate of filtered list and type casting accordingly but it hasn't worked out for me either.Rest of code works perfectly fine.
controller is:
package todolist;
import java.io.IOException;
import java.net.URL;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.ResourceBundle;
import java.util.function.Predicate;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.collections.transformation.SortedList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonType;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Dialog;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.MenuItem;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TextArea;
import javafx.scene.control.ToggleButton;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.util.Callback;
/**
*
* #author Pc Planet
*/
public class FXMLDocumentController {
private List<ToDoItem> todoItems;
#FXML
private ListView<ToDoItem> todoListView;
#FXML
private TextArea itemDetailsTextArea;
#FXML
private Label deadlineLabel;
#FXML
private BorderPane mainBorderPane;
#FXML
private ContextMenu listContextMenu;
#FXML
private ToggleButton filterToggleButton;
#FXML
private Button exit,ADD;
private FilteredList<ToDoItem> filteredList;
private Predicate<ToDoItem> wantAllItems;
private Predicate<ToDoItem> wantTodaysItems;
private Predicate<ToDoItem> uncompleted;
private ObservableList<ToDoItem> completed;
public void initialize() {
// delete
listContextMenu = new ContextMenu();
MenuItem deleteMenuItem = new MenuItem("Delete");
deleteMenuItem.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
ToDoItem item = todoListView.getSelectionModel().getSelectedItem();
deleteItem(item);
}
});
// Completed
listContextMenu = new ContextMenu();
MenuItem completedMenuItem = new MenuItem("Mark as complete");
completedMenuItem.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
ToDoItem item = todoListView.getSelectionModel().getSelectedItem();
completedItem(item);
}
});
listContextMenu.getItems().addAll(deleteMenuItem);
listContextMenu.getItems().addAll(completedMenuItem);
//change
todoListView.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<ToDoItem>() {
#Override
public void changed(ObservableValue<? extends ToDoItem> observable, ToDoItem oldValue, ToDoItem newValue) {
if(newValue != null) {
ToDoItem item = todoListView.getSelectionModel().getSelectedItem();
itemDetailsTextArea.setText(item.getDetails());
DateTimeFormatter df = DateTimeFormatter.ofPattern("MMMM d, yyyy"); // "d M yy");
deadlineLabel.setText(df.format(item.getDeadline()));
}
}
});
wantAllItems = (ToDoItem todoItem) -> true;
wantTodaysItems = (ToDoItem todoItem) -> (todoItem.getDeadline().equals(LocalDate.now()));
filteredList = new FilteredList<ToDoItem>(ToDoData.getInstance().getTodoItems(), wantAllItems);
// list sort
SortedList<ToDoItem> sortedList = new SortedList<ToDoItem>(filteredList,
new Comparator<ToDoItem>() {
#Override
public int compare(ToDoItem o1, ToDoItem o2) {
return o1.getDeadline().compareTo(o2.getDeadline());
}
});
todoListView.setItems(sortedList);
todoListView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
todoListView.getSelectionModel().selectFirst();
todoListView.setCellFactory(new Callback<ListView<ToDoItem>, ListCell<ToDoItem>>() {
#Override
public ListCell<ToDoItem> call(ListView<ToDoItem> param) {
ListCell<ToDoItem> cell = new ListCell<ToDoItem>() {
#Override
protected void updateItem(ToDoItem item, boolean empty) {
super.updateItem(item, empty);
if(empty) {
setText(null);
} else {
setText(item.getShortDescription());
if(item.getDeadline().isBefore(LocalDate.now().plusDays(1))) {
setTextFill(Color.RED);
} else {
setTextFill(Color.GREEN);
}
}
}
};
cell.emptyProperty().addListener(
(obs, wasEmpty, isNowEmpty) -> {
if(isNowEmpty) {
cell.setContextMenu(null);
} else {
cell.setContextMenu(listContextMenu);
}
});
return cell;
}
});
}
#FXML
public void showNewItemDialog() {
Dialog<ButtonType> dialog = new Dialog<>();
dialog.initOwner(mainBorderPane.getScene().getWindow());
dialog.setTitle("Add New Todo Item");
dialog.setHeaderText("Use this dialog to create a new todo item");
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(getClass().getResource("todoitemdialog.fxml"));
try {
dialog.getDialogPane().setContent(fxmlLoader.load());
} catch(IOException e) {
System.out.println("Couldn't load the dialog");
e.printStackTrace();
return;
}
dialog.getDialogPane().getButtonTypes().add(ButtonType.OK);
dialog.getDialogPane().getButtonTypes().add(ButtonType.CANCEL);
Optional<ButtonType> result = dialog.showAndWait();
if(result.isPresent() && result.get() == ButtonType.OK) {
DialogController controller = fxmlLoader.getController();
ToDoItem newItem = controller.processResults();
todoListView.getSelectionModel().select(newItem);
}
}
#FXML
public void completedtasks(ActionEvent event){
}
#FXML
public void handleKeyPressed(KeyEvent keyEvent) {
ToDoItem selectedItem = todoListView.getSelectionModel().getSelectedItem();
if(selectedItem != null) {
if(keyEvent.getCode().equals(KeyCode.DELETE)) {
deleteItem(selectedItem);}
else{
completedItem(selectedItem);
}
}
}
public void handleClickListView() {
ToDoItem item = todoListView.getSelectionModel().getSelectedItem();
itemDetailsTextArea.setText(item.getDetails());
deadlineLabel.setText(item.getDeadline().toString());
}
public void deleteItem(ToDoItem item) {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("Delete Todo Item");
alert.setHeaderText("Delete item: " + item.getShortDescription());
alert.setContentText("Are you sure? Press OK to confirm or cancel to Back out.");
Optional<ButtonType> result = alert.showAndWait();
if(result.isPresent() && (result.get() == ButtonType.OK)) {
ToDoData.getInstance().deleteTodoItem(item);
}
}
public void completedItem(ToDoItem item) {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("Mark as Completed");
alert.setHeaderText("Completed task: " + item.getShortDescription());
alert.setContentText("Are you sure? Press OK to confirm or cancel to Back out.");
Optional<ButtonType> result = alert.showAndWait();
if(result.isPresent() && (result.get() == ButtonType.OK)) {
ToDoData.getInstance().completed(item);
}
}
#FXML
public void wantTodaysItems(){
ToDoItem selectedItem = todoListView.getSelectionModel().getSelectedItem();
filteredList.setPredicate(wantTodaysItems);
if(filteredList.isEmpty()) {
itemDetailsTextArea.clear();
deadlineLabel.setText("");
} else if(filteredList.contains(selectedItem)) {
todoListView.getSelectionModel().select(selectedItem);
} else {
todoListView.getSelectionModel().selectFirst();
}
}
#FXML
public void wantAllItems(){
ToDoItem selectedItem = todoListView.getSelectionModel().getSelectedItem();
filteredList.setPredicate(wantAllItems);
if(filteredList.isEmpty()) {
itemDetailsTextArea.clear();
deadlineLabel.setText("");
} else if(filteredList.contains(selectedItem)) {
todoListView.getSelectionModel().select(selectedItem);
} else {
todoListView.getSelectionModel().selectFirst();
}
}
#FXML
public void handleExit() {
Platform.exit();
}
}
ToDoData class is:
package todolist;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Iterator;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
public class ToDoData {
private static ToDoData instance = new ToDoData();
private static String filename = "TodoListItems.txt";
private ObservableList<ToDoItem> todoItems;
private ObservableList<ToDoItem> completed;
private DateTimeFormatter formatter;
public static ToDoData getInstance() {
return instance;
}
private ToDoData() {
formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
}
public ObservableList<ToDoItem> getTodoItems() {
return todoItems;
}
public void addTodoItem(ToDoItem item) {
todoItems.add(item);
}
public void loadTodoItems() throws IOException {
todoItems = FXCollections.observableArrayList();
Path path = Paths.get(filename);
BufferedReader br = Files.newBufferedReader(path);
String input;
try {
while ((input = br.readLine()) != null) {
String[] itemPieces = input.split("\t");
String shortDescription = itemPieces[0];
String details = itemPieces[1];
String dateString = itemPieces[2];
LocalDate date = LocalDate.parse(dateString, formatter);
ToDoItem todoItem = new ToDoItem(shortDescription, details, date);
todoItems.add(todoItem);
}
} finally {
if(br != null) {
br.close();
}
}
}
public void storeTodoItems() throws IOException {
Path path = Paths.get(filename);
BufferedWriter bw = Files.newBufferedWriter(path);
try {
Iterator<ToDoItem> iter = todoItems.iterator();
while(iter.hasNext()) {
ToDoItem item = iter.next();
bw.write(String.format("%s\t%s\t%s",
item.getShortDescription(),
item.getDetails(),
item.getDeadline().format(formatter)));
bw.newLine();
}
} finally {
if(bw != null) {
bw.close();
}
}
}
public void deleteTodoItem(ToDoItem item) {
todoItems.remove(item);
}
public void completed(ToDoItem item){
completed.add(item);
}
public ObservableList <ToDoItem> completed(){
return completed;
}
}
todoItem class is:
package todolist;
import java.time.LocalDate;
public class ToDoItem {
private String shortDescription;
private String details;
private LocalDate deadline;
public ToDoItem(String shortDescription, String details, LocalDate deadline) {
this.shortDescription = shortDescription;
this.details = details;
this.deadline = deadline;
}
public String getShortDescription() {
return shortDescription;
}
public void setShortDescription(String shortDescription) {
this.shortDescription = shortDescription;
}
public String getDetails() {
return details;
}
public void setDetails(String details) {
this.details = details;
}
public LocalDate getDeadline() {
return deadline;
}
public void setDeadline(LocalDate deadline) {
this.deadline = deadline;
}
}
This answer is assuming I understand you correctly. In this example, I use a FilteredList on the TableView, and I used the FilteredList's Predicate to show the data in the TableView based on the Button that is pressed. I altered the answer from here.
KeyCode 1
This code allows the TableView to update when the CheckBox values changes.
todoItem -> new Observable[] { todoItem.completeProperty()}
Key Code 2
This code allows the FilteredList to set the TableView's data based on the Button that is pressed.
flToDoItems.setPredicate((todoItem) -> {
return todoItem.getComplete();
});
Main
import java.time.LocalDate;
import java.util.Arrays;
import javafx.application.Application;
import javafx.beans.Observable;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.CheckBoxTableCell;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class App extends Application
{
final TableView<ToDoItem> selectionTableView = new TableView<>();
private final ObservableList<ToDoItem> toDoItems = FXCollections.observableList(
Arrays.asList(
new ToDoItem("Task 1", "This is Task 1", LocalDate.now().plusMonths(1)),
new ToDoItem("Task 2", "This is Task 2", LocalDate.now().plusMonths(2)),
new ToDoItem("Task 3", "This is Task 3", LocalDate.now().plusMonths(3)),
new ToDoItem("Task 4", "This is Task 4", LocalDate.now().plusMonths(4)),
new ToDoItem("Task 5", "This is Task 5", LocalDate.now().plusMonths(5))
),
todoItem -> new Observable[] { todoItem.completeProperty()}//This is needed for automatic updates in the TableView!!!!
);
final FilteredList<ToDoItem> flToDoItems = new FilteredList(toDoItems, p -> true);
public static void main(String[] args)
{
launch();
}
#Override
public void start(Stage stage)
{
final TableView<ToDoItem> todoListSelectionTableView = createTodoListSelectionTableView();
todoListSelectionTableView.setItems(flToDoItems);
Button btnAllTasks = new Button("All");
btnAllTasks.setOnAction((t) -> {
flToDoItems.setPredicate((todoItem) -> {
return true;
});
});
Button btnCompleteTasks = new Button("Complete");
btnCompleteTasks.setOnAction((t) -> {
flToDoItems.setPredicate((todoItem) -> {
return todoItem.getComplete();
});
});
Button btnIncompleteTask = new Button("Incomplete");
btnIncompleteTask.setOnAction((t) -> {
flToDoItems.setPredicate((todoItem) -> {
return !todoItem.getComplete();
});
});
VBox root = new VBox(new HBox(btnAllTasks, btnIncompleteTask, btnCompleteTasks), todoListSelectionTableView);
Scene scene = new Scene(root, 500, 500);
stage.setScene(scene);
stage.show();
}
private TableView<ToDoItem> createTodoListSelectionTableView() {
selectionTableView.setPrefSize(440, 180);
TableColumn<ToDoItem, String> shortDescriptionColumn = new TableColumn<>("Short Description");
shortDescriptionColumn.setCellValueFactory(cd -> cd.getValue().shortDescriptionProperty());
selectionTableView.getColumns().add(shortDescriptionColumn);
TableColumn<ToDoItem, String> detailsColumn = new TableColumn<>("Details");
detailsColumn.setCellValueFactory(cd -> cd.getValue().detailsProperty());
selectionTableView.getColumns().add(detailsColumn);
TableColumn<ToDoItem, LocalDate> deadlineColumn = new TableColumn<>("Deadline");
deadlineColumn.setCellValueFactory(cd -> cd.getValue().deadlineProperty());
selectionTableView.getColumns().add(deadlineColumn);
TableColumn<ToDoItem, Boolean> completeColumn = new TableColumn<>("Complete");
completeColumn.setCellValueFactory(cd -> cd.getValue().completeProperty());
completeColumn.setCellFactory(CheckBoxTableCell.forTableColumn(completeColumn));
selectionTableView.getColumns().add(completeColumn);
selectionTableView.setEditable(true);
return selectionTableView;
}
}
ToDoItem
import java.time.LocalDate;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class ToDoItem {
private final StringProperty shortDescription;
private final StringProperty details;
private final ObjectProperty<LocalDate> deadline;
private final BooleanProperty complete;
public ToDoItem(String shortDescription, String details, LocalDate deadline) {
this.shortDescription = new SimpleStringProperty(shortDescription);
this.details = new SimpleStringProperty(details);
this.deadline = new SimpleObjectProperty(deadline);
this.complete = new SimpleBooleanProperty(false);
}
public String getShortDescription() {
return shortDescription.get();
}
public void setShortDescription(String shortDescription) {
this.shortDescription.set(shortDescription);
}
public StringProperty shortDescriptionProperty()
{
return this.shortDescription;
}
public String getDetails() {
return details.get();
}
public void setDetails(String details) {
this.details.set(details);
}
public StringProperty detailsProperty()
{
return this.details;
}
public LocalDate getDeadline() {
return deadline.get();
}
public void setDeadline(LocalDate deadline) {
this.deadline.set(deadline);
}
public ObjectProperty<LocalDate> deadlineProperty()
{
return this.deadline;
}
public void setComplete(boolean complete)
{
this.complete.set(complete);
}
public boolean getComplete()
{
return this.complete.get();
}
public BooleanProperty completeProperty()
{
return this.complete;
}
}
Output
This question already has answers here:
Passing Parameters JavaFX FXML
(10 answers)
Closed 2 years ago.
i'm trying to redirect a user after he connect to the database.
This is my controller with the login method :
package packages.home;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.TextField;
import javafx.scene.control.Label;
import javafx.scene.control.Button;
import static javax.swing.JOptionPane.showMessageDialog;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class Controller extends Thread {
#FXML
private Button btnClose;
#FXML
private TextField txtUsername;
#FXML
private TextField txtPassword;
#FXML
private Label lblErrors;
#FXML
private Button btnConnect;
/// --
Connection laConnection = GestionConnection.getLaConnection();
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
public void handleButtonAction(MouseEvent event) throws IOException{
if (event.getSource() == btnClose) {
System.exit(0);
System.out.println("Fermeture de l'application.");
}
if (event.getSource() == btnConnect) {
//login here
if (logIn().equals("Success")) {
try {
//add you loading or delays - ;-)
Node node = (Node) event.getSource();
Stage stage = (Stage) node.getScene().getWindow();
//stage.setMaximized(true);
stage.close();
Scene scene = new Scene(FXMLLoader.load(getClass().getResource("Login.fxml")));
stage.setScene(scene);
stage.show();
} catch (IOException ex) {
System.err.println(ex.getMessage());
}
}
}
}
private String logIn() {
String status = "Success";
String username = txtUsername.getText();
String password = txtPassword.getText();
if(username.isEmpty() || password.isEmpty()) {
setLblErrors(Color.RED, "Champs vides.");
status = "Error";
} else {
//query
String sql = "SELECT * FROM admins Where username = ? and password = ?";
try {
// On test la requête
System.out.println("Hello");
preparedStatement = laConnection.prepareStatement(sql);
preparedStatement.setString(1, username);
preparedStatement.setString(2, password);
resultSet = preparedStatement.executeQuery();
if (!resultSet.next()) {
setLblErrors(Color.TOMATO, "Nom d'utilisateur ou mot de passe incorrect");
status = "Error";
} else {
setLblErrors(Color.GREEN, "Authentification réussite, redirection en cours ...");
showMessageDialog(null, "Vous êtes bien connecté");
}
} catch (SQLException ex) {
System.err.println(ex.getMessage());
status = "Exception";
}
}
return status;
}
private void setLblErrors(Color color, String text) {
lblErrors.setTextFill(color);
lblErrors.setText(text);
System.out.println(text);
}
}
This is my new fxml controller :
package packages.home;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.layout.AnchorPane;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
public class DashboardController implements Initializable {
#FXML
private AnchorPane rootPane;
public DashboardController(AnchorPane rootPane) {
this.rootPane = rootPane;
}
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
}
#FXML
private void loadSecond(ActionEvent event) throws IOException{
AnchorPane pane = FXMLLoader.load(getClass().getResource("dashboard.fxml"));
rootPane.getChildren().setAll(pane);
}
}
I do know how to make the link between my first controller and my new controller.
I'm new to javaFX and i wil be happy to learn new things about it.
Thanks in advance for your help.
Static Way
For example:
public class Main {
public static void main(String[] args) { ... }
public static Scene scene;
#Override
public void start (Stage stage) {
...
scene = new Scene(FXMLoader.load(...)); //Controller fxml
stage.setScene(scene);
...
}
public static void setRoot(AnchorPane pane, Parent parent) {
pane.getChildren().clear();
scene.setRoot(parent);
}
}
In Controller.java create an #FXML reference to the AnchorPane being used and pass it in the function.
if (connected) {
Main.setRoot(pane, FXMLoader.load(...)); //new screen fxml
}
EDIT: Getting reference
public void setRoot(AnchorPane pane, Parent parent) {
pane.getChildren().clear();
pane.getScene().setRoot(parent);
}
Don't call getScene() in the initialize method of a controller for the scene will be null.
if (connected) {
setRoot(pane, FXMLoader.load(...)); //new screen fxml
}
If this is a duplicate, my apologies, but I wasn't able to find an answer quite yet.
I am working on a project to run a basic inventory management system in JavaFX. I am currently trying to allow the user to add new items into a SQLite database, and while the ID and item name gets added into the database just fine, the initial value that is entered into a textfield seems to be ignored.
The program instead puts a value of 0.0 in the units available field. Here is my current code:
Main.java
package sample;
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 {
#Override
public void start(Stage primaryStage){
try {
Parent root = FXMLLoader.load(getClass().getResource("DatabaseView.fxml"));
Scene scene = new Scene(root);
primaryStage.setTitle("Brewer's Guide Inventory Management");
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
beerDatabaseData.java
package sample;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class beerDatabaseData {
private final StringProperty ID;
private final StringProperty name;
private DoubleProperty units;
public beerDatabaseData (String ID, String Name, Double Units)
{
this.ID = new SimpleStringProperty(ID);
this.name = new SimpleStringProperty(Name);
this.units = new SimpleDoubleProperty(Units);
}
public StringProperty IDProperty()
{
return this.ID;
}
public String getID()
{
return this.IDProperty().get();
}
public void setID(final String ID)
{
this.IDProperty().set(ID);
}
public StringProperty nameProperty()
{
return this.name;
}
public String getName()
{
return this.nameProperty().get();
}
public void setName(final String name)
{
this.nameProperty().set(name);
}
public DoubleProperty unitsProperty()
{
return this.units;
}
public Double getUnits()
{
return this.unitsProperty().get();
}
public void setUnits(Double units)
{
this.unitsProperty().set(units);
}
}
DatabaseViewController
package sample;
/*
Add method to auto-load data rather than pressing button (possible on-load).
Look at dependency injection (inversion of control (if possible) for testing).
Malt service (all actions with malt data).
Separation of concerns.
*/
//https://stackoverflow.com/questions/50358299/javafx-populating-multiple-tables-in-separate-tabs
//https://stackoverflow.com/questions/41465181/tableview-update-database-on-edit
//https://stackoverflow.com/questions/45977390/how-to-force-a-double-input-in-a-textfield-in-javafx
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import java.net.URL;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ResourceBundle;
public class DatabaseViewController {
#FXML
private TextField idNumberInput1, idNumberInput2;
#FXML
private TextField nameInput1, nameInput2;
#FXML
private TextField unitsInput1, unitsInput2;
#FXML
private TableView<beerDatabaseData> beerTab1, beerTab2;
#FXML
private TableColumn<beerDatabaseData, String> ID1, ID2;
#FXML
private TableColumn<beerDatabaseData, String> name1, name2;
#FXML
private TableColumn<beerDatabaseData, Double> units1, units2;
/*private ObservableList<DatabaseData> data;*/
public void initialize(URL location, ResourceBundle resource) {
//
}
private ObservableList<beerDatabaseData> data1;
private ObservableList<beerDatabaseData> data2;
public void LoadData(ActionEvent event) throws SQLException {
try {
Connection conn = SQLConnection.Connector();
this.data1 = FXCollections.observableArrayList();
this.data2 = FXCollections.observableArrayList();
ResultSet rs1 = conn.createStatement().executeQuery("SELECT * FROM Malts");
while (rs1.next()) {
this.data1.add(new beerDatabaseData(rs1.getString(1), rs1.getString(2), rs1.getDouble(3)));
}
ResultSet rs2 = conn.createStatement().executeQuery("SELECT * FROM HOPS");
while (rs2.next()) {
this.data2.add(new beerDatabaseData(rs2.getString(1), rs2.getString(2), rs2.getDouble(3)));
}
}catch (SQLException e) {
System.out.println(e);
}
this.ID1.setCellValueFactory(new PropertyValueFactory<beerDatabaseData, String>("ID"));
this.name1.setCellValueFactory(new PropertyValueFactory<beerDatabaseData, String>("Name"));
this.units1.setCellValueFactory(new PropertyValueFactory<beerDatabaseData, Double>("Units"));
this.beerTab1.setItems(null);
this.beerTab1.setItems(this.data1);
this.ID2.setCellValueFactory(new PropertyValueFactory<beerDatabaseData, String>("ID"));
this.name2.setCellValueFactory(new PropertyValueFactory<beerDatabaseData, String>("Name"));
this.units2.setCellValueFactory(new PropertyValueFactory<beerDatabaseData, Double>("Units"));
this.beerTab2.setItems(null);
this.beerTab2.setItems(this.data2);
}
//Separating add functions for each ingredient since things are a little different for each.
public void addMalt(ActionEvent event){
try
{
Connection conn = SQLConnection.Connector();
PreparedStatement Prs = conn.prepareStatement("INSERT INTO Malts(Malt_ID,Malt_Name, Malt_Units) VALUES(?, ?, ?)");
Prs.setString(1,this.idNumberInput1.getText());
Prs.setString(2, this.nameInput1.getText());
/* Pattern validEditingState = Pattern.compile("-?(([1-9][0-9]*)|0)?(\\.[0-9]*)?");
UnaryOperator<TextFormatter.Change> filter = c -> {
String text = c.getControlNewText();
if(validEditingState.matcher(text).matches()){
return c;
}
else{
return null;
}
};
StringConverter<Double> converter = new StringConverter<Double>() {
#Override
public Double fromString(String s) {
if (s.isEmpty() || "-".equals(s) || ".".equals(s) || "-.".equals(s)){
return 0.0;
} else{
return Double.valueOf(s);
}
}
#Override
public String toString(Double d) {
return d.toString();
}
};
TextFormatter<Double> textFormatter = new TextFormatter<>(converter, 0.0, filter);
unitsInput1.setTextFormatter(textFormatter);
*/
Prs.setString(3, this.unitsInput1.getText());
Prs.execute();
conn.close();
}
catch(SQLException e)
{
System.out.println(e);
}
}
/* public void addHops(ActionEvent event){
try
{
Connection conn = SQLConnection.Connector();
}
catch(SQLException e){
System.out.println(e);
}
}*/
}
I imagine there's a glaring issue that is causing this, but I'm not seeing it. What do I need to change or include to make this work? Thank you in advanced.
Looks like the Malt_Units column in your table is numeric, but you try to insert it as a string. You should parse the value in your input and then set it as Double:
Prs.setDouble(3, Double.parseDouble(this.unitsInput1.getText()));
So I am writing an AutosuggestMenu that adds a listener to a TextField and recommends suggestions in a popup ContextMenu, based on comparing the keystrokes entered with the Collection of words provided.
Unfortunately, changes to the ContextMenu elements are not displayed, and I suspect this is because I am modifying the elements of the ObservableList associated with the ContextMenu and not the list itself.
Browsing stack has led to believe I should implement an extractor, but based on the examples provided I have no idea how to do this for my specific problem. Any solution would be very much appreciated!
Source:
package com.sknb.gui;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import javafx.geometry.Side;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.CustomMenuItem;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextField;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;
public class AutosuggestMenu {
public final static int DEFAULT_MENU_SIZE = 10;
//Data members
private int menuSize;
private Collection<String> wordList;
//GUI members
private ContextMenu menu;
private final Text textBefore, textMatching, textAfter;
public AutosuggestMenu(Collection<String> keyList) {
this(keyList, DEFAULT_MENU_SIZE);
}
public AutosuggestMenu(Collection<String> keyList, int numEntries) {
if (keyList == null) {
throw new NullPointerException();
}
this.wordList = keyList;
this.menuSize = numEntries;
this.menu = new ContextMenu();
for (int i = 0; i < this.menuSize; i++) {
CustomMenuItem item = new CustomMenuItem(new Label(), true);
this.menu.getItems().add(item);
}
this.textBefore = new Text();
this.textMatching = new Text();
this.textAfter = new Text();
}
public void addListener(TextField field) {
field.textProperty().addListener((observable, oldValue, newValue) -> {
String enteredText = field.getText();
if (enteredText == null || enteredText.isEmpty()) {
this.menu.hide();
} else {
List<String> filteredEntries = this.wordList.stream()
.filter(e -> e.contains(enteredText))
.collect(Collectors.toList());
if (!filteredEntries.isEmpty()) {
populatePopup(field, filteredEntries, enteredText);
if (!(this.menu.isShowing())) {
this.menu.show(field, Side.BOTTOM, 0, 0);
}
} else {
this.menu.hide();
}
}
});
field.focusedProperty().addListener((observableValue, oldValue, newValue) -> {
this.menu.hide();
});
}
private void populatePopup(TextField field, List<String> matches, String query) {
int i = 0,
max = (matches.size() > this.menuSize) ? this.menuSize :
matches.size();
for (MenuItem item : this.menu.getItems()) {
if (i < max) {
String result = matches.get(i);
item.setGraphic(generateTextFlow(result, query));
item.setVisible(true);
item.setOnAction(actionEvent -> {
field.setText(result);
field.positionCaret(result.length());
this.menu.hide();
});
} else {
item.setVisible(false);
}
i++;
}
}
private TextFlow generateTextFlow(String text, String filter) {
int filterIndex = text.indexOf(filter);
this.textBefore.setText(text.substring(0, filterIndex));
this.textAfter.setText(text.substring(filterIndex + filter.length()));
this.textMatching.setText(text.substring(filterIndex, filterIndex + filter.length()));
textMatching.setFill(Color.BLUE);
textMatching.setFont(Font.font("Helvetica", FontWeight.BOLD, 12));
return new TextFlow(textBefore, textMatching, textAfter);
}
public int getMenuSize() {
return this.menuSize;
}
public void setMenuSize(int size) {
this.menuSize = size;
}
public Collection<String> getKeyList() {
return this.wordList;
}
public void setKeyList(Collection<String> keyList) {
this.wordList = keyList;
}
//To do: add ways to change style of ContextMenu/menu items/text elements
}
Test class using a text file of English words as a dictionary:
package autosuggestfieldtest;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Collection;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import com.sknb.gui.AutosuggestMenu;
public class AutosuggestFieldTest extends Application {
private TextField textfield;
private Collection<String> words;
private AutosuggestMenu popup;
#Override
public void start(Stage primaryStage) {
String filename = Paths.get("").toAbsolutePath().toString() + "\\words.txt";
try (Stream<String> stream = Files.lines(Paths.get(filename))) {
words = stream
.collect(Collectors.toSet());
} catch (IOException e) {
System.out.println("DERP");
}
popup = new AutosuggestMenu(words);
textfield = new TextField();
popup.addListener(textfield);
StackPane root = new StackPane();
root.getChildren().add(textfield);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("AutocompleteField Test");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Note: this is a modification of a similar solution by Ruslan, but I was wondering if there is a solution that does not involve clearing/repopulating the menu with every keystroke? I.e. just using the setGraphic and refreshing the ContextMenu?
I want to trigger a method or action when the user check or uncheck a checkbox in the tableView. the coursData.addListener(...) doesn't get triggered when the user use the checkBox .
Here is my code it compiles and the windows appears with the tableView with checkbox.
package testCheckBox2;
import javafx.application.Application;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
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.ButtonBase;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.CheckBoxTableCell;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class CheckBoxTableCellTest extends Application {
private TableView<cours> tableView;
public ObservableList<cours> coursData ;//= FXCollections.observableArrayList();
#Override
public void start(Stage primaryStage) {
this.tableView = new TableView<cours>();
final TableColumn<cours, String> Cours = new TableColumn<cours, String>("Cours");
final TableColumn<cours, Boolean> checkedCol = new TableColumn<cours, Boolean>("Checked");
this.coursData =FXCollections.observableArrayList(
new cours("Analyse", "3"),
new cours("Analyse TP", "4"),
new cours("Thermo", "5"),
new cours("Thermo TP", "7"),
new cours("Chimie", "8"));
tableView.setItems(this.coursData);
tableView.getColumns().addAll(Cours, checkedCol);
Cours.setCellValueFactory(new PropertyValueFactory<cours, String>("cours"));
checkedCol.setCellValueFactory(new PropertyValueFactory<cours, Boolean>("checked"));
checkedCol.setCellFactory(CheckBoxTableCell.forTableColumn(checkedCol));
checkedCol.setEditable(true);
tableView.setEditable(true);
final BorderPane root = new BorderPane();
root.setCenter(tableView);
coursData.addListener(new InvalidationListener() {
#Override public void invalidated(Observable o) {
System.out.println("checkBox change state ");
//Here is my problem.
//When the user click on a checkBox , the method isn't call .
}
});
Scene scene = new Scene(root, 300, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
public static class cours {
private StringProperty cours;
private StringProperty coursID;
private BooleanProperty checked;
public cours(String cours, String coursID) {
this.cours = new SimpleStringProperty(cours);
this.coursID = new SimpleStringProperty(coursID);
this.checked = new SimpleBooleanProperty(false);
}
public String getCours() {
return cours.get();
}
public String getCoursID() {
return coursID.get();
}
public boolean isChecked() {
return checked.get();
}
public void setCours(String cours) {
this.cours.set(cours);
}
public void setCoursID(String coursID) {
this.coursID.set(coursID);
}
public void setChecked(boolean checked) {
this.checked.set(checked);
}
public StringProperty coursProperty() {
return cours;
}
public StringProperty coursIDProperty() {
return coursID;
}
public BooleanProperty checkedProperty() {
return checked;
}
}
}
You have two ways of getting a notification when any of the check boxes is clicked.
One: providing a callback as argument for CheckBoxTableCell.forTableColumn instead of the tableColumn:
checkedCol.setCellFactory(CheckBoxTableCell.forTableColumn(new Callback<Integer, ObservableValue<Boolean>>() {
#Override
public ObservableValue<Boolean> call(Integer param) {
System.out.println("Cours "+items.get(param).getCours()+" changed value to " +items.get(param).isChecked());
return items.get(param).checkedProperty();
}
}));
Two: providing a callback to the collection:
final List<Cours> items=Arrays.asList(new Cours("Analyse", "3"),
new Cours("Analyse TP", "4"),
new Cours("Thermo", "5"),
new Cours("Thermo TP", "7"),
new Cours("Chimie", "8"));
this.coursData = FXCollections.observableArrayList(new Callback<Cours, Observable[]>() {
#Override
public Observable[] call(Cours param) {
return new Observable[] {param.checkedProperty()};
}
});
coursData.addAll(items);
and now listening to changes in the collection:
coursData.addListener(new ListChangeListener<Cours>() {
#Override
public void onChanged(ListChangeListener.Change<? extends Cours> c) {
while (c.next()) {
if (c.wasUpdated()) {
System.out.println("Cours "+items.get(c.getFrom()).getCours()+" changed value to " +items.get(c.getFrom()).isChecked());
}
}
}
});