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
Related
I am trying to create a TreeView where each TreeCell represents a statement in the program. By invoking setGraphics, I want to replace the default cell with a customized Node, like the following figure.
I am using a VBox as all the children are placed vertically. The Header and Footer are 2 tiny areas reserved for Drag-and-Drop operations. e.g. I can drag-and-drop a new statement before the current one by moving the cursor over its header.
I want to use Label for header and footer, and I want to limit their height to 2 pixels, so I have tried:
public VBox getTestContainer() {
VBox vbox = new VBox();
Label header = new Label();
header.setPrefHeight(2);
header.setPrefWidth(200);
... ... ...
vbox.getChildren().add(header, ..., footer);
}
public void start(Stage stage) throws Exception {
Group root = new Group();
root.getChildren().add(getTestBlock());
stage.setTitle("Test");
stage.setScene(new Scene(root, 400, 300));
stage.show();
}
To make sure that the VBox is not resized by other layout pane, I have simply put it in a Group.
The setPrefWidth works, it gives me a 200-pixel wide Label and VBox, but the setPrefHeight doesn't. As you can see the height of the header is much larger than 2 pixels.
My question is how to correctly set the height of Label?
Setting the prefHeight (or maxHeight) to a value smaller than the computed min height of the Label still results in the lable's minimum height being used as smallest possible height for the Label. This minimum height is based on the font size.
header.setFont(Font.font(2));
Would reduce the calculated minimum height.
Since it doesn't seem like you're trying to add any text to those nodes, just use Regions instead of Labels as first and last child of the VBox.
So, the situation is... I have a vbox inside a scrollpane. I am adding hbox's into the vbox and then calling vbox.setVvalue(1.0) after every insert.
However say, there are 5 hbox's, the scroller only makes it so that the last visible item is the 4th hbox - with one hbox below what is currently seen(needing to be scrolled down to be visible).
I've found a solution which is to bind the scrollpane's vvalue property to the vbox's heightproperty like so: scrollPane.vvalueProperty().bind(vbox.heightProperty()) which i assume changes the vvalue to the max every time the vbox height is changed (i.e when a new hbox is added).
However, i still would like to improve my knowledge and why the first (setting the vvalue of the scrollpane after every insert) is different from binding the properties. Thanks!
Setting the new vvalue happens before the layout pass caused by modifying the VBox, but the result applied before the layout pass. Since the formula for the y coordinate of the top that are shown in the viewport is
top = max(0, vvalue * (contentHeight - viewportHeight))
and during the layout pass the content's top left is kept in place, you see the bottom of the old content at the bottom of the viewport.
To fix this you could manually trigger a layout pass on the ScrollPane using
scrollPane.applyCss();
scrollPane.layout();
Example
#Override
public void start(Stage primaryStage) {
VBox content = new VBox();
ScrollPane scrollPane = new ScrollPane(content);
VBox.setVgrow(scrollPane, Priority.ALWAYS);
Button button = new Button("fill");
button.setOnAction(evt -> {
for (int i = 0; i < 20; i++) {
content.getChildren().add(new Text(Integer.toString(i)));
}
System.out.println("content size before layout: " + content.getHeight());
// manually layout scrollPane
scrollPane.applyCss();
scrollPane.layout();
System.out.println("content size after layout: " + content.getHeight());
scrollPane.setVvalue(1d);
});
Scene scene = new Scene(new VBox(button, scrollPane), 200, 200);
primaryStage.setScene(scene);
primaryStage.show();
}
I am having problems with positioning my images in my JavaFX program using setX and setY on the ImageView's for the images. I am not sure what is the problem? Appreciate any help given!
Here's my code:
Image rocket2 = new Image("img/Rocket.png");
ImageView iv1 = new ImageView(rocket2);
iv1.setX(60);
iv1.setY(44);
Image rocket1 = new Image("img/Rocket.png");
ImageView iv2 = new ImageView(rocket1);
iv2.setX(5);
iv2.setY(16);
Image background = new Image("img/space.png");
ImageView iv3 = new ImageView(background);
StackPane root = new StackPane();
root.getChildren().addAll(iv3, iv2, iv1);
Scene scene = new Scene(root, 300, 300);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.setResizable(false);
primaryStage.setTitle("Space stuff");
primaryStage.show();
I suspect that something goes wrong because I have set a background image.
img here on what's happening
Don't place your items in a StackPane if you want to explicitly define their layout positions (setX and setY). A StackPane is a managed layout pane. It will automatically set the location of items added to it (default is to center everything one on top of the other inside the StackPane).
Instead use a Pane or a Group, which are not managed layout panes and allow you to layout your content in the Pane however you wish.
To layout your content inside the Pane, you can use setLayoutX and setLayoutY rather than setX and setY, though I guess setX and setY should also work (I've never used them before on ImageView).
Pavlo, already created an answer while I was typing this (so this answer is a duplicate), but I'll leave this as it adds a bit more explanation.
Replacing StackPane with Pane should solve the problem.
If you however want for whatever reason to position a item in a StackPane you can use setTranslateX and setTranslateY. Theese methods set the x and y values AFTER the StackPane has done its layouting, so you will have a different starting position depending on the Alignment your StackPane uses for its children.
I want to loop through each object of a list. For each entry I want to create a GUI object that looks like this:
A checkbox on the left
An image in the center
(later) A label on the left
My problem is, that each label has a different length and it looks rather strange if not all pictures are on the same line (as seen vertically). Is there a possibility by either java or css to align the ImageVew in center of the HBox?
imageView.setLayoutX(filterBox.getWidth()/2); didn't do the trick unfortunatly. And no -fx-align: right; or -fx-float: right; seems to be existing.
I included what I have so far.
VBox filtersBox = new VBox();
HBox filterBox;
for(Filter filter : filters.getFilters()){
if(!filter.isComplex()){
filterBox = new HBox();
filterBox.getStyleClass().add("filter");
ImageView imageView = new ImageView();
[image view stuff]
final CheckBox cbox = new CheckBox(filter.getName().toString());
filterBox.getChildren().addAll(cbox, imageView);
filtersBox.getChildren().addAll(filterBox);
}
}
As far as I'm aware, this is impossible.
I see two ways you can achieve this layout, though:
Have all the checkboxes have the same (constant) preferred width. This way your image views should line up.
Use a GridPane, and add rows instead of HBoxes
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