Javafx buttons not functioning properly, and pane not resizing - java

Currently the code below produces a BorderPane with a GridPane in the center and a HBox on the bottom to hold two buttons. The left-most pane in the GridPane contains the text "Name Here". Right now I only want the buttons to move the text "Name Here" up and down but they will not move the text.
I think it has something to do with the particular GridPane node, but I'm not sure. Additionally, I don't know why the left-most GridPane takes up more space relative to the right-most GridPane within the center of the BorderPane.
Any advice will be greatly appreciated, thank you!
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.geometry.Pos;
import javafx.geometry.HPos;
import javafx.geometry.VPos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.Priority;
import javafx.scene.text.Text;
public class differentWindows extends Application {
protected Text name = new Text("Name Here");
protected BorderPane getPane() {
// HBox to hold the up and down buttons
HBox paneForButtons = new HBox(20);
Button btUp = new Button("Up");
Button btDown = new Button("Down");
paneForButtons.getChildren().addAll(btUp, btDown);
paneForButtons.setAlignment(Pos.BOTTOM_LEFT);
// Grid pane to go in center of the border pane, for the name and video
GridPane paneForTextNVideo = new GridPane();
paneForTextNVideo.setAlignment(Pos.CENTER);
paneForTextNVideo.setGridLinesVisible(true);
paneForTextNVideo.add(name, 0, 0);
Text temp = new Text("temp");
paneForTextNVideo.add(temp, 1, 0);
paneForTextNVideo.setHalignment(temp, HPos.CENTER);
paneForTextNVideo.setValignment(temp, VPos.CENTER);
paneForTextNVideo.setHgrow(temp, Priority.ALWAYS);
paneForTextNVideo.setVgrow(temp, Priority.ALWAYS);
paneForTextNVideo.setHalignment(name, HPos.CENTER);
paneForTextNVideo.setValignment(name, VPos.CENTER);
paneForTextNVideo.setHgrow(name, Priority.ALWAYS);
paneForTextNVideo.setVgrow(name, Priority.ALWAYS);
// Border pane to hold all windows
BorderPane pane = new BorderPane();
pane.setBottom(paneForButtons);
pane.setCenter(paneForTextNVideo);
btUp.setOnAction(e -> name.setY(name.getY() - 10));
btDown.setOnAction(e -> name.setY(name.getY() + 10));
return pane;
} // end of the getPane method
#Override
public void start(Stage primaryStage) {
Scene scene = new Scene(getPane(), 450, 200);
primaryStage.setTitle("Assignment #7");
primaryStage.setScene(scene);
primaryStage.show();
} // end of start method
public static void main(String[] args) {
Application.launch(args);
}
} // end of class

Try using setLayoutY instead of setY:
btUp.setOnAction(e -> name.setLayoutY(name.getLayoutY() - 10));
btDown.setOnAction(e -> name.setLayoutY(name.getLayoutY() + 10));
As a sidenote, the Node parent class also has a relocate method for easily changing both the X and Y coordinates:

Related

Why are my JavaFX buttons unevenly spaced?

