Vbox not filling up all of the available space in a gridpane - java

I am currently developing a messenger in javafx. my general layout is a gridpane with a customized Vbox containing a ListView and a Textfield. The problem is that as you can see below there is a big emty area beneath the textfield. I already tried setting the rowspan to 2, which didn't work.
The important Code:
Main:
chatBox = new ChatBox();
gridPane.add(chatBox, 1, 0, 1, 2);
ChatBox(extends Vbox):
private static ListView<Message> messages;
private TextField inputField;
public ChatBox() {
inputField = new TextField();
messages = new ListView<>();
init();
getChildren().addAll(messages, inputField);
}

Try adding this in the ChatBox class:
VBox.setVgrow(messages, Priority.ALWAYS);
And add this in the main class:
GridPane.setVgrow(chatBox, Priority.ALWAYS);

You need to set the vgrow using RowConstraints. Assuming your first row contains the ListView that is supposed to take all the available space:
RowConstraints constraints = new RowConstraints();
constraints.setVgrow(Priority.ALWAYS);
gridPane.getRowConstraints().addAll(constraints, new RowConstraints());

In order to force the list view to take all the height available in its parent, you can use the following method:
messages.setMaxHeight(Double.MAX_VALUE);
If the problem comes from the VBox, its maxHeight can also be modified with the same method.

Related

How do I make all the fields in my javafx form clickable using GridPane and HBox?

I want to make a form with three sections, two with fields and one with buttons.
public class Form extends Application{
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
StackPane root = new StackPane();
GridPane fp = new GridPane();
fp.setAlignment(Pos.TOP_CENTER);
fp.setHgap(6);
fp.setVgap(6);
fp.add(new Label("Name: "), 0, 0);
TextField name = new TextField();
name.setPrefWidth(450);
fp.add(name, 1, 0);
GridPane sp = new GridPane();
sp.setAlignment(Pos.CENTER);
sp.setHgap(6);
sp.setVgap(6);
sp.add(new Label("Another Name: "), 1, 0);
TextField anothername = new TextField();
anothername.setPrefWidth(120);
sp.add(anothername, 2, 0);
HBox hbox = new HBox();
hbox.setAlignment(Pos.BOTTOM_CENTER);
Button btn1 = new Button("Button 1");
hbox.getChildren().add(btn1);
Scene scene = new Scene(root, 500, 500);
root.getChildren().addAll(fp, sp, hbox);
stage.setScene(scene);
stage.show();
}
}
formatting and some text might be off but that is my general solution. I made a root stack pane to hold all the parts of my form. I then made two grid panes to hold text fields and an hbox to hold my buttons along the bottom.
example of how it looks
My problem is that only the name field can be clicked. If I try to click another name field it wont work. I can press tab to cycle through the fields and button but I want to be able to click on each field individually. Is there a better way to create one scene with multiple panes or hboxes? I am also open to only having one grid pane, but I thought having two would be easier for formatting since I want to separate different fields. Thank you!
The issue you're facing is caused by your using a StackPane as the root element of your scene.
A StackPane, as the name suggests, stacks its children one on top of the other. Any children placed on top will be the ones receiving events (such as clicking on the anothername field).
You have added 3 nodes as children of your StackPane:
GridPane #1 fp
GridPane #2 sp
HBox hbox
Since the HBox was added last, it is the only node that can receive click events.
Using your example, I've added borders to each of the 3 items above to illustrate how JavaFX is laying them out:
As you can see, each child of the StackPane get resized to fill the entire area (I used different widths for the borders so you can see them all).
You can try this yourself by adding the following code before you show your stage:
fp.setStyle("-fx-border-color: green; -fx-border-width: 15px");
sp.setStyle("-fx-border-color: blue; -fx-border-width: 10px");
hbox.setStyle("-fx-border-color: red; -fx-border-width: 5px");
To solve this, you will need to rethink your layout entirely; a StackPane is certainly not the correct layout pane to use in your case.
I highly recommend working through the examples in Oracle's Working With Layouts in JavaFX tutorial to get a better grasp on how to best layout your scene.

Returning a node from a cell on GridPane. (JavaFX)

