Placing HBox in BorderPane throws Exception in start method, JavaFX - javafx

I am trying to make a layout consisting of a TreeView List and a couple of textfields, buttons at the bottom. I figured i'd use a BorderPane to hold my layout in place. But i am getting an Exception in Application start method and it also tells me Children: duplicate children added: parent = BorderPane#71e344e8
Do you guys have an idea of whats going on?
public class Main extends Application {
Stage window;
TextField nameInput, quantityInput;
TreeView<String> tree;
public static void main(String[] args) {
launch(args);
}
public void start (Stage primaryStage) throws Exception{
window = primaryStage;
window.setTitle("GrocerieList");
// tree view
TreeItem<String> root, food, drink;
root = new TreeItem<>();
root.setExpanded(true);
// food
food = makeBranch("Food",root);
makeBranch("Banana", food);
makeBranch("Coconut", food);
makeBranch("Eggs", food);
// drink
drink = makeBranch("Drinks",root);
makeBranch("Water", drink);
makeBranch("Fanta", drink);
makeBranch("Beer", drink);
// tree
tree = new TreeView<>(root);
tree.setShowRoot(false);
// bottom input fields
nameInput = new TextField();
nameInput.setPromptText("Productname");
nameInput.setMinWidth(100);
quantityInput = new TextField();
quantityInput.setPromptText("Quantity");
quantityInput.setMinWidth(100);
// buttons
Button addbutton = new Button("Add");
// Layout
// HBOX
HBox hBox = new HBox();
hBox.setPadding(new Insets(10));
hBox.setSpacing(10);
hBox.getChildren().addAll(nameInput, quantityInput, addbutton);
// BorderPane
BorderPane borderPane = new BorderPane();
borderPane.getChildren().addAll(tree, hBox);
borderPane.setCenter(tree);
borderPane.setBottom(hBox);
Scene scene = new Scene(borderPane, 520, 620);
window.setScene(scene);
window.show();
}
public TreeItem<String> makeBranch(String title, TreeItem<String> parent){
TreeItem<String> item = new TreeItem<>(title);
item.setExpanded(true);
parent.getChildren().add(item);
return item;
}
Complete error:
Exception in Application start method
java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:464)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:363)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1051)
Caused by: java.lang.RuntimeException: Exception in Application start method
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:900)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
at java.base/java.lang.Thread.run(Thread.java:830)
Caused by: java.lang.IllegalArgumentException: Children: duplicate children added: parent = BorderPane#71e344e8
at javafx.graphics/javafx.scene.Parent$3.onProposedChange(Parent.java:560)
at javafx.base/com.sun.javafx.collections.VetoableListDecorator.add(VetoableListDecorator.java:206)
at javafx.graphics/javafx.scene.layout.BorderPane$BorderPositionProperty.invalidated(BorderPane.java:692)
at javafx.base/javafx.beans.property.ObjectPropertyBase.markInvalid(ObjectPropertyBase.java:112)
at javafx.base/javafx.beans.property.ObjectPropertyBase.set(ObjectPropertyBase.java:147)
at javafx.graphics/javafx.scene.layout.BorderPane.setCenter(BorderPane.java:268)
at sample.Main.start(Main.java:70)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
Exception running application sample.Main

Your problem is here:
BorderPane borderPane = new BorderPane();
borderPane.getChildren().addAll(tree, hBox);
borderPane.setCenter(tree);
borderPane.setBottom(hBox);
The calls to setCenter and setBottom add those nodes to the children list. Since you've manually added the two nodes to the children list, those method calls lead to adding the same node to the same parent twice—that's not allowed. When it comes to layouts that provide special properties for positioning, such as BorderPane, you want to avoid interacting with the children list directly. Change your code to:
BorderPane borderPane = new BorderPane();
borderPane.setCenter(tree);
borderPane.setBottom(hBox);

Related

JavaFx Call another panel and transmits values

