Adding a node to a new parent in javafx - java

I'm recently building a javafx program which will work as a school database. I've made a SceneManager class which handles all on screen transitions and other gui tasks at runtime. Now i'm intending to add a back button to every visible window so that the user can get back at the previous window anytime. For that I've added the following method to SceneManager :
public static void addBackButton(Pane from,Pane to){
Node n1 = to.getChildren().get(0);
to.getChildren().remove(n1);
BorderPane fp = new BorderPane();
fp.setLeft(createBackButton(from));
fp.setCenter(n1);
to.getChildren().add(0, fp);
}
public static Button createBackButton(Pane p){
Button bk = new Button("",new ImageView("icons/appbar.arrow.left2.png"));
bk.setOnAction((ActionEvent evt)->{
swapToNext(p);
});
return bk;
}
However the above is not working. Only the button is being shown without the node 0, which is however generally a heading label in my program. I'm unable to find any general solution to this problem, like the method will be valid for anytype of node in 0. Any ideas?

Edit: I removed my old answer, since it wasn't what you were looking for.
Edit 2: Inspiration in the form of headaches.
The red color is the pane.
After a nice long weekend, I realized we could just use an anchor pane.
AnchorPane ap = new AnchorPane(p1,back); //<--- order matters.
AnchorPane.setBottomAnchor(back, 0.0); //<--- 0.0 is the distance from that edge
AnchorPane.setLeftAnchor(back, 0.0);
AnchorPane.setLeftAnchor(p1, 0.0); //<--- we do this to 'bind' the entire pane
AnchorPane.setBottomAnchor(p1, 0.0); //<--- to the anchorpane
AnchorPane.setRightAnchor(p1, 0.0); //<--- this ensures that it will
AnchorPane.setTopAnchor(p1, 0.0); //<--- even show behind the button
p1 is the pane, back is the button itself, and the button contains the link
back to the previous pane.
Here you simply need to return the anchorpane from that addBackButton function. You'll end up with an Anchorpane that contains a button and the previous pane.
I'm going to get more caffeine; I hope I helped. :)

Related

JavaFX on ActionEvent dynamically add / remove Node

I build a simple JavaFX App and I wan't to create a circle in the center of an ellipse when the Mouse enters the ellipse.
This is some of the Code:
ellipse = new Ellipse(30,30,40,40);
ellipse.setFill(Color.TRANSPARENT);
ellipse.setStroke(Color.BLACK);
ellipse.setOnMouseEntered(event -> {
Circle circle = new Circle();
circle.setCenterX(30);
circle.setCenterY(30);
circle.setFill(Color.GREEN);
group.getChildren().add(circle);
group.getChildren().removeAll(ellipse);
System.out.println("Added Circle");
});
group = new Group();
group.getChildren().add(ellipse);
vBox = new VBox();
vBox.getChildren().add(group);
The Vbox is added to a Scene and the Scene is added to the PrimaryStage.
If I run the program and my Mouse enters the ellipse the ellipse will be removed but the circle will not be added.
Can anyone explain me why?
First of all this seems to be the wrong way of implementing an dynamic node Adding / removing thing. What would be the right way?
But I'm also interested in why can I remove a Node so easy but I can't added it so easy?
My mistake, the Circle has no radius...
If I add a radius to the circle everything works fine,

JavaFX - How do you add multiple elements to a StackPane?

I'm new to JavaFX. I'm trying to create a simple centred menu that contains text with buttons below.
I've created two elements, Text title and Button testButton. Then I created StackPane stackPane. I'm then trying to add the two elements to the stackPanes children and adding that to a new Scene. However, only the last element shows up.
How can I add multiple elements to the StackPane?
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("Test Title");
Text title = new Text("hey!");
StackPane.setAlignment(title, Pos.TOP_CENTER);
Button testButton = new Button("Testing");
StackPane.setAlignment(testButton, Pos.TOP_CENTER);
StackPane stackPane = new StackPane();
stackPane.setPrefSize(300, 300);
stackPane.setPadding(new Insets(25, 0, 0, 0));
stackPane.getChildren().add(title);
stackPane.getChildren().add(testButton);
Scene scene = new Scene(stackPane);
primaryStage.setScene(scene);
primaryStage.show();
}
I want to reference the official documentation here: https://docs.oracle.com/javase/8/javafx/api/javafx/scene/layout/StackPane.html, especially:
StackPane lays out its children in a back-to-front stack.
The z-order of the children is defined by the order of the children list with the 0th child being the bottom and last child on top. If a border and/or padding have been set, the children will be layed out within those insets.
Now, to answer your question: You do it as you did, but you probably want an offset as both the children are at the same position, hence the one later added is overlaying all the previous ones.
You can check that by changing e.g.
Text title = new Text("Adding a very, very, very, very, very, very long text here... now that vile button should not overlap me anymore!");
or setting the alignment differently.
If you don't want to bother with the optimal layout by manually positioning, it's probably better to use another Pane that does that for you, e.g. one of the direct known subclasses here: https://docs.oracle.com/javafx/2/api/javafx/scene/layout/Pane.html

Getting the absolute coordinates of a node in a BorderPane with some null regions

