How to get better ImageView resize quality? - javafx

Images scaled in JavaFX using setFitWidth()/setFitHeight() methods have significantly inferior quality compared to images prescaled in graphics editor, in my case Photoshop.
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("Image Resize Test");
StackPane root = new StackPane();
root.setStyle("-fx-background-color: gray;");
ImageView imageView = new ImageView("save.png");
//ImageView imageView = new ImageView("save_small.png");
imageView.setPreserveRatio(true);
imageView.setFitHeight(15);
root.getChildren().add(imageView);
primaryStage.setScene(new Scene(root, 600, 600));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Application screenshots:
.
Image on the left is scaled in JavaFX, and the image on the right is prescaled in Photoshop. The first image has white border clearly visible only on its right side, while the second image (resized in Photoshop) has faint border visible on all sides, which better represents the original image that has white border all around it.
I tried setting imageView.setSmooth(true) and SceneAntialiasing.BALANCED, but results are the same.
These are PNG images used in this example:
Scaled (15x15) PNG image (resized in Photoshop):
Original (500x509) PNG image:

Related

Frosted Glass Clipping in JavaFX

I'm trying to achieve this effect here but on a static background (without the scrolling). I'm getting this weird clip on my results though (without the frost effect). I think I know where the problem is in my code but I'm not sure how to solve it.
public class App extends Application {
private static final double BLUR_AMOUNT = 80;
private static final Effect frostEffect = new BoxBlur(BLUR_AMOUNT, BLUR_AMOUNT, 3);
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
ImageView background = new ImageView(bgImage);
StackPane centerBlurredPane = (StackPane) frozenCenterUI();
BorderPane centerContent = new BorderPane();
centerContent.setCenter(new Text("Center"));
centerContent.setTop(new Text("Top"));
centerContent.setLeft(new Text("Left"));
centerContent.setRight(new Text("Right"));
centerBlurredPane.getChildren.add(centerContent);
Scene scene = new Scene(new StackPane(background,centerBlurredPane),414, 849);
primaryStage.setScene(scene);
primaryStage.show();
}
private Node frozenCenterUI() {
Image frostImage = background.snapshot(new SnapshotParameters(), null);
ImageView frost = new ImageView(frostImage);
Rectangle filler = new Rectangle(24, 762, 366, 696);
filler.setArcHeight(50);
filler.setArcWidth(50);
filler.setFill(Color.AZURE);
Pane frostPane = new Pane(frost);
frostPane.setEffect(frostEffect);
StackPane frostView = new StackPane(filler, frostPane);
Rectangle clipShape = new Rectangle(24, 762, 366, 696);
frostView.setClip(clipShape);
return frostView;
}
}
This is what i'm getting, however. I want to apply frost on the white area here.
What should my clip shape be?
Here's my background image, backgroundImage
Edit: I found that if I change my clipShape to have the same dimensions as the scene, then I get the desired effect. However, the BorderPane I added to the frozen pane is not constrained to it, but actually stretches and fills the entire window.

Cannot set stage to transparent in Preloader