My program is structured package and control on the interface as follows
**+ Browser : BrowserController.class**
-#FXML
private SplitPane spHTMLParser;
#FXML
private TextField txtURL;
#FXML
private Button btnSearch;
#FXML
private WebView browser;
**+ Browser/Console : ConsoleController.class**
#FXML
private Label lblURL;
In the browser page when the user clicks the btnSearch,I will show webview site with user input url. When the process is complete I want to show the Console.fxml in Browser.fxml with SplitPane and When the console is displayed, I'd label can get value url . Please help me!
#FXML
void btnSearch(ActionEvent event) {
String url = txtURL.getText().trim();
if (!url.isEmpty()) {
WebEngine webEngine = browser.getEngine();
progressBar.progressProperty().bind(webEngine.getLoadWorker().progressProperty());
webEngine.load(url);
webEngine.getLoadWorker().stateProperty().addListener((ObservableValue<? extends Worker.State> observable, Worker.State oldValue, Worker.State newValue) -> {
switch (newValue) {
case SUCCEEDED:
if (count++ != 0) {
btnNext.setDisable(false);
}
btnBack.setDisable(false);
progressBar.setVisible(false);
{
try {
FXMLLoader fxmlLoader = new FXMLLoader();
Pane pnConsole = fxmlLoader.load(getClass().getResource("console/Console.fxml").openStream());
spHTMLParser.getItems().add(pnConsole);
spHTMLParser.setDividerPositions(0.5);
} catch (IOException ex) {
Logger.getLogger(BrowserController.class.getName()).log(Level.SEVERE, null, ex);
}
}
break;
}
});
}
}
Load events url successful work exactly but I got an error when trying to call the other pane via fxml
Its error messages with commands
Pane pnConsole = fxmlLoader.load(getClass().getResource("console/Console.fxml").openStream());
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at publishers.controllers.resources.browser.BrowserController.lambda$webView$4(BrowserController.java:144)
at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:182)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.ReadOnlyObjectPropertyBase.fireValueChangedEvent(ReadOnlyObjectPropertyBase.java:74)
at javafx.beans.property.ReadOnlyObjectWrapper.fireValueChangedEvent(ReadOnlyObjectWrapper.java:102)
at javafx.beans.property.ObjectPropertyBase.markInvalid(ObjectPropertyBase.java:112)
at javafx.beans.property.ObjectPropertyBase.set(ObjectPropertyBase.java:146)
at javafx.scene.web.WebEngine$LoadWorker.updateState(WebEngine.java:1260)
at javafx.scene.web.WebEngine$LoadWorker.dispatchLoadEvent(WebEngine.java:1371)
at javafx.scene.web.WebEngine$LoadWorker.access$1200(WebEngine.java:1253)
at javafx.scene.web.WebEngine$PageLoadListener.dispatchLoadEvent(WebEngine.java:1240)
at com.sun.webkit.WebPage.fireLoadEvent(WebPage.java:2400)
at com.sun.webkit.WebPage.fwkFireLoadEvent(WebPage.java:2244)
at com.sun.webkit.network.URLLoader.twkDidFinishLoading(Native Method)
at com.sun.webkit.network.URLLoader.notifyDidFinishLoading(URLLoader.java:838)
at com.sun.webkit.network.URLLoader.lambda$didFinishLoading$96(URLLoader.java:829)
at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
at java.lang.Thread.run(Thread.java:745)

Continue program execution after showAndWait javafx

