javajavafxtextformattingeclipse-neon

Is there a way to have two different font sizes within the same text line in JavaFX?


I'm making a windows-run-mobile-concept stock market game using Java, and it's JavaFX libraries, and I'd like to have the form of currency on the lower right of the player's current balance, (in my case USD). The catch with this is, is that whenever the player gains a multiple of a thousand dollars in-game, the player's balance gets larger, which means that the string that holds the player's balance is also larger. This causes the fixed position of the string "USD" in the application to be overlapped by the player's current balance.

I've tried simply forcing the program to move the "USD" symbol whenever the number increases by a multiple of one thousand. This, however, seems highly inefficient and I'm willing to bet that there is a simpler way to do this.

    double balance = 12313.00;

    DecimalFormat decimalFormat = new DecimalFormat("#,###");
    String numberAsString = decimalFormat.format(balance);

    Text balanceText = new Text("$" + (numberAsString));
    balanceText.setFont(Font.font("Modernist", 72));
    balanceText.setFill(Color.web("77e6b3"));
    balanceText.setLayoutX(25);
    balanceText.setLayoutY(250);

    Text currencyText = new Text("USD");
    currencyText.setFont(Font.font("Modernist", 36));
    currencyText.setFill(Color.web("77e6b3"));
    currencyText.setLayoutX(275);
    currencyText.setLayoutY(250);

Solution

  • You can use a TextFlow to render rich text in multiple fonts, sizes, styles and colors:

    money

    Sample Code

    import javafx.application.Application;
    import javafx.geometry.Insets;
    import javafx.geometry.VPos;
    import javafx.scene.Scene;
    import javafx.scene.layout.VBox;
    import javafx.scene.paint.Color;
    import javafx.scene.text.*;
    import javafx.scene.text.TextFlow;
    import javafx.stage.Stage;
    
    import java.text.DecimalFormat;
    
    public class MoMoney extends Application {
        @Override
        public void start(Stage stage) throws Exception {
            double balance = 12313.00;
    
            DecimalFormat decimalFormat = new DecimalFormat("#,###");
            String numberAsString = decimalFormat.format(balance);
    
            Text balanceText = new Text("$" + (numberAsString));
            balanceText.setFont(Font.font("Modernist", 72));
            balanceText.setFill(Color.web("77e6b3"));
    
            Text currencyText = new Text("USD");
            currencyText.setTextOrigin(VPos.TOP);
            currencyText.setFont(Font.font("Modernist", 36));
            currencyText.setFill(Color.web("77e6b3"));
    
            TextFlow flow = new TextFlow(balanceText, currencyText);
            flow.setMinSize(TextFlow.USE_PREF_SIZE, TextFlow.USE_PREF_SIZE);
    
            VBox layout = new VBox(flow);
            layout.setPadding(new Insets(10));
    
            stage.setScene(new Scene(layout));
            stage.getScene().setFill(Color.rgb(35, 39, 50));
            stage.show();
        }
    
        public static void main(String[] args) {
            launch();
        }
    }
    

    JavaDoc Description

    Description of TextFlow from the JavaDoc linked above:

    TextFlow is special layout designed to lay out rich text. It can be used to layout several Text nodes in a single text flow. The TextFlow uses the text and the font of each Text node inside of it plus it own width and text alignment to determine the location for each child.

    Implementation Comments

    By default, TextFlow will wrap text to new lines if there is not enough space to render all text, so I set the minimum size of the TextFlow to its preferred size to prevent that.

    TextFlow can align the text with standard width based alignment settings such as left align, right align, justify etc. However, TextFlow doesn't have any way to vertically align text, for example to generate a superscript value. There are also other limitations such as making the text selectable for copy and paste or editing text. So look at it, and try it to see if it fits your purpose, if not then consider some of the other alternative mechanisms mentioned below.

    Alternative Approaches

    Other valid ways to do this are:

    1. Using layout containers with constraints to control layout (as in Zephyr's answer and this related question: Javafx Text multi-word colorization).
    2. Embedding a WebView to render CSS formatted html.
    3. Using a third party lib, like RichTextFX.