I'm new to JavaFX, trying to build a GUI program that displays a bill for a table at a restaurant when you click on that table. The spacing is off between the table buttons and I'm not sure why.
The GUI class for my program:
package restaurantBillingProgram;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.scene.control.Label;
import javafx.scene.control.Button;
import javafx.geometry.Pos;
public class BillingGUI extends Application {
#Override
public void start(Stage primaryStage) {
// Create grid pane
GridPane pane = new GridPane();
pane.setAlignment(Pos.CENTER);
pane.setHgap(5);
pane.setVgap(5);
// Label
pane.add(new Label("Generate bill"), 1, 0);
// Buttons
Button btT1 = new Button("Table 1");
pane.add(btT1, 0, 1);
btT1.setOnAction(e - > Billing.generateT1());
Button btT2 = new Button("Table 2");
pane.add(btT2, 1, 1);
btT2.setOnAction(e - > Billing.generateT2());
Button btT3 = new Button("Table 3");
pane.add(btT3, 2, 1);
btT3.setOnAction(e - > Billing.generateT3());
// Create scene and place in stage
Scene scene = new Scene(pane, 250, 250);
primaryStage.setTitle("Restaurant Billing Program");
primaryStage.setScene(scene);
primaryStage.show();
}
// Main method
public static void main(String[] args) {
launch(args);
}
}
From the Javadoc:
Row/Column Sizing
By default, rows and columns will be sized to fit their content; a column will be wide enough to accommodate the widest child, ...
The label in row 0 column 1 forces that column to be wider.
You probably want the label to be centered and span all 3 columns.
While doing you layout, use pane.setGridLinesVisible(true). This should only be used during debugging. It can be very useful for situations like your current situation. As #Jim Garrison pointed out, your Label is causing the issue:
Issue:
One way to fix this is to let the Label span all columns and center the Label's text.
Fix:
Key Code:
label.setMaxWidth(Double.MAX_VALUE);
label.setAlignment(Pos.CENTER);
pane.add(label, 0, 0, 3, 1);// Look at the following link to see how this add method works. https://openjfx.io/javadoc/11/javafx.graphics/javafx/scene/layout/GridPane.html#add(javafx.scene.Node,int,int,int,int)
Full Code:
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.scene.control.Label;
import javafx.scene.control.Button;
import javafx.geometry.Pos;
public class BillingGUI extends Application {
#Override
public void start(Stage primaryStage) {
// Create grid pane
GridPane pane = new GridPane();
pane.setAlignment(Pos.CENTER);
pane.setHgap(5);
pane.setVgap(5);
pane.setGridLinesVisible(true);//Use for debugging only!!!!
// Label
Label label = new Label("Generate bill");
label.setMaxWidth(Double.MAX_VALUE);
label.setAlignment(Pos.CENTER);
pane.add(label, 0, 0, 3, 1);
// Buttons
Button btT1 = new Button("Table 1");
pane.add(btT1, 0, 1);
Button btT2 = new Button("Table 2");
pane.add(btT2, 1, 1);
Button btT3 = new Button("Table 3");
pane.add(btT3, 2, 1);
// Create scene and place in stage
Scene scene = new Scene(pane, 250, 250);
primaryStage.setTitle("Restaurant Billing Program");
primaryStage.setScene(scene);
primaryStage.show();
}
// Main method
public static void main(String[] args) {
launch(args);
}
}

JavaFX GridPane Object Alignment

