Выделение строк в JavaFX TextArea - PullRequest
8 голосов
/ 03 февраля 2012

Мы используем TextArea элемент управления JavaFX в нашем приложении и пытаемся интегрировать его с Jazzy Spell Check API - например, когда пользователь вводит неверное слово, которого нет в словаре, например,слово будет выделено.

Есть ли способ выделить слово в указанном элементе управления?Я не видел вариантов для этого в JavaDocs, так что, если бы кто-то мог предложить подход?

Возможно, я мог бы использовать компонент HTMLEditor и по-разному раскрасить слова с помощью <font face="red=>wrongWord</font>,Это, однако, приносит много разных проблем с проверкой орфографии, таких как теги html и количество слов.

Ответы [ 5 ]

13 голосов
/ 07 октября 2013

RichTextFX позволяет добавлять стиль к текстовым диапазонам.

9 голосов
/ 04 февраля 2012

Элемент управления JavaFX TextArea (по состоянию на 2.0.2) не поддерживает редактирование форматированного текста, в котором смешаны стили текста (шрифты и т. Д.).

Вы можете выделить непрерывные строки символов в TextArea, управляя selectRange TextArea, как в следующем примере:

public class TextHighlight extends Application {
  public static void main(String[] args) { Application.launch(args); }
  @Override public void start(Stage stage) {
    final TextArea text = new TextArea("Here is some textz to highlight");
    text.setStyle("-fx-highlight-fill: lightgray; -fx-highlight-text-fill: firebrick; -fx-font-size: 20px;");
    text.setEditable(false);
    text.addEventFilter(MouseEvent.ANY, new EventHandler<MouseEvent>() {
      @Override public void handle(MouseEvent t) { t.consume(); }
    });

    stage.setScene(new Scene(text));
    stage.show();

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

Вы можете использовать приведенный выше код в качестве основы для переключения TextArea в режим только для чтения во время проверки орфографии. Реализуйте подсказку, чтобы найти и исправить каждое слово по очереди, пока проверка орфографии не будет завершена. Выполните запрос в отдельном диалоговом окне или панели. Демонстрация Jazzy, кажется, работает таким образом http://jazzy.sourceforge.net/demo.html,, поэтому довольно просто конвертировать его Swing UI в JavaFX.


В качестве альтернативы, вы можете использовать элемент управления JavaFX WebView, чтобы обернуть любую из множества программ проверки правописания на основе javascript / html (например, http://www.javascriptspellcheck.com/), используя технику, аналогичную показанной здесь: http://jewelsea.wordpress.com/2011/12/11/codemirror-based-code-editor-for-javafx/.

5 голосов
/ 29 мая 2014

В JavaFX 8 вы можете использовать TextFlow

. Вы можете определить определенные классы стилей для жирного, красного, зеленого или любого типа Тексты и упорядочить их в TextFlow, назначая требуемый класс стилякаждый текст

5 голосов
/ 01 декабря 2013

Это возможно ... вроде

Я знаю, что этот вопрос решен, но я нашел способ исправить проблему и решил опубликовать его для других людей, которыетакже наткнуться на этот пост.Это немного странно, но работает в крайнем случае, если вам нужно выделить текст в TextArea и не хотите принимать неудовлетворительный «невозможный» ответ.

  1. Получить цвет фона дляTextArea и цвет переднего плана шрифта текста
  2. Вычисление максимальной контрастности между цветом переднего плана и фоном
  3. Поместите прямоугольник вокруг нужного текста
  4. Установите цветпрямоугольник с цветом фона
  5. Установите режим наложения прямоугольника на ячейку с наибольшим контрастом
  6. Отключите прямоугольник

Прямоугольник теперь будет идеально сочетаться сфон, но изменить цвет текста.Отключение прямоугольника означает, что он не будет казаться пользователю чем-то более аскетичным - например, такие действия, как нажатие на прямоугольник, не будут иметь неожиданного эффекта.

Вы можете слегка настроить этот метод, если множество цветовжелаемый.

Я могу опубликовать детали реализации, если люди заинтересованы, скептически или если это сложно получить работу.

0 голосов
/ 16 ноября 2018

У меня аналогичное требование, и ответ @en_Knight мне обещает.Он только что представил теоретические детали.Основываясь на его мнениях, я подумал попробовать, и вот чем я закончил.

Есть много дел, которые еще нужно обработать.Но, по крайней мере, это должно дать достаточное представление о том, о чем @en_Knight рассказывает.

Пожалуйста, проверьте приведенную ниже демонстрационную версию:

import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.geometry.Bounds;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.effect.BlendMode;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Path;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class HighlightableTextAreaDemo extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        VBox root = new VBox();
        root.setSpacing(10);
        root.setPadding(new Insets(10));
        Scene sc = new Scene(root, 600, 600);
        stage.setScene(sc);
        stage.show();


        final HighlightableTextArea highlightableTextArea = new HighlightableTextArea();
        highlightableTextArea.setText("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.");
        highlightableTextArea.getTextArea().setWrapText(true);
        highlightableTextArea.getTextArea().setStyle("-fx-font-size: 20px;");
        VBox.setVgrow(highlightableTextArea,Priority.ALWAYS);

        Button highlight = new Button("Highlight");
        TextField stF = new TextField("40");
        TextField enF = new TextField("50");
        HBox hb = new HBox(highlight,stF,enF);
        hb.setSpacing(10);
        highlight.setOnAction(e->{highlightableTextArea.highlight(Integer.parseInt(stF.getText()), Integer.parseInt(enF.getText()));});

        Button remove = new Button("Remove Highlight");
        remove.setOnAction(e->highlightableTextArea.removeHighlight());

        Label lbl = new Label("Resize the window to see if the highlight is moving with text");
        lbl.setStyle("-fx-font-size: 17px;-fx-font-style:italic;");
        HBox rb = new HBox(remove,lbl);
        rb.setSpacing(10);

        root.getChildren().addAll(hb,rb,highlightableTextArea);
    }

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

    /**
     * Custom TextArea Component.
     */
    class HighlightableTextArea extends StackPane {
        final TextArea textArea = new TextArea();
        int highlightStartPos = -1;
        int highlightEndPos = -1;
        boolean highlightInProgress = false;

        final Rectangle highlight = new Rectangle();

        private StringProperty text = new SimpleStringProperty();

        private Group selectionGroup;

        public final String getText() {
            return text.get();
        }

        public final void setText(String value) {
            text.set(value);
        }

        public final StringProperty textProperty() {
            return text;
        }

        public HighlightableTextArea() {
            highlight.setFill(Color.RED);
            highlight.setMouseTransparent(true);
            highlight.setBlendMode(BlendMode.DARKEN);

            textArea.textProperty().bindBidirectional(text);
            getChildren().add(textArea);
            setAlignment(Pos.TOP_LEFT);
            textArea.widthProperty().addListener((obs, oldVal, newVal) -> {
                if (highlightStartPos > -1 && highlightEndPos > -1 && selectionGroup != null) {
                    highlightInProgress = true;
                    textArea.selectRange(highlightStartPos, highlightEndPos);
                    Bounds bounds = selectionGroup.getBoundsInLocal();
                    updateHightlightBounds(bounds);
                }
            });
        }

        private void updateHightlightBounds(Bounds bounds) {
            if (bounds.getWidth() > 0) {
                if (!getChildren().contains(highlight)) {
                    getChildren().add(highlight);
                }
                highlight.setTranslateX(bounds.getMinX() + 1);
                highlight.setTranslateY(bounds.getMinY() + 1);
                highlight.setWidth(bounds.getWidth());
                highlight.setHeight(bounds.getHeight());
                Platform.runLater(() -> {
                    textArea.deselect();
                    highlightInProgress = false;
                });
            }
        }

        public TextArea getTextArea() {
            return textArea;
        }

        @Override
        protected void layoutChildren() {
            super.layoutChildren();
            if (selectionGroup == null) {
                final Region content = (Region) lookup(".content");
                // Looking for the Group node that is responsible for selection
                content.getChildrenUnmodifiable().stream().filter(node -> node instanceof Group).map(node -> (Group) node).filter(grp -> {
                    boolean notSelectionGroup = grp.getChildren().stream().anyMatch(node -> !(node instanceof Path));
                    return !notSelectionGroup;
                }).findFirst().ifPresent(n -> {
                    n.boundsInLocalProperty().addListener((obs, old, bil) -> {
                        if (highlightInProgress) {
                            updateHightlightBounds(bil);
                        }
                    });
                    selectionGroup = n;
                });
            }
        }

        public void highlight(int startPos, int endPos) {
            highlightInProgress = true;
            highlightStartPos = startPos;
            highlightEndPos = endPos;
            textArea.selectRange(startPos, endPos);
        }

        public void removeHighlight() {
            textArea.deselect();
            getChildren().remove(highlight);
            highlightStartPos = -1;
            highlightEndPos = -1;
        }

    }

}
...