Hello I have a procedure who load a stage like this :
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainApp.class.getResource(ConstantsUI.CHEMIN_VIEW+
ConstantsUI.ECRAN_CAISSE_FERMEE));
AnchorPane ecran = (AnchorPane) loader.load();
// Show the scene containing the root layout.
Scene scene = new Scene(ecran);
MainApp.getInstance().getPrimaryStage().setScene(scene);
genericController = loader.getController();
genericController.setStage(MainApp.getInstance().getPrimaryStage());
// on garde la fenêtre en premier plan
MainApp.getInstance().getPrimaryStage().setMaximized(true);
MainApp.getInstance().getPrimaryStage().show();
MainApp.getInstance().getPrimaryStage().showAndWait();
System.out.println("toto");
And I have an button with this code :
#FXML
public void clickButton() {
System.out.println("------here-----");
stage.close();
}
My problem is, that after I clicked on my button, the message "toto" is not visible. Why ?
Thanks.
Calling showAndWait is not allowed for the primary stage.
From the javadoc
Throws:
[...]
IllegalStateException - if this method is called on the primary stage.
You could instead use a onHidden event handler:
MainApp.getInstance().getPrimaryStage().setOnHidden(evt -> {
System.out.println("toto");
});
MainApp.getInstance().getPrimaryStage().show();
Alternatively if you want to run the code after the last window of the application has been closed (asumming you didn't use Platform.setExplicitExit(false)), you could override Application.stop():
#Override
public void stop() throws Exception {
System.out.println("toto");
}

How to close a new popup window from Controller in JavaFX

I have Controller.java for Scene.fxml and ControllerSettings.java for WindowSettings.fxml. In Controller.java I create a new popup window (no dialog) with following method:
#FXML
public void handleSubmenuSettings(ActionEvent event) throws IOException {
Stage stage;
Parent root;
ControllerSettings controller;
stage = new Stage();
FXMLLoader loader = new FXMLLoader(getClass().getResource("WindowSettings.fxml"));
root = (Parent) loader.load();
controller = (ControllerSettings) loader.getController();
stage.setScene(new Scene(root));
stage.setTitle("Settings");
stage.initModality(Modality.APPLICATION_MODAL);
stage.setResizable(false);
stage.initOwner(submenuSettings.getScene().getWindow());
stage.showAndWait();
stage.setOnCloseRequest(e -> {
e.consume();
controller.saveSettings();
stage.close();
});
}
I want to save the settings when closing the new popup window but that doesn't work with stage.setOnCloseRequest.
The showAndWait() method will block execution until the window has closed; i.e. subsequent statements will not be executed until after the window is closed. So you don't register the listener for the close request until after the window has been closed. Clearly, no request to close the window will occur after the window is closed, so your handler is never invoked.
It's not really clear why you are using a close request handler anyway. Presumably you simply want to call controller.saveSettings() after the window closes. Since you are using showAndWait() you can just do:
#FXML
public void handleSubmenuSettings(ActionEvent event) throws IOException {
Stage stage;
Parent root;
ControllerSettings controller;
stage = new Stage();
FXMLLoader loader = new FXMLLoader(getClass().getResource("WindowSettings.fxml"));
root = (Parent) loader.load();
controller = (ControllerSettings) loader.getController();
stage.setScene(new Scene(root));
stage.setTitle("Settings");
stage.initModality(Modality.APPLICATION_MODAL);
stage.setResizable(false);
stage.initOwner(submenuSettings.getScene().getWindow());
stage.showAndWait();
controller.saveSettings();
}

JavaFX + Scene Builder how switch scene

I'm working with JavaFx and Scenebuilder and want create a local app for myself called "Taskplanner" in eclipse.
I created a new Stage and set it with a Scene (see Main.java). But not sure how to set a new Scene in the old stage (see Controller.java). Didnt also not find out if it is possible pass the signInButtonClicked()-Methode the "Stage primaryStage" over Scene Builder
Can anybody help ?
Controller.java:
#FXML
Button btnSignIn;
#FXML
public void signInButtonClicked() throws Exception
{
//Here I want call the new Scene(SignInGUI.fxml) in my old Stage
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("../view/SignInGUI.fxml"));
}
Main.java:
#Override
public void start(Stage primaryStage) throws Exception
{
Parent root = FXMLLoader.load(getClass().getResource("../view/LoginGUI.fxml"));
primaryStage.setTitle("Taskplanner");
primaryStage.setScene(new Scene(root,500,500));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
You can get a reference to the Scene and Window from your button reference. From there, it's up to you to decide how to you want to show the new view.
Here's how you get those references:
Scene scene = btnSignIn.getScene();
Window window = scene.getWindow();
Stage stage = (Stage) window;
You can change the view by changing the root of your Scene:
FXMLLoader loader = ... // create and load() view
btnSignIn.getScene().setRoot(loader.getRoot());
Or you can change the entire Scene:
FXMLLoader loader = ... // create and load() view
Stage stage = (Stage) btnSignIn.getScene().getWindow();
Scene scene = new Scene(loader.getRoot());
stage.setScene(scene);

Opening a new scene in java FX

I have two FXML files and one Controller.
I have posted the code in which i have tried to create a second stage (and failed).
Error message is:
javafx.scene.layout.AnchorPane cannot be cast to javafx.fxml.FXMLLoader
How do I fix it?
#FXML private Scene trial_scene;
#FXML public Stage m;
#FXML public void click(Stage stage) throws IOException {
m = new Stage();
openWindow();
}
#FXML private void openWindow() throws IOException {
FXMLLoader root =FXMLLoader.load(
SampleController.class.getResource(
"settings.fxml"
)
);
m.initModality(Modality.WINDOW_MODAL);
m.setTitle("My modal window");
m.setScene(trial_scene);
m.show();
}
The static method FXMLLoader.load returns the root node (and so the objet hierarchy) defined in the .fxml file. In your case it seems to be an AnchorPane.
Your fist line should be
AnchorPane root = FXMLLoader.load(SampleController.class.getResource("settings.fxml"));
Use this object to construct your new scene, for example
Scene trial_scene = new Scene(root, 300, 300, Color.BLACK);
Then pass this scene to your new stage
m.setScene(trial_scene);

Resources