JDK-8119257 : GridPane oddness with row alignment set to VPos.BASELINE
  • Type: Bug
  • Component: javafx
  • Sub-Component: scenegraph
  • Affected Version: 8
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2013-05-29
  • Updated: 2015-06-17
  • Resolved: 2013-06-04
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8
8Fixed
Related Reports
Relates :  
Description
Using GridPane for a complex layout of controls in our application I found some odd behaviour surrounding VPos.BASELINE alignment set on all row constraints in the grid.

Firstly using baseline alignment with an hgap and/or a vgap set sometimes causes an extra gap at the outside of the grid.

Secondly turning on grid lines totally messes up the layout of nodes in the grid.

Run the following test case. 

At first everything is nicely lined up. Click on the "Grid Lines" button and you will see with the grid lines visible that there is actually an extra vgap at the bottom. Then, anything that will cause the grid to re-layout will seem to re-position the first row in totally the wrong place (like resizing the stage). 

Finally, you can select the "Default  Row Align" checkbox to see the odd behaviours disappear once the row constraints are removed.

*******************************************************************

import java.util.ArrayList;
import java.util.List;

import javafx.application.Application;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.binding.Bindings;
import javafx.collections.FXCollections;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.geometry.VPos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Label;
import javafx.scene.control.RadioButton;
import javafx.scene.control.TextField;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.RowConstraints;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;


public class GridPaneTest extends Application {
	
	@Override public void start(final Stage primaryStage) throws Exception {
		
		final GridPane grid = new GridPane();
		grid.setHgap(20);
		grid.setVgap(20); 
		
		RowConstraints rc = new RowConstraints();
		rc.setValignment(VPos.BASELINE);
		ChoiceBox<String> comboBox = new ChoiceBox<>(
		      FXCollections.observableArrayList("Short", "Longer", "Really Long"));
		comboBox.getSelectionModel().select(0);
		grid.getRowConstraints().add(rc);
		grid.add(new BaseHBox(new Label("test1: "), comboBox), 0, 0);
		
		rc = new RowConstraints();
		rc.setValignment(VPos.BASELINE);
		grid.getRowConstraints().add(rc);
		grid.add(new BaseHBox(new Label("test2: "), new Button("Grid Lines") {
         {setOnAction(new EventHandler<ActionEvent>() {
            @Override public void handle(ActionEvent event) {
               grid.setGridLinesVisible(!grid.isGridLinesVisible());
            }
         });}
      }), 0, 1);
		
		rc = new RowConstraints();
		rc.setValignment(VPos.BASELINE);
		grid.getRowConstraints().add(rc);
		grid.add(new BaseHBox(new Label("test3: "), new TextField("testing...") {
         {setPrefColumnCount(6);}
      }), 0, 2);
		
		rc = new RowConstraints();
		rc.setValignment(VPos.BASELINE);
		grid.getRowConstraints().add(rc);
		ToggleGroup tGroup = new ToggleGroup();
		RadioButton radio1 = new RadioButton("Choice 1");
		RadioButton radio2 = new RadioButton("Choice 2");
		radio1.setToggleGroup(tGroup);
		radio2.setToggleGroup(tGroup);
		grid.add(new BaseHBox(new Label("test4: "), 
	      new VBox(5, radio1, radio2)), 1, 0);
		
		grid.add(new BaseHBox(new Label("test5: "), new CheckBox("Default Row Align") {
		   {final List<RowConstraints> constraints = new ArrayList<>();
		    selectedProperty().addListener(new InvalidationListener() {
            @Override public void invalidated(Observable observable) {
               if ( isSelected() ) {
                  constraints.addAll(grid.getRowConstraints());
                  grid.getRowConstraints().clear();
               } else {
                  grid.getRowConstraints().addAll(constraints);
                  constraints.clear();
               }
            }});}
		}), 1, 1);
		
		CheckBox mainCheck = new CheckBox("Main choice");
		CheckBox subCheck = new CheckBox("Sub choice");
		subCheck.disableProperty().bind(Bindings.not(mainCheck.selectedProperty()));
		VBox.setMargin(subCheck, new Insets(0, 0, 0, 20));
		grid.add(new BaseHBox(new Label("test6: "),new VBox(5, mainCheck, subCheck)), 1, 2);
		
		primaryStage.setScene( new Scene(grid) );
		
		primaryStage.sizeToScene();
		primaryStage.centerOnScreen();
		
		primaryStage.show();
		
	}
	
	public static void main(String[] args) throws Exception{
	   launch(args);
   }
	
	private static class BaseHBox extends HBox {
	   public BaseHBox(Node ... nodes) {
	      super(5, nodes);
	      setAlignment(Pos.BASELINE_LEFT);
	   }
	}
	
}


Comments
There were three issues actually: -first is the number of RowContraints in the test. There are 4 row contraints, but children are only in three rows. If you add more RowContraints to the GridPane, the rows will be there (thus the visible spacing) even if there are no children in them - The actual bug in the baseline computation. That was fixed. - A bug that makes the first baseline computation invalid. This leads to an incorrect window height, as the first computation of the GridPane's height is smaller then the second one. This is tracked by RT-30037.
04-06-2013