I have a school project or something like that and I am trying to make a sign up panel for users. This panel opens when user clicks on sign up. It looks like this.
What I am trying to do is I want to disable that Create Button and It will be enabled only if there are 3 checks on the dialog.
I am using a GridPane on Dialog and I was thinking about returning those certain nodes (Checks which are ImageViews) at those cells and check whether the condition is true. However, I could not figure out how to return a node from GridPane. If you have any other approach for this problem it is fine too.
This is the code's relevant part.
public void SignUp(){
//Create the custom dialog.
Dialog signUpDialog = new Dialog();
//Dialog Title
signUpDialog.setTitle("Sign Up");
//Setting "OK" button type.
ButtonType buttonTypeCreate = new ButtonType("Create", ButtonBar.ButtonData.OK_DONE);
//Adding Button types.
signUpDialog.getDialogPane().getButtonTypes().addAll(buttonTypeCreate, ButtonType.CANCEL);
//Creating the GridPane.
GridPane gridPane = new GridPane();
gridPane.setHgap(10);
gridPane.setVgap(10);
gridPane.setPadding(new Insets(20, 150, 10, 10));
//Setting the Check Icon.
Image imageCheck = new Image("resources/check_icon.png");
//Setting 3 different ImageViews for Check Icon because can't add duplicates to GridPane.
ImageView imageViewCheck1 = new ImageView(imageCheck);
ImageView imageViewCheck2 = new ImageView(imageCheck);
ImageView imageViewCheck3 = new ImageView(imageCheck);
//Setting the X Icon.
Image imageX = new Image("resources/x_icon.png");
//Setting 3 different ImageViews for X Icon because can't add duplicates to GridPane.
ImageView imageViewX1 = new ImageView(imageX);
ImageView imageViewX2 = new ImageView(imageX);
ImageView imageViewX3 = new ImageView(imageX);
//TextField for User ID.
TextField textFieldDialogUserID = new TextField();
textFieldDialogUserID.setPromptText("User ID");
textFieldDialogUserID.setAlignment(Pos.CENTER_RIGHT);
//PasswordField for Password.
PasswordField passwordFieldDialogPassword = new PasswordField();
passwordFieldDialogPassword.setPromptText("Password");
passwordFieldDialogPassword.setAlignment(Pos.CENTER_RIGHT);
//PasswordField for Confirm Password.
PasswordField passwordFieldDialogConfirmPassword = new PasswordField();
passwordFieldDialogConfirmPassword.setPromptText("Confirm Password");
passwordFieldDialogConfirmPassword.setAlignment(Pos.CENTER_RIGHT);
gridPane.add(new Label("User ID"), 0, 0);
gridPane.add(textFieldDialogUserID, 1, 0);
gridPane.add(new Label("Password"), 0, 1);
gridPane.add(passwordFieldDialogPassword, 1, 1);
gridPane.add(new Label("Confirm Password"), 0, 2);
gridPane.add(passwordFieldDialogConfirmPassword, 1, 2);
gridPane.add(imageViewX1,2,0);
gridPane.add(imageViewX2,2,1);
gridPane.add(imageViewX3,2,2);
signUpDialog.getDialogPane().setContent(gridPane);
Stage signUpStage = (Stage) signUpDialog.getDialogPane().getScene().getWindow();
signUpStage.getIcons().add(new Image("resources/application_icon.png"));
Optional<Pair<String, String>> result = signUpDialog.showAndWait();
}
Create an appropriate BooleanBinding which expresses when the button should be disabled. You can use the Bindings utility class to create the expression, including comparison, ands and ors. To make the code more readable do a static import of the functions.
Get the create button from your panel and bind the boolean expression to the disable property of your button.
If any of the values change the JavaFX framework will automatically reevaluate the bindings and update the button's state accordingly.
import static javafx.beans.binding.Bindings.*;
BooleanBinding notComplete = or(
equal(textFieldDialogUserID.textProperty(), null),
equal(passwordFieldDialogPassword.textProperty(), null));
Node createButton = signUpDialog.getDialogPane().lookupButton(buttonTypeCreate);
createButton.disableProperty().bind(notComplete);
You can use the same mechanism to control the visibility of each checkmark. Create a 'incomplete' BooleanBinding for each textfield and bind it with a not binding to the visible property of the checkmark. Use all these BooleanBindings in a compound or to determine the button state. This way the button state and checkmarks will always be in sync.
I could not figure out how to return a node from GridPane.
gridPane.getChildren()
provides the list of nodes, but you already have your components textFieldDialogUserID, passwordFieldDialogPassword, passwordFieldDialogConfirmPassword.
=> Add an action listener for each of them, that checks the values when its value is changed. depending on the result, enable/disable the Create button (per default, it should be disabled).
you can have an example : http://docs.oracle.com/javafx/2/ui_controls/text-field.htm

Nodes in VBox don't have the same width