I have a set of custom made "buttons" for the menu screen of my game. It's basically a StackPane with a Rectangle and a Text node stacked. Basically this is similar to how my buttons are structured.
Pane button1 = new StackPane(new Rectangle(100, 50), new Text("Play!"));
Pane button2 = [....];
Then I insert buttons into a VBox and into my menu along with a header text:
VBox buttons = new VBox(button1, button2, button3...);
Pane menuScreen = new BorderPane(buttons, new Text("The Game"), null, null, null);
However, for my custom detection for mouse position compared to the buttons I need to know the buttons' positions...
int x = button1.getLayoutX(); //returns 0
int x = button1.getTranslateX(); //returns 0
int x = button1.localToScene(0, 0).getX(); //returns 0
int x = button1.localToScene(buttons.get(0).getBoundsInLocal()).getMinX(); //returns 0
int x = button1.localToScene(buttons.get(0).getBoundsInLocal()).getMaxX(); //returns the width of the entire scene
int x = buttons.get(0).getTranslateX(); //returns 0
int y = button1.localToScene(buttons.get(0).getBoundsInLocal()).getMinY();
The last case returns 234.0 if I have the VBox set with .setAlignment(Pos.CENTER) and 64.0 if I don't. But for .getMinX() it stays at 0.0 in either case. I believe it's related to the BorderPane's left/right/bot regions being set to null while the top region has the title text.
I cannot find any way of getting the x coordinate when the buttons are in a layout pane other than the Pane class itself. I tried StackPane as well. My suspicion is that there is no fixed coordinate and that properties are involved, but I only get confused from reading about it when I don't know what I'm looking for.
I have tried solutions from this quesion and this seems to be the same but as I mentioned I'm afraid my minX() doesn't have a set value since the VBox is the only thing filling the center row of my BorderPane.
Edit: StackPane seems to give the right values for .getMinX() when I use .setAlignment(Pos.CENTER), but I am not allowed to do that with the text, only with the VBox, so then the text gets stuck on top of the buttons.
My issue was cause by the VBox and my StackPanes taking up all the possible space, not just the area of the visible Rectangle. Problem was solved by calling setMaxWidth(100) on the StackPane which contained the Rectangle and the Text.
Also, the only problem seems to be that you have a zero x-coordinate. Maybe this is "real". Set a background on button1 to see where it is in the layout. – James_D

JavaFX Popup under Node

Resources and examples for this Popup widget are vague.
Suppose I have a random Node somewhere on the stage. How do I open a Popup exactly under it (e.g. like a dropdown menu, but with other nodes inside it).
I'm trying to avoid boilerplate code (i.e. fine-tuning the position myself).
Update 1:
Either Point2D point = node.localToScene(0.0, 0.0); does not work as I imagine it should, or I'm using it wrong.
Update 2:
See here a simple example, but lacking the functionality I'm needing
Let's say you have the node node
you can get its position by
Point2D point = node.localToScene(0.0, 0.0);
// now get point.getX() and point.getY() here
Considering the example that you have given (in Update 2):
I removed this bit:
popup.setX(300);
popup.setY(200);
and modified this code:
show.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
popup.show(primaryStage);
Point2D point = show.localToScene(0.0, 0.0);
popup.setX(primaryStage.getX() + point.getX());
popup.setY(primaryStage.getY() + point.getY() + 40);
// this 40 could be show.getPrefHeight() if height of button is set
}
});
Since Popup is a separate window, you need to set its position by adding the offset of the Stage.

When adding a second item to my stackpane, the first item loses its Event/MouseOn. Why? How can I fix? JavaFX

I have a stackpane. When I add a second item to my stack pane, both show up, but I can't click on my first item anymore. It becomes 'unclickable'.
what ever I defined in my .setonmouse does not work. It works for my second item. If I switch the order they are in the stack pane, the other one works, but not both.
is there a fix for this? This is what my program looks like:
I want my 'grid' centered ALWAYS. There are buttons to the left centered in a column, there will be buttons on the right later on, and there will be buttons/Text on top of the grid and buttom in the margins later on too.
I want everything to be clickable.
http://img688.imageshack.us/img688/6025/examplerg.png
StackPane orders items in Z-order: latter above the former. So, your second item gots all mouse clicks and first one (being covered by second) doesn't get anything.
For layout you've described you can use BorderPane:
public void start(Stage stage) throws Exception {
BorderPane root = new BorderPane();
root.setCenter(new Rectangle(100,100, Color.RED));
root.setLeft(new Rectangle(10,10, Color.BLUE));
root.setRight(new Rectangle(10,10, Color.CYAN));
stage.setScene(new Scene(root,300,300));
stage.show();
}
You can make any Pane "mouse transparent", so that it doesn't consume any click events, and lets them pass through to the stack under it.
Here's some example code... this example sets up 4 panes in a stack, with just the mainPane accepting clicks to begin with.
StackPane rootPane = new StackPane();
VBox mainPane = new VBox(80);
BorderPane helpOverlayPane = new BorderPane();
helpOverlayPane.setMouseTransparent(true);
Canvas fullScreenOverlayCanvas = new Canvas();
fullScreenOverlayCanvas.setMouseTransparent(true);
VBox debugPane = new VBox();
debugPane.setAlignment(Pos.BASELINE_RIGHT);
AnchorPane debugOverlay = new AnchorPane();
debugOverlay.setMouseTransparent(true);
debugOverlay.getChildren().add(debugPane);
AnchorPane.setBottomAnchor(debugPane, 80.0);
AnchorPane.setRightAnchor(debugPane, 20.0);
rootPane.getChildren().addAll(mainPane, fullScreenOverlayCanvas, debugOverlay, helpOverlayPane);
Now, when you want to use your canvas to draw on top, make sure you change mouse transparent to false for just that stack, and keep all panes on top of it mouse transparent.
fullScreenOverlayCanvas.setMouseTransparent(false);
debugOverlay.setMouseTransparent(true);
fullScreenOverlayCanvas.setVisible(true);
doSomethingWithCanvasThatNeedsMouseClicks();
P.S. I did some editing of the code I had, so it may not run as-is. Also, see discussion of making only parts of panes transparent here:
JavaFX Pass MouseEvents through Transparent Node to Children

Categories