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
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());
}
}
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);
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
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.
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);
}
});