Javafx: Cannot Set Font Size Programmatically After Font Being Set by CSS

JavaFX: Cannot set font size programmatically after font being set by CSS

It's by design. For architectural reasons chain of overrides for css works as follows:

default caspian.css < API settings < user's Scene css < user's Parent css < setStyle()

Here is the quote from css reference guide:

The JavaFX CSS implementation applies the following order of precedence; a style from a user agent style sheet has lower priority than a value set from code, which has lower priority than a Scene or Parent style sheet. Inline styles have highest precedence. Style sheets from a Parent instance are considered to be more specific than those styles from Scene style sheets.

Thus, you can achieve your goal by using setStyle() instead of an API call. Try to run the next example:

public void start(Stage stage) {
VBox root = new VBox(10);

Scene scene = new Scene(root, 300, 250);
// font.css: .labelStyleClass { -fx-font-size: 20 }
scene.getStylesheets().add(getClass().getResource("font.css").toExternalForm());

root.getChildren().add(LabelBuilder.create().text("default").build());
root.getChildren().add(LabelBuilder.create().text("font-css").styleClass("labelStyleClass").build());

Label lblApi = LabelBuilder.create().text("font-css-api (doesn't work)").styleClass("labelStyleClass").build();
lblApi.setFont(Font.font(lblApi.getFont().getFamily(), 40));
root.getChildren().add(lblApi);

Label lblStyle = LabelBuilder.create().text("font-css-setstyle (work)").styleClass("labelStyleClass").build();
lblStyle.setStyle("-fx-font-size:40;");
root.getChildren().add(lblStyle);

stage.setTitle("Hello World!");
stage.setScene(scene);
stage.show();
}

Hot to update dynamically font size

Please consider taking a look at the official JavaFX documentation. There you find the code example which answers your question:

Text t = new Text("That's the text");
t.setFont(Font.font ("Verdana", 20));

UPDATE

In your application controller get an instance of your root pane, e.g. AnchorPane and use the setId("") function to set new style for the whole pane (my actionChange is connected with a button on the pane, which triggers the event/change):

public class AppController implements Initializable {
@FXML
private AnchorPane mainPane;

@Override
public void initialize(URL arg0, ResourceBundle arg1) {
// TODO Auto-generated method stub
}

@FXML
public void actionChange() {
mainPane.setId("fancytext");
}
}

When pressing the button, the style for the pane is changed. I just used the font-size as an example. Before, you need to specify the new style in your CSS file:

.root {
-fx-font: 12px Tahoma;
}

#fancytext {
-fx-font: 20px Tahoma;
}

That's before:

Before the button is pressed

That's after the button was pressed:

After the button is pressed

Set Font globally in JavaFX

You can skin your application with CSS as described on the Oracle Website.
Using following syntax you may set the general theme for your application:

.root{
-fx-font-size: 16pt;
-fx-font-family: "Courier New";
-fx-base: rgb(132, 145, 47);
-fx-background: rgb(225, 228, 203);
}

You include the css as followed:

scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());

In JavaFX2.2, how to set the font size for text entered in input fields and table headers?

I found these useful articles by Marco and by Rob

So I

1) manually changed the width of the table column

        <TableColumn text="First Name" prefWidth="90" >
<cellValueFactory>
<PropertyValueFactory property="firstName" />
</cellValueFactory>
</TableColumn>
<TableColumn text="Last Name" prefWidth="90" >
<cellValueFactory>
<PropertyValueFactory property="lastName" />
</cellValueFactory>
</TableColumn>

2) Added a link in the fxml file

  <stylesheets>
<URL value="@tffontsize.css" />
</stylesheets>

3) created a css file tfffontsize.css

.text-field {
-fx-font-size: 12pt;
}
.table-view .column-header{
-fx-font-size: 14;
}

.table-cell {
-fx-font-size: 12px;
}

Sample Image

How to dynamically change font size in UI to always be the same width in JavaFX?

You can use temp Text object to measure text size, and scale the font if it doesn't fit. Something like this:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class Main extends Application {

//maximum width of the text/label
private final double MAX_TEXT_WIDTH = 400;
//default (nonscaled) font size of the text/label
private final double defaultFontSize = 32;
private final Font defaultFont = Font.font(defaultFontSize);

@Override
public void start(Stage primaryStage) {

final TextField tf = new TextField("Label text goes here");

final Label lbl = new Label();
lbl.setFont(defaultFont);
lbl.textProperty().addListener((observable, oldValue, newValue) -> {
//create temp Text object with the same text as the label
//and measure its width using default label font size
Text tmpText = new Text(newValue);
tmpText.setFont(defaultFont);

double textWidth = tmpText.getLayoutBounds().getWidth();

//check if text width is smaller than maximum width allowed
if (textWidth <= MAX_TEXT_WIDTH) {
lbl.setFont(defaultFont);
} else {
//and if it isn't, calculate new font size,
// so that label text width matches MAX_TEXT_WIDTH
double newFontSize = defaultFontSize * MAX_TEXT_WIDTH / textWidth;
lbl.setFont(Font.font(defaultFont.getFamily(), newFontSize));
}

});
lbl.textProperty().bind(tf.textProperty());

final AnchorPane root = new AnchorPane(lbl, tf);
AnchorPane.setLeftAnchor(tf, 0d);
AnchorPane.setRightAnchor(tf, 0d);
AnchorPane.setBottomAnchor(tf, 0d);

primaryStage.setScene(new Scene(root, MAX_TEXT_WIDTH, 200));
primaryStage.show();
}
}

