I wrote a simple test JavaFX application that do what you are asking.
This is the result

And this is the code
package sample;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.Orientation;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
primaryStage.setTitle("Hello World");
Scene scene = new Scene(new Group(), 300, 275);
//Create a FlowPane that will contain many Text.
FlowPane flowLabel = new FlowPane(Orientation.HORIZONTAL);
flowLabel.setBackground(new Background(new BackgroundFill(Color.BEIGE, CornerRadii.EMPTY, Insets.EMPTY)));
flowLabel.setColumnHalignment(HPos.LEFT);
//This is the label text. The text that the user must insert
final String text = "Hello world!";
//Create a Text object for each character
final Text[] characters = new Text[text.length()];
for(int i = 0; i < text.length(); i++) {
Character c = text.charAt(i);
characters[i] = new Text(c.toString());
flowLabel.getChildren().add(characters[i]);
}
//Create the text field and add a listener to do something when the text change.
TextField field = new TextField();
field.textProperty().addListener(new ChangeListener<String>() {
@Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
//Do the magic
String fieldText = newValue;
if(text.startsWith(fieldText)) {
for(int i = 0; i < text.length(); i++) {
if(i < fieldText.length()) {
characters[i].setFill(Color.GREEN);
} else {
characters[i].setFill(Color.BLACK);
}
}
} else {
for(int i = 0; i < text.length(); i++) {
characters[i].setFill(Color.RED);
}
}
}
});
FlowPane pane = new FlowPane(Orientation.HORIZONTAL);
pane.setVgap(8);
pane.getChildren().add(flowLabel);
pane.getChildren().add(field);
((Group)scene.getRoot()).getChildren().add(pane);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I think that this isn't the best way to do that, but will help you to proceed.