Pausing JavaFX task crashes App - javafx

I am a novice on JavaFX.
Recently I was trying to modify the code by jewelsea found on this link :
https://gist.github.com/jewelsea/4989970#file-promptingtaskdemo-java-L87
On the code above, the program pauses a FutureTask with a dialog.showAndWait() method.
I was trying to pause a Task using something else so I commented out the showAndWait(), and added a button with this code
Platform.runLater(task);
try {
task.get();
} catch(ExecutionException ee) {}
catch(InterruptedException ie) {}
in its .setOnAction(), but it crashes the application everytime the button is pressed, any help will really be appreciated.
public class PromptingTaskDemo extends Application {
private static final String[] SAMPLE_TEXT =
"MISSING Lorem ipsum dolor sit amet MISSING consectetur adipisicing elit sed do eiusmod tempor incididunt MISSING ut labore et dolore magna aliqua"
.split(" ");
#Override public void start(Stage primaryStage) {
Label status = new Label();
ProgressBar progress = new ProgressBar();
Button pauseButton = new Button("Pause");
VBox textContainer = new VBox(10);
textContainer.setStyle("-fx-background-color: burlywood; -fx-padding: 10;");
LoadTextTask task = new LoadTextTask(SAMPLE_TEXT, textContainer);
status.textProperty().bind(task.messageProperty());
progress.progressProperty().bind(task.progressProperty());
final Thread taskThread = new Thread(task, "label-generator");
taskThread.setDaemon(true);
pauseButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Platform.runLater(task);
try {
task.get();
} catch(ExecutionException ee) {}
catch(InterruptedException ie) {}
}
});
VBox layout = new VBox(10);
layout.getChildren().addAll(status, progress, pauseButton, textContainer);
layout.setStyle("-fx-background-color: cornsilk; -fx-padding: 10;");
primaryStage.setScene(new Scene(layout, 300, 700));
primaryStage.show();
taskThread.start();
}
public static void main(String[] args) { launch(args); }
}
class LoadTextTask extends Task<Void> {
private final String[] lines;
private final Pane container;
private final IntegerProperty idx = new SimpleIntegerProperty(0);
FutureTask<String> futureTask;
LoadTextTask(final String[] lines, final Pane container) {
this.lines = lines;
this.container = container;
}
#Override protected Void call() throws Exception {
try {
updateProgress(0, lines.length);
while (idx.get() < lines.length) {
final Label nextLabel = new Label();
final int curIdx = idx.get();
updateMessage("Reading Line: " + curIdx);
String nextText = lines[curIdx];
if ("MISSING".equals(nextText)) {
updateMessage("Prompting for missing text for line: " + curIdx);
futureTask = new FutureTask(
new MissingTextPrompt(
container.getScene().getWindow()
)
);
Platform.runLater(futureTask);
nextText = futureTask.get();
nextLabel.setStyle("-fx-background-color: palegreen;");
}
nextLabel.setText(nextText);
Platform.runLater(
new AddNodeLater(
container,
curIdx,
nextLabel
)
);
idx.set(curIdx + 1);
updateProgress(curIdx + 1, lines.length);
Thread.sleep(200);
}
updateMessage("Loading Text Completed: " + idx.get() + " lines loaded");
} catch (Throwable t) {
t.printStackTrace();
}
return null;
}
class MissingTextPrompt implements Callable<String> {
final Window owner;
public Button pauseButton = new Button("Pause");
MissingTextPrompt(Window owner) {
this.owner = owner;
}
#Override public String call() throws Exception {
final Stage dialog = new Stage();
dialog.setTitle("Enter Missin Text");
dialog.initOwner(owner);
dialog.initStyle(StageStyle.UTILITY);
dialog.initModality(Modality.WINDOW_MODAL);
final TextField textField = new TextField();
final Button submitButton = new Button("Submit");
submitButton.setDefaultButton(true);
submitButton.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent t) {
dialog.close();
}
});
final VBox layout = new VBox(10);
layout.setAlignment(Pos.CENTER_RIGHT);
layout.setStyle("-fx-background-color: azure; -fx-padding: 10;");
layout.getChildren().setAll(textField, submitButton);
dialog.setScene(new Scene(layout));
//dialog.showAndWait();
return textField.getText();
}
}
class AddNodeLater implements Runnable {
final Pane container;
final Node node;
final int idx;
public AddNodeLater(final Pane container, final int idx, final Node node) {
this.container = container;
this.node = node;
this.idx = idx;
}
#Override public void run() {
container.getChildren().add(idx, node);
}
}
}

