【问题标题】:JavaFX: How to change the color of text in TextArea corresponding to the selectRangeJavaFX:如何更改与 selectRange 对应的 TextArea 中文本的颜色
【发布时间】:2018-11-28 02:56:12
【问题描述】:

我打算从 TextArea 中获取所选文本的范围并更改 selectRange 的字体颜色。我的 TextArea 被初始化为 FXML 文件的一部分。我可以通过使用 textArea.getSelection() 来获取 selectRange,我想为上述方法返回的范围内的文本着色。请建议我怎么做。

【问题讨论】:

  • 不太清楚,您只是想让TextArea 在选择文本时显示不同的颜色,还是希望格式化所选文本以使其具有不同的颜色?
  • 我想将所选文本格式化为不同的颜色。抱歉不清楚我对 JavaFX 还很陌生。
  • 我不确定你是否真的明白我的意思。前者意味着您正在尝试更改TextArea 的外观和感觉。另一方面,后者意味着文本本身将是富文本,并且当您将其复制到另一个文本编辑器时,这种格式仍然存在。同样对于后者,可以在整个文本的不同部分使用各种颜色。
  • 好的,我会尽量准确一点。我正在尝试构建一个文本突出显示应用程序。我的 TextArea 中所有突出显示的字符串都应该是彩色的,比如说黄色字体。这样即使在我移除高亮显示后,之前高亮显示的文本也应该有一种颜色格式来指示其高亮显示的文本。

标签: javafx javafx-8 javafx-css


【解决方案1】:

首先,我建议根据您的要求使用任何富文本控件(RichTextFX)。但是,如果您对使用 TextArea 非常具体,请检查以下方法。

我提供的方法可能不是正确的解决方案,也可能不适合您的确切要求。但它可以帮助您朝那个方向思考。

这是基于Highlighting Strings in JavaFX TextArea 中提供的想法(@en_Knight)。我建议先通读这个 OP,然后检查我的以下实现。

我创建了一个自定义 TextArea 控件,它的工作原理与上述 OP 中提供的相同。即,混合节点以获得所需的效果。您可以通过更改演示中组合框的值来检查不同的混合效果。我假设您可能需要 BlendMode.ADD

在您选择文本时,突出显示仍然存在。

import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.effect.BlendMode;
import javafx.scene.layout.*;
import javafx.scene.shape.Path;
import javafx.scene.shape.PathElement;
import javafx.stage.Stage;

import java.util.ArrayList;
import java.util.List;

public class CustomTextAreaDemo extends Application {
    @Override
    public void start(Stage stage) throws Exception {

        final VBox root = new VBox();
        root.setSpacing(10);
        root.setPadding(new Insets(10));
        final Scene sc = new Scene(root, 600, 300);
        stage.setScene(sc);
        stage.show();

        final CustomTextArea customTextArea = new CustomTextArea();
        customTextArea.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.");
        customTextArea.setWrapText(true);
        customTextArea.setStyle("-fx-font-size: 15px;");
        VBox.setVgrow(customTextArea, Priority.ALWAYS);

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

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

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

        ComboBox<BlendMode> blendModes = new ComboBox<>();
        blendModes.getItems().addAll(BlendMode.values());
        blendModes.getSelectionModel().selectedItemProperty().addListener((obs, old, blend) -> {
            customTextArea.getHighlightPath().setBlendMode(blend);
        });
        blendModes.getSelectionModel().select(BlendMode.ADD);

        root.getChildren().addAll(hb, rb,blendModes, customTextArea);
    }

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

    class CustomTextArea extends TextArea {
        /**
         * Start position of the highlight.
         */
        private int highlightStartPos = -1;

        /**
         * End position of the highlight.
         */
        private int highlightEndPos = -1;

        /**
         * Path node to act as highlight.
         */
        private final Path highlightPath = new Path();

        /**
         * Node to keep reference of the selectionGroup node of the TextArea.
         */
        private Group selectionGroup;

        /**
         * Node to keep reference of the all contents of the TextArea.
         */
        private StackPane contentPane;

        /**
         * Node to keep reference of the content node.
         */
        private Region textContent;

        /**
         * Specifies whether the selection of text is done for purpose of highlighting.
         */
        private boolean highlightInProgress = false;

        public CustomTextArea() {
            highlightPath.setStyle("-fx-fill:red");
            highlightPath.setMouseTransparent(true);
            highlightPath.setManaged(false);
            highlightPath.setStroke(null);
            textProperty().addListener((obs, oldVal, newVal) -> removeHighlight());
            widthProperty().addListener((obs, oldVal, newVal) -> {
                if (highlightStartPos > -1 && highlightEndPos > -1 && selectionGroup != null) {
                    highlightInProgress = true;
                    selectRange(highlightStartPos, highlightEndPos);
                }
            });
        }

        /**
         * Highlights the range of characters in the text area.
         *
         * @param startPos Start position of the character in the text
         * @param endPos   End position of the character in the text
         */
        public void highlight(final int startPos, final int endPos) {
            highlightStartPos = startPos;
            highlightEndPos = endPos;
            highlightInProgress = true;
            selectRange(highlightStartPos, highlightEndPos);
        }

        public Path getHighlightPath() {
            return highlightPath;
        }

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

        /**
         * Updates the highlight with the provided bounds.
         */
        private void updateHightlightBounds() {
            if (!selectionGroup.getChildren().isEmpty()) {
                final Path p = (Path) selectionGroup.getChildren().get(0);
                final List<PathElement> elements = new ArrayList<>(p.getElements());

                highlightPath.getElements().clear();
                highlightPath.getElements().addAll(elements);
                final Node textNode = textContent.lookup(".text");
                highlightPath.setLayoutX(textNode.getLayoutX());
                highlightPath.setLayoutY(textNode.getLayoutY());

                if (contentPane != null && !contentPane.getChildren().contains(highlightPath)) {
                    contentPane.getChildren().add(highlightPath);
                }
                highlightInProgress = false;
                Platform.runLater(this::deselect);
            }
        }

        /**
         * Removes the highlight in the text area.
         */
        public void removeHighlight() {
            if (contentPane != null) {
                contentPane.getChildren().remove(highlightPath);
            }
            highlightStartPos = -1;
            highlightEndPos = -1;
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-02
    • 2016-07-26
    • 1970-01-01
    • 2021-08-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多