How to align Labels with different Text sizes to Botttom? - javafx

I have two different Labels, one large one which displays a changing text and a smaller one which displays a % sign, and has to be smaller.
I have these two in a GridPane and aligned the left text to BOTTOM_RIGHT and aligned the right text BOTTOM_LEFT, so there is no gap in between:
How can I get the two texts to align so they look like the following image?
In hindsight, a TextFlow would have been a better solution, but I'm much too far into my project to change this now.

This depends on how you've built your Scene. If you're using FXML/Scene Builder, you'd set the valignment property for your GridPane row to BASELINE.
Here's a complete FXML that replicates your screenshots (without styling):
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.*?>
<GridPane xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/11.0.1">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0"/>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0"/>
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="-Infinity" valignment="BASELINE" vgrow="SOMETIMES"/>
</rowConstraints>
<children>
<Label style="-fx-font-size: 5.0em;" text="44"/>
<Label style="-fx-font-size: 3.0em;" text="\%" GridPane.columnIndex="1"/>
</children>
</GridPane>
If you're designing the Scene in Java, the end goal is the same: set the valignment of the row to BASELINE:
import javafx.application.Application;
import javafx.geometry.VPos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Region;
import javafx.scene.layout.RowConstraints;
import javafx.stage.Stage;
public class TextAlignSample extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
// Simple Interface
GridPane root = new GridPane();
RowConstraints constraints = new RowConstraints(
Region.USE_PREF_SIZE,
Region.USE_COMPUTED_SIZE,
Region.USE_COMPUTED_SIZE);
constraints.setValignment(VPos.BASELINE);
root.getRowConstraints().add(constraints);
// Add our Labels
root.add(new Label("44") {{
setStyle("-fx-font-size: 5.0em");
}}, 0, 0);
root.add(new Label("%") {{
setStyle("-fx-font-size: 3.0em");
}}, 1, 0);
// Show the stage
primaryStage.setScene(new Scene(root));
primaryStage.setTitle("TextAlignSample Sample");
primaryStage.show();
}
}
The Result:
Sorry for the odd color; something is wrong with my screen cap software

Related

JavaFx : Enable outer scrollview once the end of inner scrollview has been reached

I have a parent scrollpane which contains a webview as one of its children. When I scroll over the webview by having the mouse pointer on the webview area, it continues scrolling as expected till the end of the webview. However, is there a way where I can make the parent scrollpane scroll down, once the end of the child-webview is reached, while still the mouse pointer is on the webview-area ?
Sample Structure :
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.web.*?>
<ScrollPane prefHeight="455.0" prefWidth="602.0" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="wes.we.fx.view.ui.express.reports.generic.Demo">
<content>
<AnchorPane prefHeight="400.0" prefWidth="600.0">
<children>
<VBox layoutX="26.0">
<children>
<WebView prefHeight="316.0" prefWidth="530.0" />
</children>
</VBox>
</children>
</AnchorPane>
</content>
</ScrollPane>
Explanation of my solution: When using a WebView you can inject javascript which is what I used to pull values of the page to figure out when I was at the bottom. I am no JavaScript wiz so Im am not sure if there is a better solution here(I could not find one). I used the formula of screenTopPosition + screenTotalHeight to get the screenBottomPosition and compared that to the totalPageHeight if they are equal then you are at the bottom of the page this all worked as expected. This is where I feel it gets "Hacky" I couldn't figure out how to get the focus of the scrollbar from the scrollPane when at the bottom of the page. So my only other idea was to increment the scrollPane Vvalue by a fixed value when you were at the bottom of the webpage. The problem is the value you choose to increment it by may be different than the actual scrolling value incrementing I chose .1 once the Vvalue hits 1 it is at the bottom of the scrollPane
This is not exactly how I wanted to solve this problem hopefully someone can recommend a better solution that feels less "Hacky" and I would be glad to edit my answer if provided with guidance on how to figure out what the default incrementing is for the Vvalue
public class Main extends Application {
#Override
public void start(Stage stage) {
ScrollPane scrollPane = new ScrollPane();
scrollPane.setPrefSize(602, 455);
AnchorPane anchorPane = new AnchorPane();
anchorPane.setPrefSize(600, 400);
scrollPane.setContent(anchorPane);
VBox vBox = new VBox();
vBox.setPrefWidth(530);
vBox.setLayoutX(26);
anchorPane.getChildren().add(vBox);
WebView webView = new WebView();
webView.setPrefSize(530,316);
webView.getEngine().load("http://www.google.com");
webView.setOnScroll(event -> {
Integer screenTopPosition = (Integer) (webView.getEngine().executeScript("document.body.scrollTop"));
Integer screenTotalHeight = (Integer) webView.getEngine().executeScript("document.body.clientHeight");
Integer screenBottomPosition = screenTopPosition + screenTotalHeight;
Integer totalPageHeight = (Integer) webView.getEngine().executeScript("document.body.scrollHeight");
if(screenBottomPosition.equals(totalPageHeight)){
System.out.println("Bottom of Page Reached");
scrollPane.setVvalue(scrollPane.getVvalue()+.1);
}
});
vBox.getChildren().add(webView);
Label label = new Label("Content\nContent");
label.setFont(new Font(100));
vBox.getChildren().add(label);
stage.setScene(new Scene(scrollPane));
stage.show();
}
}