Related

Create Nodes within Loop

Note: this is an updatet version of the initial question.
Whats now beeing asked is how I can get access to the values of a certain row for calculations purposes. For example how can I calculate the difference betweeen values of the expensesColumn and the earningsColumn? (Because there was to much code within my questions, I deleted most of the imports)
package application;
import javafx.application.Application;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {Table.create(primaryStage);}
catch(Exception e) {e.printStackTrace();}
}
public static void main(String[] args) {
launch(args);
}
}
package application;
public class UserJava {
private String member;
private double expenses;
private double earnings;
//Getter und Setter
public String getMember() {
return member;
}
public void setMember(String member) {
this.member = member;
}
public double getExpenses() {
return expenses;
}
public void setExpenses(double expenses) {
this.expenses = expenses;
}
public double getEarnings() {
return earnings;
}
public void setEarnings(double earnings) {
this.earnings = earnings;
}
}
package application;
import javafx.stage.Stage;
public class Table {
static TableView<UserJava> table;
public static void create (Stage primaryStage){
try {
GridPane primarygridpane = new GridPane();
HBox hboxTable = new HBox(10);
//Definition der Tabelle
TableColumn<UserJava, String> userColumn = new TableColumn<>("Name");
userColumn.setCellValueFactory(new PropertyValueFactory<>("member"));
userColumn.setMinWidth(200);
TableColumn<UserJava, Double> expensesColumn = new TableColumn<>("Ausgaben");
expensesColumn.setCellValueFactory(new PropertyValueFactory<>("expenses"));
expensesColumn.setMinWidth(100);
TableColumn<UserJava, Double> earningsColumn = new TableColumn<>("Pfand");
earningsColumn.setCellValueFactory(new PropertyValueFactory<>("earnings"));
earningsColumn.setMinWidth(100);
table = new TableView<>();
table.getColumns().addAll(userColumn, expensesColumn, earningsColumn);
TextField tfMember = new TextField();
tfMember.setMinWidth(200);
tfMember.setPromptText("Name");
TextField tfExpenses = new TextField();
tfExpenses.setMinWidth(100);
tfExpenses.setPromptText("Ausgaben");
TextField tfEarnings = new TextField();
tfEarnings.setMinWidth(100);
tfEarnings.setPromptText("Pfand");
Button btnAdd = new Button("Hinzufügen");
Button btnDelete = new Button("Löschen");
hboxTable.getChildren().addAll(tfMember, tfExpenses, tfEarnings, btnAdd, btnDelete);
table.setEditable(true);
userColumn.setCellFactory(TextFieldTableCell.forTableColumn());
// table.setItems(getUser());
//Sonstiges
Scene scene = new Scene(primarygridpane,725,400);
Text titel = new Text("Application");
titel.setFont(Font.font("Arial", FontWeight.BOLD, 28));
primarygridpane.add(titel, 0, 0, 2, 1);
primarygridpane.add(table, 0, 2);
primarygridpane.add(hboxTable, 0, 3);
// scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
//Funktionen
btnAdd.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent e) {
try {
UserJava user = new UserJava();
user.setMember(tfMember.getText());
user.setExpenses(Double.parseDouble(tfExpenses.getText()));
user.setEarnings(Double.parseDouble(tfEarnings.getText()));
table.getItems().add(user);
tfMember.clear();
tfExpenses.clear();
tfEarnings.clear();
System.out.println(table.getItems());
}
catch (NumberFormatException Ausnahme) {}
}
});
btnDelete.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent e) {
try {
ObservableList<UserJava> userSelected, userAll;
userAll = table.getItems();
userSelected = table.getSelectionModel().getSelectedItems();
userSelected.forEach(userAll::remove);
System.out.println();
}
catch (java.util.NoSuchElementException Ausnahme) {}
}
});
}
catch (Exception e) {e.printStackTrace();}
}
public ObservableList<UserJava> getUser(){
ObservableList<UserJava> user = FXCollections.observableArrayList();
user.add(new UserJava());
return user;
}
public void changeCell(CellEditEvent<?, ?> ediditedCell) {
UserJava personSelected = table.getSelectionModel().getSelectedItem();
personSelected.setMember(ediditedCell.getNewValue().toString());
}
}

