Javafx GridPane, how to center Node? (Text/Label) - java

I am trying to learn Javafx for a class I am taking. I am having a lot of difficulty transitioning from HTML + ERB templates to the Javafx framework (I am a Rails dev).
For some reason I am unable to center a Label node in a gridpane. Here is my start method:
#Override
public void start(Stage stage) throws Exception {
GridPane root = new GridPane();
FlowPane leftbanner = new FlowPane();
leftbanner.setPrefWidth(200);
String bgStyle = "-fx-background-color: lightblue;"
+ "-fx-background-radius: 0%;"
+ "-fx-background-inset: 5px;";
leftbanner.setStyle(bgStyle);
root.add(leftbanner, 0, 0, 1, 1);
root.add(createGridPane(), 1, 0, 1, 1);
Scene scene = new Scene(root, 700, 500);
stage.setTitle("Recommendify");
stage.setScene(scene);
stage.show();
}
I am using the createGridPane method to build my app. Here are the contents of that method which includes my attempts to center the label:
public GridPane createGridPane() {
GridPane grid = new GridPane();
grid.setPadding(new Insets(10));
grid.setHgap(10);
grid.setVgap(10);
Text txt = new Text("Recommendify");
txt.setFont(Font.font("Dialog", FontWeight.BOLD, 12));
GridPane.setHalignment(txt, HPos.CENTER);
grid.add(txt, 0, 0, 1, 1);
grid.add(new Separator(), 0, 1, 3, 1);
return grid;
}
I have also tried these solutions posted here: JavaFX alignment of Label in GridPane
Do I need to throw this Label node into a container in order to center it in the GridPane? Like an HBox or VBox?

There is actually nothing wrong with your code. The "Recommendify" text is centered in its cell. However, the cell is no wider than the text itself.
You can see this by turning on the grid lines within your createGridPane() method:
grid.setGridLinesVisible(true);
To test the alignment, you can add ColumnConstraints to the GridPane:
grid.getColumnConstraints().add(new ColumnConstraints(150));
The above statement sets the preferred width of the first column to 150. Here is the new result:
As you can see, the Text node is centered properly.
EDIT: Keep in mind that if you want your Text to be centered over the Separator you've added to the second row, you need to have
it span 3 columns as well.

Related

Why won't javafx rectangles display their color when sizing to the parent container's getWidth/Height?

I'm trying to use rectangles as the background for text labels by putting them behind the VBox text in a StackPane, but when I try using the VBox's getWidth() or getHeight() values for the rectangle's size, the rectangle does not appear. I suppose I could
This works, displaying the blue rectangle behind the text, though not the size I want:
StackPane tadPane = new StackPane();
tadPane.setBorder(border);
Rectangle tadRec = new Rectangle();
VBox tadBox = new VBox();
Label totalXP = new Label("Total XP: ");
Label diff = new Label("Difficulty: ");
tadBox.getChildren().addAll(totalXP,diff);
tadRec.setWidth(50);
tadRec.setHeight(50);
tadRec.setFill(Color.BLUE);
tadPane.getChildren().addAll(tadRec,tadBox);
But this doesn't, the rectangle is not visible:
StackPane tadPane = new StackPane();
tadPane.setBorder(border);
Rectangle tadRec = new Rectangle();
VBox tadBox = new VBox();
Label totalXP = new Label("Total XP: ");
Label diff = new Label("Difficulty: ");
tadBox.getChildren().addAll(totalXP,diff);
tadRec.setWidth(tadBox.getWidth());
tadRec.setHeight(tadBox.getHeight());
tadRec.setFill(Color.BLUE);
tadPane.getChildren().addAll(tadRec,tadBox);
I can't understand why this would be happening. Raw numbers in the setWidth/Height work, but the getWidth/Height from the VBox should be returning numbers too if the labels with text are inside.
The reason for this is that at the time you retrieve the height and width, no layout pass has happened for the VBox so the size is still the initial one of 0 x 0.
You could use bindings to make the size update on a layout:
tadRec.widthProperty().bind(tadBox.widthProperty());
tadRec.heightProperty().bind(tadBox.heightProperty());
though it could be much simpler to simply apply a a background to the VBox instead of using a Rectangle:
tadBox.setStyle("-fx-background-color: blue;");

JavaFX - force the child of a GridPane to fit the size of the cell

