Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Achieve Unique Column Width for each Cell in Different Rows with a GridPane?

I am trying to model credit card data in JavaFx using a GridPane:

My model contains 3 rows (Note: each field is comprised of label + text field):

Row 1: First name and last name (4 fields)

Row 2: Credit card number (2 fields)

Row 3: Expiration date - month, year + CVV (6 fields)

See screenshot below:

Card Data Model

I was reading this tutorial which states:

All cells in the same row will have the same height, and all cells in the same column will have the same width. Different rows can have different heights and different columns can have different widths.

Are there any workarounds to to have different size columns on a row by row basis in a GridPane?

like image 478
Bradford Griggs Avatar asked Nov 23 '21 23:11

Bradford Griggs


People also ask

What is GridPane in java?

GridPane lays out its children within a flexible grid of rows and columns. If a border and/or padding is set, then its content will be layed out within those insets. A child may be placed anywhere within the grid and may span multiple rows/columns.

How do you have different cell widths in the same column?

To change the width of a column in Excel, click a cell in the column and click "Home" on the ribbon menu. Under "Cells," click "Format" and click "Column Width" under "Cell Size." Enter the desired width and click "OK." Experiment with appropriate column widths to find one that works for your needs.

How do I add a column to a GridPane in JavaFX?

This feature exists in the JavaFX Scene Builder by right clicking on the GridPane and selecting GridPane, then it will show a list of options: Add Row Above, Add Row Below, Add Column After, Add Column Before.

How can you increase the width of a particular column?

Set a column to a specific width Select the column or columns that you want to change. On the Home tab, in the Cells group, click Format. Under Cell Size, click Column Width. In the Column width box, type the value that you want.

How many columns do I need to span a grid?

With a common divider you can create the right number of columns to accommodate each grid area. In my example below, I created 400 columns of .25% width each (400 * .25 = 100%). It then spanned grid areas across the correct number of columns:

How do I create a grid with three different lengths?

To make this work you need to find a common divider for all three lengths (42.5%, 48.75% and 52.5%). With a common divider you can create the right number of columns to accommodate each grid area. In my example below, I created 400 columns of .25% width each (400 * .25 = 100%).

How many columns can I create with a common divider?

With a common divider you can create the right number of columns to accommodate each grid area. In my example below, I created 400 columns of .25% width each (400 * .25 = 100%).

How much grid gap do I need for a 50-50 split?

The 2.5% grid gap works in the first two rows. But in all following rows, where the items are 50-50, there's no room for the 2.5% gap. To make this work you need to find a common divider for all three lengths (42.5%, 48.75% and 52.5%).


2 Answers

For the specific layout in the image, I would use a VBox with HBox for rows:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.geometry.Insets;
import javafx.geometry.Pos;

public class App extends Application {

    @Override
    public void start(Stage stage) {

        Label lblFirst = new Label("First");
        Label lblLast = new Label("Last");
        Label lblNumber = new Label("Card Number");
        Label lblMonth = new Label("Month");
        Label lblYear = new Label("Year");
        Label lblCVV = new Label("CVV");
        
        TextField txtFirst = new TextField();
        TextField txtLast = new TextField();
        TextField txtNumber = new TextField();
        TextField txtMonth = new TextField();
        TextField txtYear = new TextField();
        TextField txtCVV = new TextField();

        HBox row1 = new HBox(10);
        HBox row2 = new HBox(10);
        HBox row3 = new HBox(10);
        
        row1.getChildren().add(createCell(lblFirst, txtFirst));
        row1.getChildren().add(createCell(lblLast, txtLast));
        
        row2.getChildren().add(createCell(lblNumber, txtNumber));
        
        row3.getChildren().add(createCell(lblMonth, txtMonth));
        row3.getChildren().add(createCell(lblYear, txtYear));
        row3.getChildren().add(createCell(lblCVV, txtCVV));
        
        VBox rows = new VBox(10, row1, row2, row3);
        
        StackPane.setMargin(rows, new Insets(10));
        
        StackPane root = new StackPane(rows);

        Scene scene = new Scene(root);

        stage.setScene(scene);
        stage.show();
    }

