0

I am now wondering how to automatically highlight the text within a text area. I have researched further and found a method to do so however I am not sure how it can still highlight a String automatically after the user enters search.

enter image description here

Note: Ignore the radio buttons

Here is the method I tried within the action event when clicking the search button

 @FXML
 private void searchButton(ActionEvent actionEvent){
    String key = keyField.getText();
    String field = textField.getText();
    System.out.println(key);
    System.out.println(field);

        textField.getText();
        if (textField.getText().equals(key)) {
            textField.setStyle("-fx-highlight-fill: yellow; -fx-highlight-text-fill: black; -fx-font-size: 12px; ");
            textField.setEditable(false);
            textField.addEventFilter(MouseEvent.ANY, new EventHandler<MouseEvent>() {
                @Override
                public void handle(MouseEvent t) {
                    t.consume();
                }
            });

            Platform.runLater(new Runnable() {
                @Override
                public void run() {
                    textField.selectRange(13, 18);
                }
            });
        }

    ToggleGroup group = new ToggleGroup();
    rabinKarpp.setToggleGroup(group);
    kmp.setToggleGroup(group);
    naive.setToggleGroup(group);

    ArrayList indexes = new ArrayList();
    if (rabinKarpp.isSelected()){
        indexes = RabinKarp.process(field, key);
    }
    else if (kmp.isSelected()){
        indexes = KMPAlgo.process(field, key);
    }
    else if (naive.isSelected()){
        indexes = NaiveAlgo.process(field, key);
    }
    else if(!naive.isSelected() && !kmp.isSelected() && !rabinKarpp.isSelected()) {
        Alert alert = new Alert(Alert.AlertType.WARNING, "Select an algorithm first before proceeding.",ButtonType.OK);
        alert.showAndWait();
    }

}

the expected output should be the "hello" from "hello everyone" to be highlighted but I'm still stumped on how to do so.

EDIT:

The code now looks like this but still the highlights will not turn up sadly.

@FXML protected void searchButton(ActionEvent actionEvent){

    String key = keyField.getText();
    String field = textField.getText();
    System.out.println(key);
    System.out.println(field);

    ToggleGroup group = new ToggleGroup();
    rabinKarpp.setToggleGroup(group);
    kmp.setToggleGroup(group);
    naive.setToggleGroup(group);

    ArrayList indexes = new ArrayList();
    if (rabinKarpp.isSelected()){
        indexes = RabinKarp.process(field, key);
    }
    else if (kmp.isSelected()){
        indexes = KMPAlgo.process(field, key);
    }
    else if (naive.isSelected()){
        indexes = NaiveAlgo.process(field, key);
    }
    else if(!naive.isSelected() && !kmp.isSelected() && !rabinKarpp.isSelected()) {
        Alert alert = new Alert(Alert.AlertType.WARNING, "Select an algorithm first before proceeding.",ButtonType.OK);
        alert.showAndWait();
    }
}

@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
    List<List<Integer>> locations = new ArrayList();
    keyField.textProperty().addListener((o, oldValue, newValue) -> {
        Pattern pattern = Pattern.compile(newValue);
        Matcher matcher = pattern.matcher(textField.getText());

        locations.clear();
        if (newValue.isEmpty()) {
            // no highlighting for the empty search string
            textField.deselect();
        } else {
            int index = textField.getText().indexOf(newValue);
            if (index < 0) {
                // text not found
                textField.deselect();
            } else {
                while(matcher.find())
                {
                    List<Integer> tempList = new ArrayList<>();
                    tempList.add(matcher.start());
                    tempList.add(matcher.end());

                    locations.add(tempList);
                }
            }
        }
    });
    AtomicInteger currentIndex = new AtomicInteger(-1);
    downButton.setOnAction((t) -> {
        if(currentIndex.get() >= -1 && currentIndex.get() < locations.size() - 1)
        {
            textField.selectRange(locations.get(currentIndex.incrementAndGet()).get(0), locations.get(currentIndex.get()).get(1));
        }
    });

    upButton.setOnAction((t) -> {
        if(currentIndex.get() > 0 && currentIndex.get() <= locations.size())
        {
            textField.selectRange(locations.get(currentIndex.decrementAndGet()).get(0), locations.get(currentIndex.get()).get(1));
        }
    });
}
3