I am trying to use JavaFX to create a scene with the program's title positioned at the top-center, and buttons in a vertical line along the left side of the scene. However, both of these elements are displayed clustered up in the top-right of the scene, instead of where I want them to be.
How can I get these elements to be displayed where I want them to?
Here is how I try to set the program title's position:
grid.add(gameTitle, 0, 0);
GridPane.setHalignment(gameTitle, HPos.CENTER);
GridPane.setValignment(gameTitle, VPos.TOP);
I try to set the VBox object similarly:
grid.getChildren().add(buttonBox);
GridPane.setHalignment(buttonBox, HPos.LEFT);
GridPane.setValignment(buttonBox, VPos.CENTER);
This is what is displayed:
My entire MainMenu class. (This class is called in my Main class to construct the scene):
package scenes;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.application.Platform;
import javafx.geometry.HPos;
import javafx.geometry.VPos;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
public class MainMenu {
public Pane getMainMenuPane() {
// Create the scene grid
GridPane grid = new GridPane();
grid.setHgap(10);
grid.setVgap(10);
// Set the game title to the top center
Text gameTitle = new Text("Bandit King");
Font titleFont = new Font(75);
gameTitle.setFont(titleFont);
//
grid.add(gameTitle, 0, 0);
GridPane.setHalignment(gameTitle, HPos.CENTER);
GridPane.setValignment(gameTitle, VPos.TOP);
// Create Button objects and put in VBox
Button[] buttArr = makeButtons();
VBox buttonBox = new VBox();
buttonBox.getChildren().addAll(buttArr);
buttonBox.setSpacing(10);
// add Button VBox to GridPane
grid.getChildren().add(buttonBox);
GridPane.setHalignment(buttonBox, HPos.LEFT);
GridPane.setValignment(buttonBox, VPos.CENTER);
return (Pane) grid;
}
private Button[] makeButtons() {
// Create buttons
Button start = new Button("Start a New Game");
Button load = new Button("Load a Saved Game");
Button exit = new Button("Exit the Game");
// set Button actions
start.setOnAction( a -> {
System.out.println("WIP- start game.");
});
load.setOnAction( a -> {
System.out.println("WIP- load game");
});
exit.setOnAction( a -> {
Platform.exit();
System.exit(0);
});
// return Button[] array
Button[] buttArr = {start, load, exit};
return buttArr;
}
}
My Main class (Displays the scene):
package central;
import javafx.stage.Stage;
import scenes.*;
import controllers.*;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
public class Main extends Application {
// Get scene panes
private static Pane mainMenu = new MainMenu().getMainMenuPane();
// Create SceneController object.
private static Scene scene = new Scene(mainMenu, 1600, 900);
public static SceneController SceneControl = new SceneController(scene);
#Override
public void start(Stage stage) {
stage.setTitle("Bandit King");
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
The default cell you add the children of a GridPane to is (0, 0) which is what you do in this line:
grid.getChildren().add(buttonBox);
you need to change this to
grid.add(buttonBox, 0, 1);
to set the row index to 1. (There are alternatives to assigning the row index this way, but this is the most convenient option in this case.)
This won't result in the first column taking the full width of the GridPane though. If you also want the first column to take all the width available, you need to specify this by adding ColumnConstraints:
ColumnConstraints constraints = new ColumnConstraints();
constraints.setHgrow(Priority.ALWAYS);
grid.getColumnConstraints().add(constraints);
As far as what I noticed, you added all the nodes in a column and set there positions, but you did not specify how much the column needs to be stretched. GridPane column will not stretch automatically by itself unless specified.
You can debug your program, by enabling the gridLinesVisible of GridPane property to true.
grid.setGridLinesVisible(true);
You need to specify the columnConstraints, to let the GridPane column stretch to the available width.
ColumnConstraints constraint = new ColumnConstraints();
constraint.setHgrow(Priority.ALWAYS);
grid.getColumnConstraints().add(constraint);

Pane -> Hbox -> ImageView fit height

I have ImageView inside HBox inside Pane, and want ImageView height fit HBox height when resizing stage. Trying the following code
package sample;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
Pane pane = new Pane();
pane.setBackground(new Background(new BackgroundFill(Color.RED, CornerRadii.EMPTY, Insets.EMPTY)));
HBox hBox = new HBox();
hBox.setBackground(new Background(new BackgroundFill(Color.GREEN, CornerRadii.EMPTY, Insets.EMPTY)));
hBox.setPrefHeight(100);
hBox.setPrefWidth(100);
hBox.prefHeightProperty().bind(pane.heightProperty());
ImageView imageView = new ImageView("http://www.calgary.ca/CA/city-manager/scripts/about-us/webparts/images/ourHistory_retina.jpg");
imageView.fitHeightProperty().bind(hBox.heightProperty());
imageView.setPreserveRatio(true);
hBox.getChildren().add(imageView);
pane.getChildren().add(hBox);
primaryStage.setScene(new Scene(pane, 300, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
When starting, ImageView is not fit windows height, it shown in it's original size. And it scales only up when I resize window to make it bigger, then original image size.
Also I see, that hBox.prefHeightProperty().bind(pane.heightProperty()) works perfectly (height of red HBox background behind image is corresponding window height).
So it seems imageView.fitHeightProperty().bind(hBox.heightProperty()) behaves not as I expecting.
How can I make ImageView fit height of HBox, nested in Pane?
In the code you posted, the HBox is actually getting taller than the root Pane that contains it (though it is getting clipped so you only see the portion in side the root). So the binding on the fitHeight is behaving as you want, but the layout with respect to the HBox's preferred height is not doing what you expect. So you need better control over the layout of the HBox.
The layout pane that allows you the most control is the GridPane. So, while it's possible there may be easier ways to do this, using a GridPane as the root and placing the HBox in the only cell at 0,0 allows you to control how the HBox is resized. The only additional thing you need here is to allow the HBox to shrink indefinitely with setMinHeight(0).
I think the following provides the behavior you want:
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.RowConstraints;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
GridPane root = new GridPane();
RowConstraints rc = new RowConstraints();
rc.setVgrow(Priority.ALWAYS);
root.getRowConstraints().add(rc);
root.setBackground(new Background(new BackgroundFill(Color.RED, CornerRadii.EMPTY, Insets.EMPTY)));
HBox hBox = new HBox();
hBox.setBackground(new Background(new BackgroundFill(Color.GREEN, CornerRadii.EMPTY, Insets.EMPTY)));
hBox.setMinHeight(0);
ImageView imageView = new ImageView("http://www.calgary.ca/CA/city-manager/scripts/about-us/webparts/images/ourHistory_retina.jpg");
imageView.fitHeightProperty().bind(hBox.heightProperty());
imageView.setPreserveRatio(true);
hBox.getChildren().add(imageView);
root.add(hBox, 0, 0);
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Thanks to James_D, who have suggested the solution. It's possible even remain Pane as root.
The only line to be added is
hBox.setMinHeight(0);
Also odd
hBox.setPrefHeight(100);
hBox.setPrefWidth(100);
should be removed.

adding border title in JavaFX [duplicate]

This above picture is result of my code.But I want like the following.
How can I fix it? The following is my code.I read too many sources but they was too complicated. For example,a source that I read, I think this way is very complicated.Maybe there is a easy way to solve this problem.
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class Test extends Application {
public BorderPane border = new BorderPane();
public Label name = new Label("Name");
public Label surname = new Label("Surname");
public TextField name1 = new TextField();
public TextField surname1 = new TextField();
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage arg0) throws Exception {
Scene scene = new Scene(new VBox(), 300, 200);
arg0.setTitle("Header");
arg0.setResizable(false);
scene.setFill(Color.OLDLACE);
StackPane grid = addStackPane();
border.setMargin(grid, new Insets(12,12,12,12));
border.setCenter(grid);
((VBox) scene.getRoot()).getChildren().add(border);
arg0.setScene(scene);
arg0.show();
}
#SuppressWarnings("static-access")
public StackPane addStackPane() {
StackPane pane = new StackPane();
GridPane grid = new GridPane();
Label title = new Label("Border Title");
title.setStyle("-fx-translate-y: -7");
pane.setAlignment(title, Pos.TOP_LEFT);
grid.setStyle("-fx-content-display: top");
grid.setStyle("-fx-border-insets: 20 15 15 15");
grid.setStyle("-fx-background-color: white");
grid.setStyle("-fx-border-color: black");
grid.setHgap(10);
grid.setVgap(10);
grid.setPadding(new Insets(25, 10, 25, 10));
grid.add(name, 1, 0);
grid.add(name1, 2, 0);
grid.add(surname, 1, 1);
grid.add(surname1, 2, 1);
pane.getChildren().addAll(grid, title);
return pane;
}
}
Thank you all that reads this topic.
Try to set -fx-background-color of your title label to the same color as the borderPane's background. And make sure you set in a css file, because it's not possible to set multiple styles via setStyle() unless you concatenate them:
myComponent.setStyle("-fx-text-fill: white;"+
"-fx-background-color: black;");
Furthermore it is bad practice to use an InlineStyleSheets as it always has a higher priority than a rule specified in a CSS StyleSheet.
(If you change pane.setAlignment(title, Pos.TOP_LEFT) to StackPane.setAlignment(title, Pos.TOP_LEFT) you can remove the "static-acces" warning.)
User jewelsea has made a control to perform this.
The related stackoverflow question is: How to add border to panel of javafx?
And on gitHub: https://gist.github.com/jewelsea/2838292
I have used it with minimal modification and it works like a charm.

Aligning buttons in Javafx layouts

I would like to align my button so that the first button is on the left of the screen and the other two are on the right. I am currently using HBox to try to position them but i cannot seem to able to figure out how to lay them out properly. The code below is what i am using now.
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.stage.Stage;
public class ButtonTest extends Application {
private Button min, close, openfile;
public static void main(String[] args){
launch(args);
}
#Override
public void start(final Stage stage) throws Exception {
stage.setTitle("Button Test");
Group root = new Group();
BorderPane borderpane = new BorderPane();
setUpButtons();
HBox hbox = new HBox();
hbox.setSpacing(10);
hbox.getChildren().add(openfile);
HBox hbox1 = new HBox();
hbox1.setAlignment(Pos.CENTER_RIGHT);
hbox1.getChildren().addAll(min, close);
hbox.getChildren().add(hbox1);
HBox.setHgrow(hbox1, Priority.ALWAYS);
borderpane.setTop(hbox);
root.getChildren().add(borderpane);
Scene scene = new Scene(root,800,600);
stage.setFullScreen(true);
scene.getStylesheets().add("button.css");
stage.setScene(scene);
stage.show();
}
private void setUpButtons() {
close = new Button("x");
close.setId("closeBtn");
min = new Button("_");
min.setId("minBtn");
openfile = new Button("Open file");
openfile.setId("openFileBtn");
}
}
Any help would be appreciated
Thanks
Set the aligment of your outer HBox (hbox) to LEFT, and the aligment of your inner HBox (hbox1) to RIGHT.
Then you can have outer content on the left, and inner content on the right.
*EDIT: got your problem now. Stop using Group and add the borderpane directly to the Scene:
Scene scene = new Scene(borderpane,800,600);

Categories

Resources