I use a VBox to provide 3 Input fields.
They are all set up like this:
tf = new TextField();
tf.setPrefWidth(Double.MAX_VALUE);
sp = new Spinner<Integer>(0, 3, 1);
sp.setPrefWidth(Double.MAX_VALUE);
dp = new DatePicker(LocalDate.now());
dp.setPrefWidth(Double.MAX_VALUE);
vbox.getChildren().addAll(tf, sp, dp);
The width of the TextField and the DatePicker is equal. However the Spinner is slightly shorter.
How can I get all to the same size?
Note: Using .setMinWidth(Control.USE_PREF_SIZE); led to a layout Problem with the parent node (which does extend StackPane) of the VBox.
Explination: The Component with the border extends StackPane and can only hold one node. The "node" in this case is a VBox, that holds the 3 Input fields and the Buttons.
Use setMaxWidth on the individual controls and call setFillWidth(true) on the VBox itself:
tf = new TextField();
tf.setMaxWidth(Double.MAX_VALUE);
sp = new Spinner<Integer>(0, 3, 1);
sp.setMaxWidth(Double.MAX_VALUE);
dp = new DatePicker(LocalDate.now());
dp.setMaxWidth(Double.MAX_VALUE);
vBox.setFillWidth(true);
vbox.getChildren().addAll(tf, sp, dp);

Display images dynamically in a ScrollPane

I want to add multiple images in a ScrollPane when clicking a button. Now when I click the button a new rectangle is created and fitted with a new image.
The problem is the scrollbar is not displaying when a new image is added.
Here is the code:
#FXML
public void handleButtonPause(){
Rectangle r = new Rectangle();
if(counterIm==0){
//Ap1.setMinSize(Sp1.getWidth(), Sp1.getHeight() - 10);
r.setY(Sp1.getHeight() *((double)1/36));
r.setWidth(Sp1.getWidth()*0.75);
rectWidth=r.getWidth();
r.setHeight(Sp1.getHeight()/6);
rectHeight=r.getHeight();
}
else {
r.setY(Sp1.getHeight()*((7*counterIm+1)/36));
r.setWidth(rectWidth);
r.setHeight(rectHeight);
}
r.setX(Sp1.getWidth() / 10);
r.setArcWidth(20);
r.setArcHeight(20);
Ap1.getChildren().add(r);
Image image = new Image(new File("C:\\Users\\Manuel\\Desktop\\error.png").toURI().toString());
r.setFill(new ImagePattern(image));
Sp1.setVvalue(1);
counterIm=counterIm+1;
I don't know how your composition looks like.
A good approach could be to put the images into a VBox and put the VBox into the ScrollPane.
And check if you have set the VBar Policy of your SrollPane:
srollbar.setVbarPolicy(ScrollBarPolicy.AS_NEEDED);
You can also set the maximal height of the VBox to double maximum to make it sure it will always grow vertically:
vbox.setMaxHeight(Double.MAX_VALUE);

ImageView in JavaFX not keeping proper size

I am using this format to place an image as a background picture.
final VBox mainroot = new VBox();
mainroot.getChildren().addAll(backbutton,heroship);
final StackPane mainstackPane = new StackPane();
mainstackPane.getChildren().addAll(iv2,mainroot);
final HBox hbox = new HBox(mainstackPane);
iv2 is my image iteself, created like this
final Image imagegame = new Image(bcolor,width,height, false, false);
ImageView iv2 = new ImageView();
iv2.setImage(imagegame);
iv2.setPreserveRatio(true);
iv2.setFitWidth(width);
iv2.setFitHeight(height);
As well, I am adding a set amount of Labels using an array and a for loop,
Label[] alienship = new Label[10];
for (int i=0;i<alienship.length;i++)
{
mainroot.getChildren().add(alienship[i]);
}
My problem is, every time I change the array of Labels size lets say from 10 to 20, the image itself shifts downwards and I would have to translate it back up to fit.
I have tried using both a VBox and an HBox but I am not able to see a difference in my result.
I have also tried to use .setFitWidth() and .setFitHeight() but nothing helped.
With Label[] alienship = new Label[10];
Result: http://puu.sh/eAihN/c5c7f38ef0.jpg
(In this case I would have used .setTranslate to allign it back up.
With Label[] alienship = new Label[20];
Result: http://puu.sh/eAiqz/3b4280b63b.jpg
What can I do to fix this issue and ensure it stays alligned no matter what size I set the array to?
Thanks.
Problem
The problem is not with the ImageView, but with the Layout/Container that you chose to add heroship and alienship.
VBox is a layout whose height depends on the no of children and height of each child. When the number of alienship increases the VBox height will increase to accommodate all the children.
Solution
You must consider a layout which can add any number of children, without any effect on the width and height of the container. Consider StackPane
Quick fix is to make the VBox as the parent of the StackPane. Add the Image and the space ships to the StackPane, then add the Button and the StackPane to your VBox. Finally adding the VBox to your HBox.
final StackPane mainstackPane = new StackPane();
mainstackPane.getChildren().addAll(iv2, heroship);
final VBox mainroot = new VBox();
mainroot.getChildren().addAll(backbutton, mainstackPane);
final HBox hbox = new HBox(mainroot);
Add all your alienships to the StackPane instead of adding them to the VBox
Label[] alienship = new Label[10];
for (int i=0;i<alienship.length;i++)
{
mainstackPane.getChildren().add(alienship[i]);
}

Categories

Resources