ADDITIONAL SYSTEM INFORMATION :
Operating System is windows 10, but bug is located in the Skin code, so OS independent.
We have seen the bug in javaFX 11 and 12.
A DESCRIPTION OF THE PROBLEM :
When you set css styles (-fx-padding and -fx-pref-height) on a TextField the baseline is not computed correctly. The used font has also be taken into account. Some fonts have more effect in this bug than others.
The same problem can be found in the ComboBoxSkin, too.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the following class. It creates a HBox with baseline alignment on a label and a TextField. Then it uses a font, where the problem is greater than the usual 'System' font. At least, css styles for padding and pref-height is set.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The baseline (visualized in the example program) should be the baseline for both the Label and the TextField.
ACTUAL -
The computation of the TextField should be correct. The text should have the same Y start-position, as the HBox aligns by the baseline.
---------- BEGIN SOURCE ----------
package baselinecomputationerror;
import javafx.application.Application;
import javafx.application.Platform;
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.control.skin.TextFieldSkin;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Line;
import javafx.scene.text.Text;
import javafx.scene.transform.Scale;
import javafx.stage.Stage;
public class Main extends Application
{
private static final Label label = new Label("TextField");
private static final TextField control = new TextField("TextField");
private static final Line baseLine = new Line();
private static final HBox rootPane = new HBox(label, control, baseLine);
public static void main(String[] args)
{
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception
{
baseLine.setManaged(false);
//control.setSkin(new BetterTextFieldSkin(control));
rootPane.setPadding(new Insets(5));
rootPane.getTransforms().add(new Scale(4, 4));
rootPane.setAlignment(Pos.BASELINE_LEFT);
rootPane.setStyle("-fx-font-family: Tahoma; -fx-font-size: 18");
control.setStyle("-fx-padding: 0 5 1 7;-fx-pref-height: 1.7em;");
baseLine.setStyle("-fx-stroke: #ff033390;");
Platform.runLater(() -> {
baseLine.setStartX(label.getLayoutX());
baseLine.setStartY(label.getLayoutY() + label.getBaselineOffset() + 1.0);
baseLine.setEndX(control.getLayoutX() + control.getWidth());
baseLine.setEndY(baseLine.getStartY());
});
primaryStage.setTitle("Baseline Computation Error");
primaryStage.setScene(new Scene(rootPane, 1200, 700));
primaryStage.show();
}
private static class BetterTextFieldSkin extends TextFieldSkin
{
BetterTextFieldSkin(TextField control)
{
super(control);
}
@Override
public double computeBaselineOffset(double topInset, double rightInset, double bottomInset, double leftInset)
{
// very hacky, but it works for accessing textNode in this demo
Text textNode = (Text) ((Pane) this.getChildren().get(0)).getChildren().get(1);
return super.computeBaselineOffset(topInset, rightInset, bottomInset, leftInset) + textNode.getBoundsInParent().getMinY();
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
You can workaround the bug with uncomment the line
//control.setSkin(new BetterTextFieldSkin(control));
It is very hacky, as the problematic code is in the Skin on a private Text node.
FREQUENCY : always
Operating System is windows 10, but bug is located in the Skin code, so OS independent.
We have seen the bug in javaFX 11 and 12.
A DESCRIPTION OF THE PROBLEM :
When you set css styles (-fx-padding and -fx-pref-height) on a TextField the baseline is not computed correctly. The used font has also be taken into account. Some fonts have more effect in this bug than others.
The same problem can be found in the ComboBoxSkin, too.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the following class. It creates a HBox with baseline alignment on a label and a TextField. Then it uses a font, where the problem is greater than the usual 'System' font. At least, css styles for padding and pref-height is set.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The baseline (visualized in the example program) should be the baseline for both the Label and the TextField.
ACTUAL -
The computation of the TextField should be correct. The text should have the same Y start-position, as the HBox aligns by the baseline.
---------- BEGIN SOURCE ----------
package baselinecomputationerror;
import javafx.application.Application;
import javafx.application.Platform;
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.control.skin.TextFieldSkin;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Line;
import javafx.scene.text.Text;
import javafx.scene.transform.Scale;
import javafx.stage.Stage;
public class Main extends Application
{
private static final Label label = new Label("TextField");
private static final TextField control = new TextField("TextField");
private static final Line baseLine = new Line();
private static final HBox rootPane = new HBox(label, control, baseLine);
public static void main(String[] args)
{
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception
{
baseLine.setManaged(false);
//control.setSkin(new BetterTextFieldSkin(control));
rootPane.setPadding(new Insets(5));
rootPane.getTransforms().add(new Scale(4, 4));
rootPane.setAlignment(Pos.BASELINE_LEFT);
rootPane.setStyle("-fx-font-family: Tahoma; -fx-font-size: 18");
control.setStyle("-fx-padding: 0 5 1 7;-fx-pref-height: 1.7em;");
baseLine.setStyle("-fx-stroke: #ff033390;");
Platform.runLater(() -> {
baseLine.setStartX(label.getLayoutX());
baseLine.setStartY(label.getLayoutY() + label.getBaselineOffset() + 1.0);
baseLine.setEndX(control.getLayoutX() + control.getWidth());
baseLine.setEndY(baseLine.getStartY());
});
primaryStage.setTitle("Baseline Computation Error");
primaryStage.setScene(new Scene(rootPane, 1200, 700));
primaryStage.show();
}
private static class BetterTextFieldSkin extends TextFieldSkin
{
BetterTextFieldSkin(TextField control)
{
super(control);
}
@Override
public double computeBaselineOffset(double topInset, double rightInset, double bottomInset, double leftInset)
{
// very hacky, but it works for accessing textNode in this demo
Text textNode = (Text) ((Pane) this.getChildren().get(0)).getChildren().get(1);
return super.computeBaselineOffset(topInset, rightInset, bottomInset, leftInset) + textNode.getBoundsInParent().getMinY();
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
You can workaround the bug with uncomment the line
//control.setSkin(new BetterTextFieldSkin(control));
It is very hacky, as the problematic code is in the Skin on a private Text node.
FREQUENCY : always