    private static HBox createCell(Label label, TextField text) {
        HBox pane = new HBox(5, label, text);
        label.setMinWidth(Pane.USE_PREF_SIZE);
        text.setMinWidth(50);
        pane.setAlignment(Pos.CENTER);
        HBox.setHgrow(pane, Priority.ALWAYS);
        HBox.setHgrow(text, Priority.ALWAYS);
        return pane;
    }

    public static void main(String[] args) {
        launch();
    }

}

Output:

like image 112
Oboe Avatar answered Nov 09 '22 17:11

Oboe


+1 for what @JamesD suggested and @Oboe answer. Ideally I would separate each row layout, to handle it in easy way than making it complex using only one GridPane.

Having said that, if you want to go with or learn about how you can do the similar layouting using one GridPane, the below implemenation may give you a quick idea.

Firstly split your layout into the required columns, to figure out how many total columns you need. (as in the below image)

enter image description here

Now you will know which node will sit in which column and how many columns it will occupy (colspan)

I will explain for one node:

Lets say you want insert the field of first name. If you notice in the picture, it is in rowIndex: 0, columnIndex: 1 and it is occupying 4 columns, so the colSpan value will be 4. Here we are not combining any rows, so the rowSpan value will be always 1.

pane.add(getField(), 1, 0, 4, 1); // node, colIndex, rowIndex, colSpan, rowSpan

Similarly you can relate the rest of the nodes layouting. And also for more precising you can set the prefered width of each column using ColumnConstraints. Below is the complete code for the layout & constraints:

enter image description here

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class CreditCardPaneDemo extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        VBox root = new VBox();
        root.setPadding(new Insets(5));
        root.setSpacing(10);
        Scene scene = new Scene(root,300,200);
        stage.setScene(scene);
        stage.setTitle("CreditCard");
        stage.show();

        GridPane pane = new GridPane();
        pane.setStyle("-fx-border-color:black;-fx-border-width:1px;-fx-background-color:yellow");
        pane.setPadding(new Insets(5));
        pane.setHgap(5);
        pane.setVgap(5);

        pane.add(getLabel("First"), 0, 0, 1, 1);
        pane.add(getField(), 1, 0, 4, 1);
        pane.add(getLabel("Last"), 5, 0, 1, 1);
        pane.add(getField(), 6, 0, 2, 1);

        pane.add(getLabel("Card Number"), 0, 1, 3, 1);
        pane.add(getField(), 3, 1, 5, 1);

        pane.add(getLabel("Month"), 0, 2, 2, 1);
        pane.add(getField(), 2, 2, 2, 1);
        pane.add(getLabel("Year"), 4, 2, 1, 1);
        pane.add(getField(), 5, 2, 1, 1);
        pane.add(getLabel("CVV"), 6, 2, 1, 1);
        pane.add(getField(), 7, 2, 1, 1);

        pane.getColumnConstraints().addAll(getCc(70), getCc(20), getCc(80), getCc(20), getCc(25), getCc(90), getCc(80), getCc(100));

        CheckBox gridLines = new CheckBox("Show grid lines");
        gridLines.selectedProperty().addListener((obs, old, val) -> pane.gridLinesVisibleProperty().set(val));
        root.getChildren().addAll(gridLines, pane);
    }

    private ColumnConstraints getCc(double width) {
        ColumnConstraints cc = new ColumnConstraints();
        cc.setPrefWidth(width);
        return cc;
    }

    private Label getLabel(String txt) {
        Label lbl = new Label(txt);
        lbl.setMinWidth(Region.USE_PREF_SIZE);
        return lbl;
    }

    private TextField getField() {
        TextField field = new TextField();
        field.setMaxWidth(Double.MAX_VALUE);
        return field;
    }
}
like image 41
Sai Dandem Avatar answered Nov 09 '22 16:11

Sai Dandem