Why are my JavaFX buttons unevenly spaced? - java

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);
}
}

Related

How do I display buttons and text under eachother with JavaFX

I have been trying to display buttons and some text with javafx but it whont work it just displays over eachother in the middle of the screen:
I have been trying to use vbox and ive also tried to use hbox but both dont change how it looks when i run it
(when i run it i get no erors)
(also im using vs code if that has anything to say)
Here is my code so far:
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class App extends Application {
#Override
public void start(Stage primaryStage) {
// buttons
VBox vboxBtn = new VBox();
vboxBtn.setPadding(new Insets(10, 10, 10, 10));
vboxBtn.setSpacing(10);
Button btnRoom = new Button("changeRoom");
Button btnMap = new Button("changeMap");
vboxBtn.getChildren().addAll(btnRoom, btnMap);
// text
VBox vboxTxt = new VBox();
vboxTxt.setPadding(new Insets(10, 10, 10, 10));
vboxTxt.setSpacing(10);
Text txtRoom = new Text("Room");
Text txtMap = new Text("Map");
vboxTxt.getChildren().addAll(btnRoom, btnMap);
String currentRoom = "None";
String currentMap = "None";
// button for switching maps
btnMap.setText("Change the map");
// button click
btnMap.setOnAction(new EventHandler<ActionEvent>(){
#Override
public void handle(ActionEvent event) {
System.out.println("Hello world");
}
});
// text for maps
txtMap.setText("Map: " + currentMap);
// button for switching rooms
btnRoom.setText("Hello world");
// button click
btnRoom.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Hello world");
}
});
// text
txtRoom.setText("Room: " + currentRoom);
StackPane root = new StackPane();
root.getChildren().add(btnRoom);
root.getChildren().add(btnMap);
root.getChildren().add(txtRoom);
root.getChildren().add(txtMap);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I think the problem is you are adding butons and txts to the pane instead of Vboxes and Hboxes.
I believe you want them on a 4x4 grid, to do that you need to add your virtual boxes to a hbox then add that hbox to a pane, or u could use a grid.
Or you could set their locations, I dont know if this is possible with code, but you can do that in screenbuilder.
PS: check out screenbuilder for javafx.

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);

Javafx buttons not functioning properly, and pane not resizing

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:

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.

JavaFX GridPane column sizing

I'm trying to make a window with a certain layout using 2 columns, but I can't quite get it to work the way I want.
First, some simplified example code:
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Spinner;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
public class GridTest extends Application {
#Override
public void start(final Stage stage) throws Exception {
final GridPane grid = new GridPane();
grid.setHgap(5);
grid.setVgap(5);
grid.setPadding(new Insets(10, 10, 10, 10));
grid.add(new Label("Something:"), 0, 0);
final Spinner<?> s1 = new Spinner<>();
grid.add(s1, 1, 0);
grid.add(new Label("Another thing:"), 0, 1);
final Spinner<?> s2 = new Spinner<>();
grid.add(s2, 1, 1);
final Button b = new Button("A button");
grid.add(b, 0, 2, 2, 1);
stage.setScene(new Scene(grid, 400, 150));
stage.show();
}
public static void main(final String... args) {
launch(args);
}
}
Here is what I want:
the spinners and the button should use all available width
the labels should always keep their preferred width, and never change their size
when I make the window wider, the spinners and the button should grow
when I make the window narrower, the spinners and the button should shrink, but not below their preferred width
I tried using all sorts of constraints, but I couldn't get everything to work right. I think the main problem I found was that after getting the spinners to use the available width, they refused to shrink when narrowing the window.
I'm using Oracle JDK 1.8.0_60 in Linux.
This seems to be a Spinner bug, I'm getting much better results if I use TextFields instead.
Example:
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.stage.Stage;
public class GridTest extends Application {
#Override
public void start(final Stage stage) throws Exception {
final GridPane grid = new GridPane();
grid.setHgap(5);
grid.setVgap(5);
grid.setPadding(new Insets(10, 10, 10, 10));
ColumnConstraints cc = new ColumnConstraints();
cc.setMinWidth(GridPane.USE_PREF_SIZE);
grid.getColumnConstraints().add(cc);
cc = new ColumnConstraints();
cc.setMinWidth(GridPane.USE_PREF_SIZE);
cc.setHgrow(Priority.ALWAYS);
grid.getColumnConstraints().add(cc);
grid.add(new Label("Something:"), 0, 0);
final TextField t1 = new TextField();
grid.add(t1, 1, 0);
grid.add(new Label("Another thing:"), 0, 1);
final TextField t2 = new TextField();
grid.add(t2, 1, 1);
final Button b = new Button("A button");
b.setMaxWidth(Double.MAX_VALUE);
grid.add(b, 0, 2, 2, 1);
stage.setScene(new Scene(grid, 400, 150));
stage.show();
}
public static void main(final String... args) {
launch(args);
}
}
But replace the TextFields with Spinners and all hell breaks loose...

Categories

Resources