I am trying to create a simple splash screen. In fact I have a stackpane with an image as background. I do not want to show the default javafx decorations.
So I tried StageStyle.TRANSPARENT but it makes the whole thing transparent. On the other hand StageStyle.UNDECORATED show the image but with a white background. Here is the code in my start method.
public class SplashScreen extends Preloader {
private Stage stage;
#Override
public void start(Stage stage) throws Exception {
this.stage = stage;
StackPane root = (StackPane) FXMLLoader.load(getClass().getClassLoader().getResource("layouts/splash.fxml"));
Scene scene = new Scene(root, 690, 380,true, SceneAntialiasing.BALANCED);
scene.setFill(Color.TRANSPARENT);
stage.initStyle(StageStyle.TRANSPARENT);
stage.setScene(scene);
stage.show();
}
...
I am using java 11.0.8 and javafx 14
JavaFX 15 fixed this. Seems it was a bug.

Bi-coloring JavaFX TableCell Background?

I have a javafx.scene.control.TableView containing some javafx.scene.control.TableColumns containing some javafx.scene.control.TextFields. Some of the TextFields should get a bi-coloured background: diagonally divided, the upper left half one colour, the lower right half another colour. Like the cells for Ge, Sb, Po in https://de.wikipedia.org/wiki/Periodensystem#/media/Datei:Periodensystem_deutsch_-_neue_Farben.svg. Is this possible without a background image?
Edit: added some code. For simplicity’s sake, i omitted the surrounding table and use now a javafx.scene.text.Text instead of a javafx.scene.control.TextField. The basic setup that follows gives a uniform background to the StackPane which is a start.
public class DividedBackgroundDemo extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("Test: Diagonally divided colour background");
Text txt = new Text("Text");
txt.setFont(Font.font("Arial", FontWeight.BOLD, FontPosture.REGULAR, 50));
StackPane root = new StackPane();
root.getChildren().add(txt);
root.setStyle("-fx-background-color: blue;");
primaryStage.setScene(new Scene(root, 200, 200));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Later on, when i will use a 13x13 grid of Text, i will have to imbed each Text into it’s own StackPane or another (perhaps more appropriate) subclass of Region to be able to provide an individually coloured background for each Text. And some of those Texts (especially the one in this example) should have a bi-colour background, both colours divided by the line from left bottom to right upper corner.
The simple solution would be to provide a background image. It’s not too difficult to produce one. But then, i have to produce a new background image for every pair of colours. I would prefer a more flexible solution.
All property setters and CSS properties i have found provide a one-colour-background. But sometimes i require bi-colour.
The proposed LineGradient would be acceptable if everything else fails. I would prefer a clear border between both colours, not a gradient.
Ok, i found a solution, at least for the simplified problem. Thanks to #kleopatra. As a path, i used a javafx.scene.shape.Polygon and filled it with the appropriate colour. Using aStackPane`, it is important to watch the z coordinate. Background naturally bottom, filled polyline as first content in the pane, and text on top.
public class DividedBackgroundDemo extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle("Test: Diagonally divided colour background");
Text txt = new Text("Text");
txt.setFont(Font.font("Arial", FontWeight.BOLD, FontPosture.REGULAR, 50));
Polygon triangle = new Polygon();
triangle.getPoints().addAll(new Double[] { 0.0, 0.0, 200.0, 0.0, 0.0, 200.0 });
triangle.setFill(Color.YELLOW);
StackPane root = new StackPane();
root.getChildren().add(triangle);
root.getChildren().add(txt);
root.setStyle("-fx-background-color: blue;");
primaryStage.setScene(new Scene(root, 200, 200));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Showing a PNG file with transparent background using javafx

Am actually working on a splash Screen unsing javaFX, everythink works fine but I want to show a png image with a transparent background on the splash screen, but am unable to do it, can someone please tell me if it's possible to do it from JavaFX Scene Builder or not ?
I'm in a bit of a rush, but below is a quick example to show you how it can be done by setting the StageStyle to Transparent and the scene fill to the color "transparent".
#Override
public void start(Stage aStage) throws Exception {
Pane root = new Pane();
ImageView img = new ImageView();
img.setImage(new Image(getClass().getResource("pathToYourPngLocatedInYourResourcesFolder.png").toExternalForm()));
root.getChildren().add(img);
Scene scene = new Scene(root, 500, 500);
scene.setFill(Color.TRANSPARENT);
aStage.initStyle(StageStyle.TRANSPARENT);
aStage.setScene(scene);
aStage.show();
}
Let me know how it works out :)

Make a BorderPane region go over another

I've been trying for days and days now to get a BorderPane region go over another region...
The problem is as follow: My app is set in a BorderPane root, With:
A header in its TOP region
A menu in its LEFT region
The content, depending on the page, in it's CENTER
And an optional panel on its RIGHT region
That right region is the problem. It should appear/disappear when clicking on a "notification button" that is in the TOP region. So far so good. The thing is that the app doesn't use the RIGHT region, so I'm trying to make the RIGHT region that contains an AnchorPane go over the CENTER region. The normal state of the app is without the RIGHT region and I don't want to resize the whole app when opening the noitifications. Tried several things, such as:
When clicking the notification button, send the CENTER part toBack() and set the RIGHT width to the 300 wanted pixels
Sending the RIGHT region toFront()
Sending the whole BorderPane toFront()
None of them work, as they all either not show, or resize the center part which I don't want. I'd like the RIGHT to float above the CENTER region when the notification menu is showing.... Is there any way to do that? Or maybe another idea to trigger a container that would show above the CENTER part? Of course, I go design the panel in every CENTER pane and make it visible or not, but my app is about 15 different center windows so it would be really bad in terms of modifications...
I think you should not be trying to make the borderpane do this for you or you will end up with behavior you do not want like the center NOT resizing when the application is resized while the panel is visible.
Remember that JavaFX is really 3D. How about you try to wrap the BorderPane inside of an AnchorPane, GridPane or ScrollPane (whichever makes sense) instead of trying to get the right insert to do your thing. e.g. add an ScrollPane (your Slider) to the containing AnchorPane and bring that to the front and anchor it's top, right and bottom.
This should give you a right-aligned ScrollPane on top of your borderpane.
Then of course if you want it to be fancy with an animated slide you can try this out : https://gist.github.com/jewelsea/1437374
or this:
http://blog.physalix.com/javafx2-borderpane-which-slides-in-and-out-on-command/
Here is a very rough example to show the idea:
public class JavaFXApplication2 extends Application {
ScrollPane slider;
AnchorPane root;
#Override
public void start(Stage primaryStage) {
Button btn = new Button();
btn.setText("Slide in");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
root.getChildren().add(slider);
AnchorPane.setRightAnchor(slider, 0.);
AnchorPane.setTopAnchor(slider, 0.);
AnchorPane.setBottomAnchor(slider, 0.);
slider.toFront();
}
});
Label l = new Label();
l.setText("Test Label to Show inside content");
Label l2 = new Label();
l2.setText("Peek-a-Boo");
slider = new ScrollPane();
slider.setStyle("-fx-border-color: orangered;");
slider.setContent(l2);
root = new AnchorPane();
root.getChildren().add(btn);
root.getChildren().add(l);
AnchorPane.setRightAnchor(l, 0.);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}

Resources