JavaFX creating series for linechart: null

I am creating a new window controller in which I process data to be put into a linechart.
Though in the end the new window shows an empty LineChart. When I debug the line in which the series is put into the Linechart, the IDE states "series[null]".
So what am I missing?
Class of the new window:
public class ChartWindow {
Map<Job, List<LoadTestResultStatus>> lTRSMapOfJobs;
final LineChart lineChartMain;
Job originJob;
XYChart.Series series;
boolean lTRSfilled=false;
ObjectHub objectHub;
public ChartWindow(Job job, ObjectHub objectHub) {
this.objectHub = objectHub;
series = new XYChart.Series();
final NumberAxis xAxis = new NumberAxis();
final NumberAxis yAxis = new NumberAxis();
xAxis.setLabel("Time");
yAxis.setLabel("Time");
lineChartMain = new LineChart<Number, Number>(xAxis, yAxis);
lTRSMapOfJobs = new HashMap<>();
originJob = job;
lTRSMapOfJobs.put(job, objectHub.getDbManagement().getLTRSListOfJobFromDB(job));
fillLineChart();
}
public void fillLineChart() {
Platform.runLater(new Runnable() {
#Override
public void run() {
objectHub.getGuiReporter().statusStart(0);
objectHub.getGuiReporter().progressbarAddAmountOfStep(lTRSMapOfJobs.get(originJob).size());
}
});
for (LoadTestResultStatus l : lTRSMapOfJobs.get(originJob)) {
objectHub.getExecutor().submit(new Runnable() {
#Override
public void run() {
XYChart.Data xyChart = new XYChart.Data(l.getTs(), l.getLt());
try {
addToSeries(xyChart);
objectHub.getGuiReporter().progressbarAddStep();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
//TODO heavy CPU load:(
while(!lTRSfilled){
if(ObjectHub.getGuiReporter().progressBarDifference()==0){
lTRSfilled = true;
}
}
lineChartMain.getData().addAll(series);
}
void addToSeries(XYChart.Data xyChart) {
synchronized (this) {
series.getData().add(xyChart);
}
}
public Map<Job, List<LoadTestResultStatus>> getlTRSMapOfJobs() {
return lTRSMapOfJobs;
}
public void setlTRSMapOfJobs(Map<Job, List<LoadTestResultStatus>> lTRSMapOfJobs) {
this.lTRSMapOfJobs = lTRSMapOfJobs;
}
public LineChart getLineChartMain() {
return lineChartMain;
}
}
MainController method who processes the new window:
public void showLineChartForJob() {
progressBarLabel.setText("Preparing Linechart calculation...");
ChartWindow object to request executorservices
Thread createChartWindow = new Thread(new Runnable() {
#Override
public void run() {
int jobId = Integer.parseInt(visualizeTabIdInputTextField.getText());
Job lineChartJob = new Job(objectHub);
for (Job j : objectHub.getLtResultManagement().getjobSet()) {
if (j.getNumber() == jobId) {
lineChartJob = j;
break;
}
}
chartWindowList.add(new ChartWindow(lineChartJob, objectHub));
Platform.runLater(new Runnable() {
#Override
public void run() {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/fxml/ChartWindow.fxml"));
fxmlLoader.setController(chartWindowList.get(0));
StackPane secondaryLayout = new StackPane();
try {
secondaryLayout.getChildren().setAll(Collections.singleton(fxmlLoader.load()));
} catch (IOException e) {
e.printStackTrace();
}
Scene secondScene = new Scene(secondaryLayout, 1200, 1600);
Stage newWindow = new Stage();
newWindow.setTitle("Second Stage");
newWindow.setScene(secondScene);
newWindow.setX(50);
newWindow.setY(50);
newWindow.show();
}
});
}
});
createChartWindow.setName("createChartWindowThread");
createChartWindow.start();
}
Capture from debug taken at the last line of the First Controller:
Regards
Ok, case closed:
Failure was to not adress the scene to the linechart:
Scene secondScene = new Scene(secondaryLayout, 1200, 1600);
Fixed by obtaining the chart from the controller:
Scene secondScene = new Scene(chartWindowList.get(0).lineChartMain, 1200, 1600);

JavaFX TableView custom header

i am customizing JavaFX TableView's header.
therefore i add a Graphic to the Label. By clicking the Label of the header i toggle my custom header(two lined). all this is working fine.
The header gets automatically resized so the custom headerfits in.
BUT, when i hide my custom headerthe headerstays large.
What am i missing so the headershrinks again?
i created a MCVE to demonstrate my problem:
public class TableViewHeaderMCVE extends Application {
private final TableView<Person> table = new TableView<>();
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
final VBox root = new VBox();
Scene scene = new Scene(root);
stage.setWidth(218);
stage.setHeight(216);
TableColumn colName = new TableColumn("name");
colName.setMinWidth(100);
colName.setSortable(false);
TableColumn colProfession = new TableColumn("profession");
colProfession.setMinWidth(100);
colProfession.setSortable(false);
table.getColumns().addAll(colName, colProfession);
root.getChildren().addAll(table);
stage.setScene(scene);
stage.show();
// apply this after show!
TableViewHeader.installMod(table);
}
public static class TableViewHeader {
public static void installMod(TableView table) {
for (Node n : table.lookupAll(".column-header > .label")) {
if (n instanceof Label) {
new CustomHeaderLabel((Label) n);
}
}
}
}
public static class CustomHeaderLabel extends BorderPane {
protected Label customNode = null;
BooleanProperty expanded = new SimpleBooleanProperty(this, "expanded", false);
public CustomHeaderLabel(final Label parent) {
Label label = new Label(parent.getText());
// custom MenuButton
Button btn = new Button();
btn.setGraphic(new Label("\u2261"));
btn.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent ae) {
System.out.println("Hello World");
}
});
TextField filterTextField = new TextField();
filterTextField.promptTextProperty().set("type here to filter");
setCenter(label);
setRight(btn);
setBottom(filterTextField);
EventHandler<MouseEvent> toggleHeader = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent me) {
expanded.set(!expanded.get());
}
};
parent.setOnMouseClicked(toggleHeader);
expanded.addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> obs, Boolean oldValue, Boolean value) {
showCustomHeader(value);
}
});
label.textProperty().bind(parent.textProperty());
parent.setGraphic(this);
customNode = parent;
showCustomHeader(expanded.get());
}
protected void showCustomHeader(Boolean value) {
if (value) {
customNode.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
} else {
customNode.setContentDisplay(ContentDisplay.TEXT_ONLY);
}
}
}
public static class Person {
private final SimpleStringProperty name;
private final SimpleStringProperty profession;
private Person(String name, String profession) {
this.name = new SimpleStringProperty(name);
this.profession = new SimpleStringProperty(profession);
}
public String getName() {
return name.get();
}
public String getProfession() {
return profession.get();
}
}
}
thanks to #James_D for his reply.
after his reply i tested the code on another computer
works on:
JDK 1.8.0_161 on Windows 10
JDK 9.0.4 and JDK 10 on Mac OS X
fails on:
JDK 1.8.0_66-b18 on Windows 7