how i can take autosize for the second fxml inside main fxml

how i can load my second fxml in my first fxml
you most but for Main AnchorPane in each controller
this code inside fxml
<AnchorPane minHeight="-Infinity" minWidth="-Infinity" prefHeight="520" prefWidth="782.0" style="-fx-background-color: White; -fx-background-radius: 15px; -fx-border-radius: 12px;" AnchorPane.bottomAnchor="1.0" AnchorPane.leftAnchor="1.0" AnchorPane.rightAnchor="1.0" AnchorPane.topAnchor="1.0" xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Controller.CreateitemController">
then in main screen but this code for open the second screen inside main screen when click the button
#FXML
public void groupshow(ActionEvent event) throws IOException {
Parent root = FXMLLoader.load(getClass().getResource("/FX/creategroupshow.fxml"));
setting_page.getChildren().setAll(root);
}
enter image description here

JavaFX layout based on percentage of window size

I need to create a Layout in JavaFX with 3 labels. Each label should be centered horizontally. The first should be placed 1/4 of the way down the window, the second should be halfway down (i.e. centered vertically) and the third should be 3/4 of the way down.
The labels should keep their relative positions if the window is resized.
It seems pretty simple, but I can't figure out how to do it. I tried with a VBox, but there doesn't seem to be a way to have fine control over the vertical placement. I then looked at AnchorPane, but couldn't see how to do this.
Can someone show me an easy way to do this either with FXML or programmatically?
You can do this with a GridPane (there may be other ways). Fill it with four rows and one column, and use RowConstraints to make each row the same height and to align the labels at the bottom of each row. Use a ColumnConstraints object to center the labels horizontally.
SSCCE:
import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.geometry.VPos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.RowConstraints;
import javafx.stage.Stage;
public class LayoutExample extends Application {
#Override
public void start(Stage primaryStage) {
GridPane root = new GridPane();
int numRows = 4 ;
for (int i = 0 ; i < numRows ; i++) {
RowConstraints rc = new RowConstraints();
rc.setPercentHeight(100.0 / numRows);
rc.setValignment(VPos.BOTTOM);
root.getRowConstraints().add(rc);
}
ColumnConstraints cc = new ColumnConstraints();
cc.setHalignment(HPos.CENTER);
cc.setPercentWidth(100);
root.getColumnConstraints().add(cc);
for (int row = 0; row < 3 ; row++) {
Label label = new Label("Label "+(row+1));
root.add(label, 0, row);
}
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
The FXML based approach and using a VBox instead of a GridPanewould look like this:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>
<VBox xmlns:fx="http://javafx.com/fxml" alignment="CENTER">
<Label text="Label 1" VBox.vgrow="ALWAYS">
<maxHeight><Double fx:constant="MAX_VALUE" /></maxHeight>
</Label>
<Label text="Label 2" VBox.vgrow="ALWAYS">
<maxHeight><Double fx:constant="MAX_VALUE" /></maxHeight>
</Label>
<Label text="Label 3" VBox.vgrow="ALWAYS">
<maxHeight><Double fx:constant="MAX_VALUE" /></maxHeight>
</Label>
</VBox>
This code may not like like this, when generated by SceneBuilder, because I use the e(fx)clipse internal DSL FXGraph to generate it.
EDIT
As #James_D suggested (see comment below), this might not be the solution fitting at any time. So. A minor update to the FXML from above would be to use Regions as "spacers" around your Labels.
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.Region?>
<?import javafx.scene.layout.VBox?>
<VBox xmlns:fx="http://javafx.com/fxml" alignment="CENTER">
<Region VBox.vgrow="ALWAYS">
<maxHeight><Double fx:constant="MAX_VALUE" /></maxHeight>
</Region>
<Label text="Label 1"/>
<Region VBox.vgrow="ALWAYS">
<maxHeight><Double fx:constant="MAX_VALUE" /></maxHeight>
</Region>
<Label text="Label 2"/>
<Region VBox.vgrow="ALWAYS">
<maxHeight><Double fx:constant="MAX_VALUE" /></maxHeight>
</Region>
<Label text="Label 3"/>
<Region VBox.vgrow="ALWAYS">
<maxHeight><Double fx:constant="MAX_VALUE" /></maxHeight>
</Region>
</VBox>
This should a more flexible solution.
The ConstrainedGridPane class below helps doing this.
In your 4 label case you'd extend it like this:
public class LabelPane extends ConstrainedGridPane() {
public LabelPane() {
// ... setup you labels
// hgap=0 - 1 column using 100%
super.fixColumnSizes(0,100);
// vgap=5 - 4 columns using 25% each ...
super.fixRowSizes(5, 25,25,25,25);
}
}
ConstrainedGridPane source code
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Region;
import javafx.scene.layout.RowConstraints;
/**
* a GridPane with Column and RowConstraints
* #author wf
*
*/
public class ConstrainedGridPane extends GridPane {
/**
* fix the columnSizes to the given column Width
* #param colWidths
*/
public void fixColumnSizes(int hGap,int... colWidths) {
this.setHgap(hGap);
// Setting columns size in percent
for (int colWidth : colWidths) {
ColumnConstraints column = new ColumnConstraints();
column.setPercentWidth(colWidth);
getColumnConstraints().add(column);
}
}
/**
* fix the rowSizes to the given rowHeights
* #param rowHeights
*/
public void fixRowSizes(int vGap,int... rowHeight) {
this.setVgap(vGap);
for (int rowWidth : rowHeight) {
RowConstraints rowc = new RowConstraints();
rowc.setPercentHeight(rowWidth);
getRowConstraints().add(rowc);
}
// grid.setPrefSize(WINDOW_WIDTH, WINDOW_HEIGHT); // Default width and
// height
this.setMaxSize(Region.USE_COMPUTED_SIZE, Region.USE_COMPUTED_SIZE);
}
}

No rounded corners with background image in JavaFX [duplicate]

I want to apply a border-radius and a shadow in JavaFX.
In CSS3 it would be:
box-shadow: rgba(0,0,0,0.8) 0 0 10px;
border-radius: 3px;
Now I want this in JavaFX, but even the border-radius is not working in the JavaFX Scene Builder. Here is a screenshot of my problem:
(source: rapid-img.de)
On the screenshot you can see that I use:
-fx-border-radius: 10 10 10 10;
-fx-background-radius: 10 10 10 10;
Use the following css to get a drop shadow:
-fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.8), 10, 0, 0, 0);
See the JavaFX CSS Reference guide for details.
To get the border in addition to the drop shadow, place your ImageView containing your Image in a StackPane. And apply the effect css above to the StackPane, in addition to a background and padding on the StackPane.
For example the css below applied to the StackPane containing your ImageView will provide a red border around your image:
-fx-padding: 10;
-fx-background-color: firebrick;
If you want the background defining your border curved at the edges, then use:
-fx-background-radius: 5;
That gets you an image like below where your image is enclosed in a shadowed border:
If you want to actually round the image itself, it's a bit trickier. You need to apply some code to:
Clip the image to a rounded rectangle.
Snapshot the clipped image.
Store the snapshot image back in the ImageView.
Remove the clip from the ImageView.
Apply the drop shadow effect to the ImageView.
Then you can get something like below:
Some code for that "BatmanLost.java":
import javafx.application.Application;
import javafx.fxml.*;
import javafx.scene.*;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.*;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import java.io.IOException;
public class BatmanLost extends Application {
class WingClipper {
#FXML
private ImageView imageView;
#FXML
public void initialize() {
// set a clip to apply rounded border to the original image.
Rectangle clip = new Rectangle(
imageView.getFitWidth(), imageView.getFitHeight()
);
clip.setArcWidth(20);
clip.setArcHeight(20);
imageView.setClip(clip);
// snapshot the rounded image.
SnapshotParameters parameters = new SnapshotParameters();
parameters.setFill(Color.TRANSPARENT);
WritableImage image = imageView.snapshot(parameters, null);
// remove the rounding clip so that our effect can show through.
imageView.setClip(null);
// apply a shadow effect.
imageView.setEffect(new DropShadow(20, Color.BLACK));
// store the rounded image in the imageView.
imageView.setImage(image);
}
}
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws IOException {
FXMLLoader loader = new FXMLLoader(
getClass().getResource(
"batmanlostinthemix.fxml"
)
);
loader.setController(new WingClipper());
Pane batman = loader.load();
stage.setTitle("Where's Batman?");
stage.setScene(new Scene(batman));
stage.show();
}
}
With some FXML "batmanlostinthemix.fxml":
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="313.0" prefWidth="477.0" style="-fx-background-color: azure;" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2">
<children>
<ImageView fx:id="imageView" layoutX="29.0" layoutY="44.0" fitHeight="224.0" fitWidth="400.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="http://collider.com/wp-content/uploads/lego-batman-movie-dc-super-heroes-unite-1.jpg" />
</image>
</ImageView>
</children>
</AnchorPane>
If you use the answer that jewelsea provided, then make sure to test first whether or not clipping is supported:
Platform.isSupported(ConditionalFeature.SHAPE_CLIP)
I try to avoid conditional features unless I have to use them. In my case, I wanted to make a picture round. So an alternative would be to use a Circle instead of an ImageView:
Circle circle = new Circle(14);
ImagePattern pattern = new ImagePattern(myImage);
circle.setFill(pattern);
The circle can be enhanced to use a shadow if supported:
if (Platform.isSupported(ConditionalFeature.EFFECT)) {
circle.setEffect(new DropShadow(8, Color.rgb(0, 0, 0, 0.8)));
}
Thanks martin for pointing ImagePattern
Rectangle rectangle = new Rectangle(0, 0, 280, 180);
rectangle.setArcWidth(30.0); // Corner radius
rectangle.setArcHeight(30.0);
ImagePattern pattern = new ImagePattern(
new Image("file:images/mustang-gt.jpg", 280, 180, false, false) // Resizing
);
rectangle.setFill(pattern);
rectangle.setEffect(new DropShadow(20, Color.BLACK)); // Shadow
Note that here Iam resizing the image to match the size of the rectangle during its load to ensure smoothness.