I am trying to force the child of a GridPane to fit the size of the cell it is in. In this case, I am creating a month view calendar and the columns and rows are a set size regardless of what is in it.
On this calendar, each cell contains a normal VBox and each VBox contains a label that displays the day of the month and each of the events for that day. Many of the days have no events; some of them have one event; and a few have more than one event.
The calendar size is dependent on the window size and will grow and shrink in accordance to the window. Right now, if the cell is too small to fit all of the events, then the height of that one VBox for that day in the cell becomes larger than the cell.
The header row has the following constraint:
HEADER_CONSTRAINT = new RowConstraints(10, -1, 500,
Priority.NEVER, VPos.BASELINE, true);
and the other rows have this constraint:
ROW_CONSTRAINT = new RowConstraints(30, 30, Integer.MAX_VALUE,
Priority.ALWAYS, VPos.TOP, true);
What I think I need to do is:
grid.add(cell, c, r);
vbox.maxHeightProperty().bind(grid.getRow(r).heightProperty()); // <-- this line is not right, but something like this.
As #fabian mentioned correctly, the size of a VBox is entirely dependent the sizes of its children. If you wish to have a container that does not resize depending on its children, you can use a Pane instead. Like this:
public void start(Stage primaryStage)
{
GridPane root = new GridPane();
Scene scene = new Scene(root, 300, 300);
int c = 0, r = 0;
Pane c0 = new Pane();
c0.setPrefSize(200, 200);
c0.setBorder(new Border(new BorderStroke(Color.RED, BorderStrokeStyle.SOLID, CornerRadii.EMPTY,
new BorderWidths(1))));
root.add(c0, c, r);
primaryStage.setScene(scene);
primaryStage.show();
}
Add a shape to test:
Pane c0 = new Pane();
c0.setPrefSize(200, 200);
c0.setBorder(new Border(new BorderStroke(Color.RED, BorderStrokeStyle.SOLID, CornerRadii.EMPTY,
new BorderWidths(1))));
{
Circle circle = new Circle(160, Color.BLUE);
circle.setCenterX(160);
circle.setCenterY(160);
c0.getChildren().add(circle);
}
root.add(c0, c, r);
Note that although the shape protrudes outside of the bounds of c0, the borders of c0 stay in place, indicating that its size is unaffected. To prevent the content from protruding out, you need to add a clip:
c0.setClip(new Rectangle(c0.getPrefWidth(), c0.getPrefHeight()));
If you want a more fancy clip instead of a simple trim, such as fade-in, fade-out, and shadows, you can read this very good tutorial here.
Now just replace this Circle with your VBox, so that the VBox is a child of this Pane, and add the Pane to your GridPane and you're done. I will provide my final code here as a reference:
public void start(Stage primaryStage)
{
GridPane root = new GridPane();
Scene scene = new Scene(root, 300, 300);
int c = 0, r = 0;
Pane c0 = new Pane();
c0.setPrefSize(200, 200);
c0.setClip(new Rectangle(c0.getPrefWidth(), c0.getPrefHeight()));
c0.setBorder(new Border(new BorderStroke(Color.RED, BorderStrokeStyle.SOLID, CornerRadii.EMPTY,
new BorderWidths(1))));
{
Circle circle = new Circle(160, Color.BLUE);
circle.setCenterX(160);
circle.setCenterY(160);
c0.getChildren().add(circle);
}
root.add(c0, c, r);
primaryStage.setScene(scene);
primaryStage.show();
}
Update:
#Jai pointed out that the size is static in this implementation. If you wish to dynamically adjust the size of the cells if the size of the GridPane changes, you can add a listener to its widthProperty and heightProperty like this:
int rowCount = 5, columnCount = 7; // You should know these values.
ChangeListener<Number> updater = (o, oV, nV) ->
{
double newWidth = root.getWidth() / columnCount;
double newHeight = root.getHeight() / rowCount;
root.getChildren().forEach(n ->
{
// Assuming every child is a Pane.
Pane p = (Pane) n;
p.setPrefSize(newWidth, newHeight);
p.setClip(new Rectangle(newWidth, newHeight));
});
};
root.widthProperty().addListener(updater);
root.heightProperty().addListener(updater);
Alternatively...
If you wish to use ColumnConstraints and RowConstraints to determine the cell size you can set the Panes to expand, and only update their clips in the listener, which now listens to ColumnConstraints and RowConstraints:
ColumnConstraints cc = new ColumnConstraints(200);
RowConstraints rc = new RowConstraints(200);
c0.setPrefSize(Double.MAX_VALUE, Double.MAX_VALUE);
c0.setClip(new Rectangle(cc.getPrefWidth(), rc.getPrefHeight()));
and...
ChangeListener<Number> updater = (o, oV, nV) ->
{
root.getChildren().forEach(n ->
{
// Assuming every child is a Pane.
Pane p = (Pane) n;
p.setClip(new Rectangle(cc.getPrefWidth(), rc.getPrefHeight()));
});
};
cc.prefWidthProperty().addListener(updater);
rc.prefHeightProperty().addListener(updater);

JavaFX How to Center Multiple Components side by side