Note that tmpText.getLayoutBounds() returns the bounds that do not include any transformations/effects (if these are needed, you'll have to add text object to temp scene and calculate its bounds in parent).

Text fits
Text fits, again
Text scaled down

Changing the font size of a label in a chart in javafx

Assuming you mean in a pie chart, use

.chart-pie-label {
-fx-font-size: 10pt ;
}

in an external css file. See http://docs.oracle.com/javafx/2/api/javafx/scene/doc-files/cssref.html#piechart

Javafx TableView change Font of an Column programmatically NOT-CSS

Here is a sample app that demonstrates how to do this.

This example uses setTextFill() and setFont() inside the setCellFactory method.

import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javafx.util.Callback;

public class Main extends Application {

private final TableView<Person> table = new TableView<>();
private final ObservableList<Person> data =
FXCollections.observableArrayList(new Person("A", "B"));
final HBox hb = new HBox();

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

@Override
public void start(Stage stage) {
Scene scene = new Scene(new Group());
stage.setWidth(450);
stage.setHeight(550);

TableColumn firstNameCol = new TableColumn("First Name");
firstNameCol.setMinWidth(100);
firstNameCol.setCellValueFactory(
new PropertyValueFactory<>("firstName"));
//Newly added code
firstNameCol.setCellFactory(new Callback<TableColumn, TableCell>() {

@Override
public TableCell call(TableColumn param) {
return new TableCell<Person, String>()
{
@Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);

if(isEmpty())
{
setText("");
}
else
{

setTextFill(Color.RED);
setFont(Font.font ("Verdana", 20));
setText(item);
}
}
};
}
});

TableColumn lastNameCol = new TableColumn("Last Name");
lastNameCol.setMinWidth(100);
lastNameCol.setCellValueFactory(
new PropertyValueFactory<>("lastName"));
lastNameCol.setCellFactory(new Callback<TableColumn, TableCell>() {

@Override
public TableCell call(TableColumn param)
{
return new TableCell<Person, String>()
{
@Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);

if(isEmpty())
{
setText("");
}
else
{

setTextFill(Color.BLUE);
setFont(Font.font ("Verdana", 20));
setText(item);
}
}
};
}
});

table.setItems(data);
table.getColumns().addAll(firstNameCol, lastNameCol);

final Button addButton = new Button("Add");
addButton.setOnAction((ActionEvent e) -> {
data.add(new Person("Z","X"));
});

hb.getChildren().addAll(addButton);
hb.setSpacing(3);

final VBox vbox = new VBox();
vbox.setSpacing(5);
vbox.setPadding(new Insets(10, 0, 0, 10));
vbox.getChildren().addAll(table, hb);

((Group) scene.getRoot()).getChildren().addAll(vbox);

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

public static class Person {

private final SimpleStringProperty firstName;
private final SimpleStringProperty lastName;

private Person(String fName, String lName) {
this.firstName = new SimpleStringProperty(fName);
this.lastName = new SimpleStringProperty(lName);
}

public String getFirstName() {
return firstName.get();
}

public void setFirstName(String fName) {
firstName.set(fName);
}

public String getLastName() {
return lastName.get();
}

public void setLastName(String fName) {
lastName.set(fName);
}
}
}

Sample Image

Set Style & Font Size of Full Screen Exit Hint, JavaFX

Trying to reuse the existing functionality is not a bad idea. But unfortunately this cannot be applied here, because you don't have any control over the message box displayed for full screen. This cannot be done even with the node lookup/traversing to find the correct node, because the message box is not part of the scene graph.

You might be wondering then how it is rendered, its the internal implementation in Scene to provide the box directly to the "Painter" to paint it over the screen.

So instead of relying on "setFullScreenExitHint" method, I would recommend to create your own message box so that you will have full control over all the parameters (display duration, location, font size, styles...).

Below is a full working demo of a custom message box shown on full screen:

Sample Image

import javafx.animation.FadeTransition;
import javafx.animation.PauseTransition;
import javafx.animation.SequentialTransition;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Popup;
import javafx.stage.Stage;
import javafx.util.Duration;

public class FullScreenStageDemo extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
StackPane root = new StackPane();
// Adding a busy background, to showcase the transparency of the message box.
root.setStyle("-fx-background-color: linear-gradient(from 41px 34px to 50px 50px, reflect, #ff7f50 30%, #faebd7 47%);");
primaryStage.setScene(new Scene(root));
primaryStage.setTitle("Full Screen Stage");
primaryStage.setFullScreen(true);
primaryStage.setFullScreenExitHint(""); // Setting empty string will not show the default message box
primaryStage.setOnShown(e->{
Duration displayDuration = Duration.millis(5000); // Adjust as per your need

Label msg = new Label("Welcome to Minesweeper. At left, you can alter the # of rows and columns. At right, set the # of mines. Play is bottom right.");
msg.setWrapText(true);
msg.setStyle("-fx-font-size:15px;-fx-font-family:verdana;-fx-text-fill:#FFFFFF;");

StackPane box = new StackPane(msg);
box.setMaxWidth(500);
box.setStyle("-fx-padding:20px;-fx-background-radius:5px,4px;-fx-background-color:#33333380,#AAAAAA60;-fx-background-insets:0,2;");

Popup popup = new Popup();
popup.getContent().add(box);
popup.show(primaryStage);

PauseTransition pause = new PauseTransition(displayDuration);
FadeTransition fade = new FadeTransition(Duration.millis(1000), box);
fade.setFromValue(1);
fade.setToValue(0);

SequentialTransition overlayTransition = new SequentialTransition();
overlayTransition.getChildren().addAll(pause,fade);
overlayTransition.setOnFinished(event -> popup.hide());
overlayTransition.play();
});
primaryStage.show();
}
}


Related Topics



Leave a reply



Submit