Border-Radius and Shadow on ImageView

I want to apply a border-radius and a shadow in JavaFX.
In CSS3 it would be:
box-shadow: rgba(0,0,0,0.8) 0 0 10px;
border-radius: 3px;
Now I want this in JavaFX, but even the border-radius is not working in the JavaFX Scene Builder. Here is a screenshot of my problem:
(source: rapid-img.de)
On the screenshot you can see that I use:
-fx-border-radius: 10 10 10 10;
-fx-background-radius: 10 10 10 10;
Use the following css to get a drop shadow:
-fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.8), 10, 0, 0, 0);
See the JavaFX CSS Reference guide for details.
To get the border in addition to the drop shadow, place your ImageView containing your Image in a StackPane. And apply the effect css above to the StackPane, in addition to a background and padding on the StackPane.
For example the css below applied to the StackPane containing your ImageView will provide a red border around your image:
-fx-padding: 10;
-fx-background-color: firebrick;
If you want the background defining your border curved at the edges, then use:
-fx-background-radius: 5;
That gets you an image like below where your image is enclosed in a shadowed border:
If you want to actually round the image itself, it's a bit trickier. You need to apply some code to:
Clip the image to a rounded rectangle.
Snapshot the clipped image.
Store the snapshot image back in the ImageView.
Remove the clip from the ImageView.
Apply the drop shadow effect to the ImageView.
Then you can get something like below:
Some code for that "BatmanLost.java":
import javafx.application.Application;
import javafx.fxml.*;
import javafx.scene.*;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.*;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import java.io.IOException;
public class BatmanLost extends Application {
class WingClipper {
#FXML
private ImageView imageView;
#FXML
public void initialize() {
// set a clip to apply rounded border to the original image.
Rectangle clip = new Rectangle(
imageView.getFitWidth(), imageView.getFitHeight()
);
clip.setArcWidth(20);
clip.setArcHeight(20);
imageView.setClip(clip);
// snapshot the rounded image.
SnapshotParameters parameters = new SnapshotParameters();
parameters.setFill(Color.TRANSPARENT);
WritableImage image = imageView.snapshot(parameters, null);
// remove the rounding clip so that our effect can show through.
imageView.setClip(null);
// apply a shadow effect.
imageView.setEffect(new DropShadow(20, Color.BLACK));
// store the rounded image in the imageView.
imageView.setImage(image);
}
}
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws IOException {
FXMLLoader loader = new FXMLLoader(
getClass().getResource(
"batmanlostinthemix.fxml"
)
);
loader.setController(new WingClipper());
Pane batman = loader.load();
stage.setTitle("Where's Batman?");
stage.setScene(new Scene(batman));
stage.show();
}
}
With some FXML "batmanlostinthemix.fxml":
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.image.Image?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="313.0" prefWidth="477.0" style="-fx-background-color: azure;" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2">
<children>
<ImageView fx:id="imageView" layoutX="29.0" layoutY="44.0" fitHeight="224.0" fitWidth="400.0" pickOnBounds="true" preserveRatio="true">
<image>
<Image url="http://collider.com/wp-content/uploads/lego-batman-movie-dc-super-heroes-unite-1.jpg" />
</image>
</ImageView>
</children>
</AnchorPane>
If you use the answer that jewelsea provided, then make sure to test first whether or not clipping is supported:
Platform.isSupported(ConditionalFeature.SHAPE_CLIP)
I try to avoid conditional features unless I have to use them. In my case, I wanted to make a picture round. So an alternative would be to use a Circle instead of an ImageView:
Circle circle = new Circle(14);
ImagePattern pattern = new ImagePattern(myImage);
circle.setFill(pattern);
The circle can be enhanced to use a shadow if supported:
if (Platform.isSupported(ConditionalFeature.EFFECT)) {
circle.setEffect(new DropShadow(8, Color.rgb(0, 0, 0, 0.8)));
}
Thanks martin for pointing ImagePattern
Rectangle rectangle = new Rectangle(0, 0, 280, 180);
rectangle.setArcWidth(30.0); // Corner radius
rectangle.setArcHeight(30.0);
ImagePattern pattern = new ImagePattern(
new Image("file:images/mustang-gt.jpg", 280, 180, false, false) // Resizing
);
rectangle.setFill(pattern);
rectangle.setEffect(new DropShadow(20, Color.BLACK)); // Shadow
Note that here Iam resizing the image to match the size of the rectangle during its load to ensure smoothness.

Resources