Closing or hiding a stage with animation?

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

Tab is not showing after inserting into new TabPane

I have implemented drag'n'drop functionality very similar to How to drag and drop tab nodes between tab panes, which works fine so far, but i also add a new Stage (SideStage below) if the tab is dragged outside of the main-window/stage. The problem is, the Tab is only showing after i either drag a new Tab to the TabPane there or if i resize the window. The main part of that drag'n'drop action is happening in the GuiPartFactory in the EventHandler which get's assigned to the Label of the Tab that gets dragged. I tried all sorts of size assigning, requestLayout, etc.
Sidestage class:
private TabPane tabPane;
public SideStage(double xPos, double yPos) {
tabPane = initTabArea();
VBox root = new VBox(0,GuiPartFactory.initMenuAndTitle(this),tabPane);
Scene scene = new Scene(root, 800, 600);
setScene(scene);
scene.setOnDragExited(new DnDExitAndEntryHandler());
scene.setOnDragEntered(new DnDExitAndEntryHandler());
setX(xPos);
setY(yPos);
;
initCloseWindowHandler();
}
private void initCloseWindowHandler() {
setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent event) {
System.out.println("closing this sidestage");
MainApp.sideStages.remove(SideStage.this);
}
});
}
private TabPane initTabArea() {
final TabPane tabPane = GuiPartFactory.createTabPane();
tabPane.addEventHandler(Tab.TAB_CLOSE_REQUEST_EVENT, new EventHandler<Event>() {
#Override
public void handle(Event event) {
System.out.println("tab got closed mon!");
if (tabPane.getTabs().isEmpty()) {
SideStage.this.close();
}
}
});
VBox.setVgrow(tabPane, Priority.ALWAYS);
return tabPane;
}
public void addTab(Tab tab) {
tabPane.getTabs().add(tab);
}
And the GuiPartFactory class:
public static ResourceBundle BUNDLE = ResourceBundle.getBundle("locales/Bundle", new Locale("en", "GB"));
public static TabPane createTabPane() {
final TabPane tabPane = new TabPane();
//This event gets fired when the cursor is holding a draggable object over this tabpane
tabPane.setOnDragOver(new EventHandler<DragEvent>() {
#Override
public void handle(DragEvent event) {
final Dragboard dragboard = event.getDragboard();
if (dragboard.hasString() && dragboard.getString().equals("tab") && ((Tab) MainApp.dndTemp).getTabPane() != tabPane) {
event.acceptTransferModes(TransferMode.MOVE);
event.consume();
}
}
});
//This event gets fired when the cursor is releasing a draggable object over this tabpane (this gets only called if it has been accepted in the previos dragover event!)
tabPane.setOnDragDropped(new EventHandler<DragEvent>() {
#Override
public void handle(DragEvent event) {
System.out.println("dropped");
Tab tab = (Tab) MainApp.dndTemp;
MainApp.dndHandled = true;
tab.getTabPane().getTabs().remove(tab);
tabPane.getTabs().add(tab);
tabPane.getSelectionModel().select(tab);
event.setDropCompleted(true);
event.consume();
}
});
return tabPane;
}
public static Tab createTab(String text) {
final Tab tab = new Tab();
final Label label = new Label("Tab" + text);
tab.setGraphic(label);
StackPane pane = new StackPane();
//need to set a real size here
pane.setPrefSize(500, 500);
tab.setContent(pane);
tab.getContent().setOnDragOver(new EventHandler<DragEvent>() {
#Override
public void handle(DragEvent event) {
final Dragboard dragboard = event.getDragboard();
if (dragboard.hasString() && dragboard.getString().equals("tab") && ((Tab) MainApp.dndTemp).getTabPane() != tab.getTabPane()) {
event.acceptTransferModes(TransferMode.MOVE);
event.consume();
}
}
});
tab.getContent().setOnDragDropped(new EventHandler<DragEvent>() {
#Override
public void handle(DragEvent event) {
System.out.println("dropped");
Tab transferTab = (Tab) MainApp.dndTemp;
MainApp.dndHandled = true;
transferTab.getTabPane().getTabs().remove(transferTab);
tab.getTabPane().getTabs().add(transferTab);
tab.getTabPane().getSelectionModel().select(transferTab);
event.setDropCompleted(true);
event.consume();
}
});
label.setOnDragDetected(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
Dragboard dragboard = label.startDragAndDrop(TransferMode.MOVE);
ClipboardContent clipboardContent = new ClipboardContent();
clipboardContent.putString("tab");
MainApp.dndTemp = tab;
MainApp.dndHandled = false;
dragboard.setContent(clipboardContent);
dragboard.setDragView(new Image("img/dragcursor.png"));
event.consume();
}
});
label.setOnDragDone(new EventHandler<DragEvent>() {
#Override
public void handle(DragEvent event) {
//our dragndrop failed
if (!MainApp.dndHandled) {
//lets see if it failed because we dropped outside of our java-windows
if (!MainApp.dndInside) {
if (!MainApp.dndTemp.equals(tab)) {
System.out.println("something is wrong here");
}
System.out.println("gotta make a new window!");
SideStage sideStage = new SideStage(event.getScreenX(), event.getScreenY());
MainApp.sideStages.add(sideStage);
//just a check to make sure we don't access a null variable
if (tab.getTabPane() != null) {
tab.getTabPane().getTabs().remove(tab);
}
sideStage.addTab(tab);
sideStage.sizeToScene();
tab.getTabPane().getSelectionModel().select(tab);
System.out.println("width: " + ((StackPane) tab.getContent()).getWidth());
System.out.println("height: " + ((StackPane) tab.getContent()).getHeight());
System.out.println("width: " + tab.getTabPane().getWidth());
System.out.println("height: " + tab.getTabPane().getHeight());
sideStage.show();
}
}
}
});
return tab;
}
public static Tab createTabRandomColor(String text) {
Random rng = new Random();
Tab tab = GuiPartFactory.createTab(text);
StackPane pane = (StackPane) tab.getContent();
int red = rng.nextInt(256);
int green = rng.nextInt(256);
int blue = rng.nextInt(256);
String style = String.format("-fx-background-color: rgb(%d, %d, %d);", red, green, blue);
pane.setStyle(style);
Label label = new Label("This is tab " + text);
label.setStyle(String.format("-fx-text-fill: rgb(%d, %d, %d);", 256 - red, 256 - green, 256 - blue));
pane.getChildren().add(label);
return tab;
}
public static MenuBar initMenuAndTitle(Stage stage) {
//setting up a window title
stage.setTitle(BUNDLE.getString("title.name"));
//adding the menubar
MenuBar menuBar = new MenuBar();
//adding the base menu entry
Menu menuStart = new Menu(BUNDLE.getString("menu.start"));
Menu menuView = new Menu(BUNDLE.getString("menu.view"));
Menu menuHelp = new Menu(BUNDLE.getString("menu.help"));
menuBar.getMenus().addAll(menuStart, menuView, menuHelp);
//adding the menuitems inside the menus
MenuItem aboutItem = new MenuItem(BUNDLE.getString("menu.about"));
aboutItem.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Dialogs popup = Dialogs.create();
popup.title(BUNDLE.getString("menu.about.title"));
popup.message(BUNDLE.getString("menu.about.message"));
popup.showInformation();
}
});
menuHelp.getItems().add(aboutItem);
MenuItem exitItem = new MenuItem(BUNDLE.getString("menu.exit"));
exitItem.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Dialogs popup = Dialogs.create();
popup.title(BUNDLE.getString("menu.exit.title"));
popup.message(BUNDLE.getString("menu.exit.message"));
popup.actions(new Action[]{YES, NO});
Action response = popup.showConfirm();
if(response.equals(YES)) {
System.exit(0);
}
}
});
menuStart.getItems().add(exitItem);
return menuBar;
}
And finally the MainApp class:
//for handling tag drag'n'drop outside of java windows
public static Object dndTemp = null;
public static boolean dndHandled = true;
public static boolean dndInside = true;
public static Set<SideStage> sideStages = new HashSet<>();
//holding the tabs (doe)
private TabPane tabPane;
#Override
public void start(Stage stage) {
tabPane = initTabs();
VBox root = new VBox(0, GuiPartFactory.initMenuAndTitle(stage), tabPane);
Scene scene = new Scene(root, 800, 600);
stage.setScene(scene);
stage.show();
scene.setOnDragExited(new DnDExitAndEntryHandler());
scene.setOnDragEntered(new DnDExitAndEntryHandler());
}
private TabPane initTabs() {
TabPane tabPane = GuiPartFactory.createTabPane();
Tab bedraggin = GuiPartFactory.createTab("be draggin");
Tab beraggin = GuiPartFactory.createTab("be raggin");
tabPane.getTabs().add(bedraggin);
tabPane.getTabs().add(beraggin);
for (int i = 0; i < 3; i++) {
Tab tab = GuiPartFactory.createTabRandomColor("" + i);
tabPane.getTabs().add(tab);
}
VBox.setVgrow(tabPane, Priority.ALWAYS);
return tabPane;
}
/**
* 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 boolean removeSideStage(SideStage sideStage) {
return sideStages.remove(sideStage);
}
public void addTab(Tab tab) {
tabPane.getTabs().add(tab);
}
public void removeTab(Tab tab) {
tabPane.getTabs().remove(tab);
}
edit: A temporary workaround is to put the actual adding of the tab into the new TabPane into a runnable. But i think this is a rather bad solution:
Platform.runLater(new Runnable() {
#Override
public void run() {
sideStage.addTab(tab);
tab.getTabPane().getSelectionModel().select(tab);
}
});

Resources