2 Answers 2

3

Simply listen to the text property of the TextField for this purpose. Note that you can only select a single range using TextArea. If you need to highlight multiple occurances you may want to use a TextFlow and it's rangeShape method as suggested by @Slaw.

@Override
public void start(Stage stage) throws IOException {
    TextArea textArea = new TextArea();
    VBox.setVgrow(textArea, Priority.ALWAYS);
    Random random = new Random();
    for (int l = 0; l < 10; l++) {
        for (int i = 0; i < 300; i++) {
            textArea.appendText(Character.toString('a' + random.nextInt('z'- 'a' + 1)));
        }
        textArea.appendText("\n");
    }

    TextField textField = new TextField();
    textField.textProperty().addListener((o, oldValue, newValue) -> {
        if (newValue.isEmpty()) {
            // no highlighting for the empty search string
            textArea.deselect();
        } else {
            int index = textArea.getText().indexOf(newValue);
            if (index < 0) {
                // text not found
                textArea.deselect();
            } else {
                // select first occurance
                textArea.selectRange(index, index + newValue.length());
            }
        }
    });

    Scene scene = new Scene(new VBox(textArea, textField));

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

Using fxml the proper place to register a listener like this would be the initialize method.

Sign up to request clarification or add additional context in comments.

1 Comment

I have tried this within my Controller class and within an initializable method but still nothing happens
2

I would like to add on to @fabian's answer. If you want to find multiple occurrences one at a time, you can find all the matches in the string and save their indexes to a list. The list can be used to step through each occurrence.

I have added 4 occurrences of hello to fabian's original string. You can type hello into the TextField and hit up and then down, to reach each occurrence.

    TextArea textArea = new TextArea();
    VBox.setVgrow(textArea, Priority.ALWAYS);
    Random random = new Random();
    for (int l = 0; l < 10; l++) {
        for (int i = 0; i < 300; i++) {
            textArea.appendText(Character.toString('a' + random.nextInt('z'- 'a' + 1)));
        }
        textArea.appendText("\n");
    }

    textArea.replaceText(0, 5, "hello");
    textArea.replaceText(20, 25, "hello");
    textArea.replaceText(30, 35, "hello");
    textArea.replaceText(textArea.getText().length() - 6, textArea.getText().length() -1, "hello");

    TextField textField = new TextField();
    List<List<Integer>> locations = new ArrayList();

    textField.textProperty().addListener((o, oldValue, newValue) -> {
        Pattern pattern = Pattern.compile(newValue);
        Matcher matcher = pattern.matcher(textArea.getText());

        locations.clear();
        if (newValue.isEmpty()) {
            // no highlighting for the empty search string
            textArea.deselect();
        } else {                
            int index = textArea.getText().indexOf(newValue);
            if (index < 0) {
                // text not found
                textArea.deselect();
            } else {
                while(matcher.find())
                {
                    List<Integer> tempList = new ArrayList<>();
                    tempList.add(matcher.start());
                    tempList.add(matcher.end());

                    locations.add(tempList);
                }
            }
        }
    });

    AtomicInteger currentIndex = new AtomicInteger(-1);
    Button btnDown = new Button("Down");
    btnDown.setOnAction((t) -> {
        if(currentIndex.get() >= -1 && currentIndex.get() < locations.size() - 1)
        {
            textArea.selectRange(locations.get(currentIndex.incrementAndGet()).get(0), locations.get(currentIndex.get()).get(1));
        }
    });

    Button btnUp = new Button("Up");
    btnUp.setOnAction((t) -> {
        if(currentIndex.get() > 0 && currentIndex.get() <= locations.size())
        {
            textArea.selectRange(locations.get(currentIndex.decrementAndGet()).get(0), locations.get(currentIndex.get()).get(1));
        }
    });
    Scene scene = new Scene(new VBox(textArea, textField, new HBox(btnDown, btnUp)));

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.