JavaFX 3D Background image - javafx

I'm trying to add a background image to my JavaFX 3D program, but it just translates the ImageView instead of setting it as the background. What am I missing?
I create the ImageView, and then add it to a separate Group object in the start method. The choiceLayout is another Group object.
Image image = new Image(Program.class.getResourceAsStream("picture.jpg"));
ImageView view = new ImageView(image);
view.setPreserveRatio(true);
view.getTransforms().add(new Translate(-image.getWidth() / 2, -image.getHeight() / 2, 800));
Group bg = new Group();
bg.getChildren().add(choiceLayout);
bg.getChildren().add(view);
Scene choiceScene = new Scene(bg, 1024, 768, true);

Related

BackgroundImage Javafx Combobox

is there a way to set an Image (like setGraphic() for Button) for a ComboBox?
file = new File(IMG_DIR + "load.png");
BackgroundImage bg = new BackgroundImage(new Image(file.toURI().toString()),BackgroundRepeat.NO_REPEAT, BackgroundRepeat.NO_REPEAT, BackgroundPosition.CENTER,
BackgroundSize.DEFAULT);
comboBox.setBackground(new Background(bg));
That's what i tried, but it only results in a black background.
As comparison, what i do with my buttons:
File file = new File(IMG_DIR + "save.png");
ImageView imageView = new ImageView(new Image(file.toURI().toString()));
buttonSave.setGraphic(imageView);
what it currently looks like:
I want a load image on the ComboBox positioned like the images on the Buttons. Is that possible?
Thanks!

JavaFX - Get Coordinates of Node Relative to its Parent

I am making a simple graphical interface for saving previously generated images. All images come to me square but I want to allow for some cropping functionality (more precisely cutting off equal parts from the bottom and top of the image). I want to do this by allowing the user to drag a shaded region over the image which will tell the user that this region will be cropped out. See the below image for details. To enable this drag functionality I have added small triangles that I want the user to drag which in turn will move the shaded regions about. However the coordinates for the triangles are all weird and seem nonsensical. Therefor I was wondering what the best way is to get the coordinates of the triangles in relation to the ImageView (or their first common parent node) in terms of ImageView-side-lengths. So if the triangle is in the center its coordinates are [0.5, 0.5] for instance.
The Image view will be moving around inside the scene and will also be changing size so it is vital that I can get the coordinates relative to not only the ImageView but also to the size of the ImageView.
Here is also the surrounding hierarchy of nodes if that helps. The Polygons are the triangles and the regions are the rectangles.
Thanks for all forms of help!
Node.getBoundsInParent returns the bounds of a node in it's parent coordinates. E.g. polygon.getBoundsInParent() would return the bounds in the VBox.
If you need to "go up" one additional step, you can use parent.localToParent to do this. vBox.localToParent(boundsInVbox) returns the bounds in the coordinate system of the AnchorPane.
To get values relative to the size of the image, you simply need to divide by it's size.
The following example only allows you to move the cover regions to in one direction and does not check, if the regions intersect, but it should be sufficient to demonstrate the approach.
The interesting part is the event handler of the button. It restricts the viewport of the second image to the part of the first image that isn't covered.
private static void setSideAnchors(Node node) {
AnchorPane.setLeftAnchor(node, 0d);
AnchorPane.setRightAnchor(node, 0d);
}
#Override
public void start(Stage primaryStage) {
// create covering area
Region topRegion = new Region();
topRegion.setStyle("-fx-background-color: white;");
Polygon topArrow = new Polygon(0, 0, 20, 0, 10, 20);
topArrow.setFill(Color.WHITE);
VBox top = new VBox(topRegion, topArrow);
top.setAlignment(Pos.TOP_CENTER);
topArrow.setOnMouseClicked(evt -> {
topRegion.setPrefHeight(topRegion.getPrefHeight() + 10);
});
// create bottom covering area
Region bottomRegion = new Region();
bottomRegion.setStyle("-fx-background-color: white;");
Polygon bottomArrow = new Polygon(0, 20, 20, 20, 10, 0);
bottomArrow.setFill(Color.WHITE);
VBox bottom = new VBox(bottomArrow, bottomRegion);
bottom.setAlignment(Pos.BOTTOM_CENTER);
bottomArrow.setOnMouseClicked(evt -> {
bottomRegion.setPrefHeight(bottomRegion.getPrefHeight() + 10);
});
Image image = new Image("https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Mona_Lisa%2C_by_Leonardo_da_Vinci%2C_from_C2RMF_retouched.jpg/402px-Mona_Lisa%2C_by_Leonardo_da_Vinci%2C_from_C2RMF_retouched.jpg");
ImageView imageView = new ImageView(image);
setSideAnchors(top);
setSideAnchors(bottom);
setSideAnchors(imageView);
AnchorPane.setTopAnchor(top, 0d);
AnchorPane.setBottomAnchor(bottom, 0d);
AnchorPane.setTopAnchor(imageView, 0d);
AnchorPane.setBottomAnchor(imageView, 0d);
AnchorPane container = new AnchorPane(imageView, top, bottom);
ImageView imageViewRestricted = new ImageView(image);
Button button = new Button("restrict");
button.setOnAction(evt -> {
// determine bouns of Regions in AnchorPane
Bounds topBounds = top.localToParent(topRegion.getBoundsInParent());
Bounds bottomBounds = bottom.localToParent(bottomRegion.getBoundsInParent());
// set viewport accordingly
imageViewRestricted.setViewport(new Rectangle2D(
0,
topBounds.getMaxY(),
image.getWidth(),
bottomBounds.getMinY() - topBounds.getMaxY()));
});
HBox root = new HBox(container, button, imageViewRestricted);
root.setFillHeight(false);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}

