Search code examples
javafxfontsdropdownchoice

JavaFX Update font with ChoiceBox


I have a ScrollPane with text, and I need to update the color & font. The color picker works ok. My problem is with the ChoiceBox for selecting the fonts. It changes when I first select a font, but when I select another option, it will not update the font. Here is the code:

package helloearthrisemain;

import javafx.animation.Interpolator;
import javafx.animation.Timeline;
import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.geometry.VPos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.ColorPicker;
import javafx.scene.control.ScrollPane;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.scene.text.TextAlignment;
import javafx.stage.Stage;
import javafx.util.Duration;

public class HelloEarthRiseMain extends Application {

    @Override
    public void start(Stage stage) {

        String message
                = "Earthrise at Christmas: "
                + "[Forty] years ago this Christmas, a turbulent world "
                + "looked to the heavens for a unique view of our home "
                + "planet. This photo of Earthrise over the lunar horizon "
                + "was taken by the Apollo 8 crew in December 1968, showing "
                + "Earth for the first time as it appears from deep space. "
                + "Astronauts Frank Borman, Jim Lovell and William Anders "
                + "had become the first humans to leave Earth orbit, "
                + "entering lunar orbit on Christmas Eve. In a historic live "
                + "broadcast that night, the crew took turns reading from "
                + "the Book of Genesis, closing with a holiday wish from "
                + "Commander Borman: \"We close with good night, good luck, "
                + "a Merry Christmas, and God bless all of you -- all of "
                + "you on the good Earth.\"";

        //Color picker
        ColorPicker colorPicker = new ColorPicker();
        colorPicker.setValue(Color.CORAL);
        colorPicker.setLayoutX(400);
        colorPicker.setLayoutY(200);

        //List of fonts
        ObservableList fonts = FXCollections.observableArrayList(
        Font.getFamilies());

        //Select font
        ChoiceBox selectFont;
        selectFont = new ChoiceBox();
        selectFont.setValue("SansSerif");
        selectFont.setLayoutX(600);
        selectFont.setLayoutY(200);
        selectFont.setItems(fonts);

        // Reference to the Text
        Text textRef = new Text(message);
        textRef.setLayoutY(100);
        textRef.setTextOrigin(VPos.TOP);
        textRef.setTextAlignment(TextAlignment.JUSTIFY);
        textRef.setWrappingWidth(600);
        textRef.setFill(colorPicker.getValue());
        textRef.setFont(Font.font("SansSerif", FontWeight.BOLD, 24));

        //Action for selecting text color.
        colorPicker.setOnAction(new EventHandler() {
            public void handle(Event t) {
                textRef.setFill(colorPicker.getValue());               
            }
        });

Action for selecting font. I believe this is where the problem is. It will change for first selection, but not when I make another selection.

    selectFont.getSelectionModel().selectedIndexProperty()
            .addListener(new ChangeListener<Number>() {
              public void changed(ObservableValue ov, Number value, Number new_value) {
                textRef.setFont(Font.font(selectFont.getAccessibleText(), FontWeight.BOLD, 24));
              }
            });

//I tried this as well. This code did not work either.


/*
        selectFont.setOnAction(new EventHandler() {
            public void handle(Event u) {
                textRef.setFont(Font.font(selectFont.getAccessibleText(), FontWeight.BOLD, 24));
            }
        });
                */

        // Provides the animated scrolling behavior for the text
        TranslateTransition transTransition = new TranslateTransition(new Duration(75000), textRef);
        transTransition.setToY(-820);
        transTransition.setInterpolator(Interpolator.LINEAR);
        transTransition.setCycleCount(Timeline.INDEFINITE);

        // Create a ScrollPane containing the text
        ScrollPane scrollPane = new ScrollPane();
        scrollPane.setLayoutX(450);
        scrollPane.setLayoutY(400);
        scrollPane.setPrefWidth(600);
        scrollPane.setPrefHeight(400);
        scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
        scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.NEVER);
        scrollPane.setPannable(true);
        scrollPane.setContent(textRef);


        // Combine ImageView and Group
        Group root = new Group(scrollPane, colorPicker, selectFont);
        Scene scene = new Scene(root);

        stage.setScene(scene);
        stage.setTitle("Hello Earthrise");
        stage.setMaximized(true);
        stage.show();

        // Start the text animation
        transTransition.play();
    }

        public static void main(String[] args) {
        Application.launch(args);`enter code here`
    }
}

Solution

  • I tried your code and even the first selection is actually not working, you have that impression because if you go in debug you'll notice that selectFont.getAccessibleText() returns null. And so Font.font(selectFont.getAccessibleText(), FontWeight.BOLD, 24) will overwrite the default SansSerif, and as on next selection the value remains null you'll not see any apparent change.

    I made it work by doing this instead:

        ObservableList<String> fonts = FXCollections.observableArrayList(Font.getFamilies());
    
        // Select font
        ChoiceBox<String> selectFont;
        selectFont = new ChoiceBox<>();
        selectFont.setValue("SansSerif");
        selectFont.setLayoutX(600);
        selectFont.setLayoutY(200);
        selectFont.setItems(fonts);
        selectFont.getSelectionModel().selectedItemProperty().addListener((obs, oldValue, newValue) -> textRef.setFont(Font.font(newValue, FontWeight.BOLD,24)));
    

    Hope it helped!