I have 2 components: Label & Button. I want to put them side by side & align them together in CENTER. But I failed to do so, as they are still aligned LEFT but not CENTER.
My code as below:
Label sloganLbl = new Label("With cost as low as $1.99, you can own a fraction share of U.S. stock. No account yet?");
sloganLbl.getStyleClass().add("blue-small-font");
Button signUpBtn = new Button("Open account now");
signUpBtn.getStyleClass().add("green-btn-small-font");
GridPane topGrid = new GridPane();
topGrid.setHgap(20);
topGrid.add(sloganLbl, 0, 0);
topGrid.add(signUpBtn, 1, 0);
topGrid.setGridLinesVisible(true);
GridPane.setHalignment(sloganLbl, HPos.RIGHT);
GridPane.setHalignment(signUpBtn, HPos.LEFT);
BorderPane topBorder = new BorderPane();
topBorder.setPadding(new Insets(15, 10, 15, 10));
topBorder.setCenter(topGrid);
topBorder.getStyleClass().add("blue-small-font");
topGrid.getStyleClass().add("blue-small-font");
borderPane.setTop(topBorder);
The problem is topBorder.setCenter(topGrid); is not able to center the content in center. Seems topGrid is taking up full width, not just total width of it's 2 columns.
How can I achieve the center alignment? Thanks!
You can update the GridPane with a gap filler column on the left and on the right.
ColumnConstraints leftFiller = new ColumnConstraints();
leftFiller.setHgrow(Priority.ALWAYS); // Fills the space left on the left side
ColumnConstraints rightFiller = new ColumnConstraints();
rightFiller.setHgrow(Priority.ALWAYS); // Fills the space left on the right side
topGrid.getColumnConstraints().addAll(leftFiller, new ColumnConstraints(),
new ColumnConstraints(), rightFiller);
topGrid.add(sloganLbl, 1, 0);
topGrid.add(signUpBtn, 2, 0);
This snippet will create a GridPane with 4 columns. The first and the last is growing when the GridPane becomes resized, the 2 inner columns hold the Label and the Button.
Please notice that the Label and the Button are now placed into the second and third column.

JavaFX Graphical Glitch

I'm experiencing a weird graphical glitch on my application. The situation is that I am creating some GridPanes and adding them to a parent GridPane which is inside a ScrollPane. However, upon scrolling, some weird glitches begin occurring. Here is a picture:
(Sorry for having to use links, I don't have enough reputation to post images).
http://s11.postimg.org/x9eg8bz4z/Glitch.png
Here is a picture of what it should look like:
http://s11.postimg.org/cqjk39l7n/Normal.png
Here is my code:
private static class Controller implements Initializable {
#FXML private GridPane projectsPane;
#Override
public void initialize(URL location, ResourceBundle resources) {
//I first create some objects to be used when
//creating the GridPanes in the following loop,
//but I have removed the code for simplicity
for(AvailableProject availableProject : availableProjects) {
GridPane projectPane = new GridPane();
projectPane.setBackground(new Background(new BackgroundFill(Color.DARKGREY, CornerRadii.EMPTY, Insets.EMPTY)));
ColumnConstraints column1 = new ColumnConstraints();
column1.setPercentWidth(50);
ColumnConstraints column2 = new ColumnConstraints();
column2.setPercentWidth(50);
projectPane.getColumnConstraints().addAll(column1, column2);
projectPane.setPadding(new Insets(5));
Label projectName = new Label(availableProject.projectName);
GridPane.setValignment(projectName, VPos.CENTER);
projectPane.add(projectName, 0, 0);
TextFlow description = new TextFlow(new Text(availableProject.description));
description.setMaxSize(200, 100);
GridPane.setValignment(description, VPos.CENTER);
projectPane.add(description, 0, 1);
Label category = new Label(availableProject.category);
GridPane.setValignment(category, VPos.CENTER);
GridPane.setHalignment(category, HPos.RIGHT);
projectPane.add(category, 1, 0, 1, 2);
projectsPane.add(projectPane, 0, yRow);
yRow++;
Pane pane = new Pane();
pane.setMinHeight(15);
projectsPane.addRow(yRow, pane);
yRow++;
}
}
}
I have tried simplifying the code to make it cleaner, but I will post the rest if needed.
Thank you!
I seem to have found the solution. By the looks of it, this really is a bug. I will report it to Oracle later. It seems the problem was that I had padding in my ScrollPane. By my testing, if padding was greater than 5, the glitches would occur. A workaround is to assign the padding to the parent GridPane rather than the ScrollPane.

gridpane size and placement to cover entire area from left to right

Hello stackoverflow users! I have a question about gridpanes. I'm working on a program (picture below) and I'm mostly finished. However, I've run into a few small cosmetic issues.
I've created my title:
GridPane grid = new GridPane();
Text scenetitle = new Text("Welcome to the Pizza Palace");
scenetitle.setFill(Color.RED);
scenetitle.setFont(Font.font("Tahoma", FontWeight.NORMAL, 20));
grid.add(scenetitle, 0, 0);
As you can see the title is Welcome to the Pizza Palace and I wanted the title to be centered so I entered
grid.add(scenetitle, 0, 0);
because I wanted the title to cover the scene (as displayed in the picture) and I wanted the title to be centered
Unfortunately, the title doesn't cover the entire scene in fact it cause the gridpane below it (0,1) where "Each Toppings" is located to expand as the title increases or decreases.
I've run into a similiar issue in the text area for "your orders"
// Create a new text area
TextArea orderscreen = new TextArea();
orderscreen.setPrefColumnCount(25);
orderscreen.setPrefRowCount(7);
grid.add(orderscreen, 0, 4);
Once again I set the grid to 0 for the far left and 4 so it would be located under the button but unfortunately as the text area increases so does my toppings.
So how do I go about creating a title or textarea using a gridpane that will cover the entire scene from left to right (like the title in the picture does)?

Categories