Get Pane size without adding it to a scene (in JavaFX)?

If I create a Pane (with nodes inside it), how can I compute the width/height without rendering it on-screen?
I am trying to create a document (in memory) and send it to a printer. The problem is that I need to compute how many pages and to do that I need to get the dimensions of the document.
A quick example I'm experimenting with:
Label testLabel1 = new Label("TEST1");
Label testLabel2 = new Label("TEST no. 2");
GridPane testGl = new GridPane();
testGl.add( testLabel1, 1, 1 );
testGl.add( testLabel2, 2, 2 );
VBox testVBox = new VBox( testGl );
Pane testPane = new Pane( testVBox );
//I read that this might be required
testPane.applyCss();
testPane.layout();
//Also that a delay is needed for the fx tread to update testPane
// (but shouldn't this all be in the same thread since it is in the same function?
// It doesn't seem to help).
Platform.runLater( ()->{
System.out.println( ">>> "+ testPane.getBoundsInLocal().getWidth() );
});
All I ever output is >>> 0.0. Note that in the program I'm developing, I have multiple Panes inside a "container" Pane. Hence, the variable testPane.
Thank you.
You need to add the Pane to a Scene for the layouting to work. There is no need to display the Scene however and there is no need to keep the Pane in this scene:
Label testLabel1 = new Label("TEST1");
Label testLabel2 = new Label("TEST no. 2");
GridPane testGl = new GridPane();
testGl.add(testLabel1, 1, 1);
testGl.add(testLabel2, 2, 2);
VBox testVBox = new VBox(testGl);
Pane testPane = new Pane(testVBox);
// add testPane to some scene before layouting
Scene testScene = new Scene(testPane);
testPane.applyCss();
testPane.layout();
System.out.println(">>> " + testPane.getBoundsInLocal().getWidth());
// Pane could be removed from scene
Group replacement = new Group();
testScene.setRoot(replacement);
Note that if you want to remove the root from a Scene you have to replace it with a non-null node.

LineChart JavaFX -saving to png - How to control the size

I cannot figure out how to control the size of the LineChart saved to png. The chart looks great on the screen, in it's own window, but it gets scrunched vertically when saved. I've tried to figure out how to control the size, but to no avail. It must be a simple setting, but...
Any help would be appreciated.
With the following code, excluding the code that sets the data values:
LineChart<Number, Number> xyChart = new LineChart<>(xAxis, yAxis);
StackPane layout = new StackPane();
layout.setPadding(new Insets(10, 10, 10, 10));
xyChart.prefWidthProperty().bind(window.widthProperty());
xyChart.prefHeightProperty().bind(window.heightProperty());
layout.getChildren().add(xyChart);
VBox mainVBox = new VBox();
mainVBox.getChildren().addAll(menuHBox, layout);
Scene scene = new Scene(mainVBox, 800, 600);
window.setScene(scene);
xyChart.setAnimated(false);
WritableImage snapShot = scene.snapshot(null);
try {
ImageIO.write(SwingFXUtils.fromFXImage(snapShot, null), "png", new File("test3.png"));
} catch (IOException e) {
}
The chart as displayed on the screen is
window grab
whereas the png file that is written is
upload of the png file
Try saving the image after the window is shown, as layouts and sizes are computed on a required basis, and may not give the same values before.
Another solution would - of course - be to explicitly set the preferred size of the node.
xyChart.setPrefWidth(...);
xyChart.setPrefHeight(...);
The reason why bindings don't help is because the window itself doesn't have the computed size yet, as previously said.

How to set image to a scene background in JavaFX?

The title says it all, I guess.
How to set a .jpg (or any other supported image format) image to a Scene background?
I somewhat achieved this by using a HBox, an Image and an ImageView, like this:
String url = ...
HBox box= new HBox();
Image x = new Image(url);
ImageView iv = new ImageView(x);
box.getChildren().add(iv);
box.setVisible(true);
Then I add that box to the Scene first, and everything else afterwards.
I'm not complaining about that piece of code - it works for my purposes - but is there a proper way to set a background?
An ImagePattern can be used as fill of the Scene:
ImagePattern pattern = new ImagePattern(myImage);
scene.setFill(pattern);
Just call setBackground on the root node of the scene. For example:
Pane root = ... ; // probably some pane subclass...
String url = ... ;
Image img = new Image(url);
BackgroundImage bgImg = new BackgroundImage(img,
BackgroundRepeat.NO_REPEAT, BackgroundRepeat.NO_REPEAT,
BackgroundPosition.DEFAULT,
new BackgroundSize(BackgroundSize.AUTO, BackgroundSize.AUTO, false, false, true, false));
// put stuff in root as normal....
Scene scene = new Scene(root);
See the Javadocs for the parameters for the BackgroundImage constructor, etc.

Resources