用textarea

问题描述 投票:0回答:1
textarea可以提供可选的文本,但不能提供可着色的文本。 textflow可以提供可着色的文本,但不是可选的文本。

,我试图将文本流覆盖在我的文本框架顶部以获得可着色和可选的文本。
    ,但是事实证明,这非常困难,目前我已经通过填充物进行硬编码,而填充物当前看起来像这样:
  1. <StackPane> <!-- TextArea for selectable text. --> <TextArea fx:id="dialog" minHeight="-Infinity" text="Label" wrapText="true" editable="false" focusTraversable="false"> <HBox.margin> <Insets left="82.0" right="7.0" /> </HBox.margin> <StackPane.margin> <Insets left="82.0" right="7.0" /> </StackPane.margin> <padding> <Insets bottom="6.0" left="6.0" right="6.0" top="6.0" /> </padding></TextArea> <!-- TextFlow for colored text. --> <TextFlow fx:id="textFlow" styleClass="text-flow" mouseTransparent="true" lineSpacing="1.2"> <HBox.margin> <Insets left="82.0" right="7.0" /> </HBox.margin> <StackPane.margin> <Insets left="82.0" right="7.0" /> </StackPane.margin> <padding> <Insets bottom="3.0" left="18.8" right="18.8" top="13.8" /> </padding></TextFlow> </StackPane>
  2. 这些值是完全任意的,并且通过一遍又一遍地将代码重新编写实验获得。 (填充和文本流对象的线条)。 尽管这适用于大多数字符,但有些字符,例如“}”,这些字符将被错位,从而导致Textarea的包裹文本比TextFlow对象更早移动。填充物也针对1DP,任何进一步的调整都没有差异。
  3. ,如果有更好的方法将文本流对象绑定到Textarea对象,以便它具有完美的覆盖层。
我知道有一些外部工具,例如RichText,但我想尝试仅将Textarea和TextFlow用于学习目的。

提前感谢您!

正如@Jewelsea的评论中提到的那样,我认为最简单的方法是使用WebView来获取所需的功能。
having说,如果您对使用HTML或WebView不太感兴趣,则可以尝试使用自定义的TextFlow布局的下面方法。

一般的想法是

我们在Textflow儿童中包括一个不受管理的文本area,它总是位于TextFlow中的所有节点的顶部 textarea造型被定制为具有透明背景,并与基础文本节点保持一致

当您在Textarea中选择任何文本时,您似乎正在选择文本流中的多色文本节点中的文本。

这只是一个建议或想法,您需要进行更多的精细调整或重构才能使其变得完全正常。

javafx fxml
1个回答
0
投票

我希望以下演示能为您提供一些如何处理的想法:

  • import javafx.application.Application; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Node; import javafx.scene.Scene; import javafx.scene.control.Label; import javafx.scene.control.TextArea; import javafx.scene.control.TextField; import javafx.scene.layout.Region; import javafx.scene.layout.VBox; import javafx.scene.text.Text; import javafx.scene.text.TextFlow; import javafx.scene.web.WebView; import javafx.stage.Stage; import java.util.List; public class SelectableTextFlowExample extends Application { public static void main(String[] args) { launch(args); } public void start(Stage primaryStage) { primaryStage.setTitle("JavaFX Selectable TextFlow Example"); // Approach #1 : Using WebView WebView webView = new WebView(); webView.setMaxWidth(200); webView.setMinHeight(Region.USE_PREF_SIZE); String content = "<span style='color:red;'>Hello</span>&nbsp;<span style='color:green'>World!</span>&nbsp;<span style='color:red;'>ContinousBigWord</span>"; webView.getEngine().loadContent(content, "text/html"); WebViewFitContent wv = new WebViewFitContent(content); // Approach #2 : TextFlow with TextArea/TextField TextFlow flow = new TextFlow(); TextField t1 = buildTextField("Hello"); TextField t2 = buildTextField("W"); TextField t3 = buildTextField("orld!"); flow.getChildren().addAll(t1, t2, t3); // Approach #3 : Custom TextFlow layout SelectableTextFlow stf = new SelectableTextFlow(); Text txt1 = new Text("Hello "); txt1.setStyle("-fx-fill:red;"); Text txt2 = new Text("World! "); txt2.setStyle("-fx-fill:green;"); Text txt3 = new Text("ContinousBigWord"); txt3.setStyle("-fx-fill:red;"); stf.getChildren().addAll(txt1, txt2, txt3); VBox vBox = new VBox(buildBox("Using WebView", wv), buildBox("Using TexFlow with TextArea/TextField", flow), buildBox("Using Custom TextFlow", stf)); vBox.setSpacing(15); vBox.setPadding(new Insets(10)); Scene scene = new Scene(vBox, 400, 300); primaryStage.setScene(scene); primaryStage.show(); } private VBox buildBox(String title, Node node) { VBox box = new VBox(); box.setAlignment(Pos.CENTER_LEFT); box.setSpacing(5); Label label = new Label(title); label.setStyle("-fx-font-size:16px;-fx-font-weight:bold;"); box.getChildren().addAll(label, node); return box; } private TextField buildTextField(String k) { MyTextField t = new MyTextField(); t.textProperty().addListener((obs, old, val) -> t.setWidthMask(val)); t.setText(k); t.setEditable(false); t.setStyle("-fx-padding:0px;-fx-background-color:transparent;-fx-background-insets:0;"); t.setMinWidth(Region.USE_PREF_SIZE); return t; } class SelectableTextFlow extends TextFlow { private final static String CSS = "data:text/css," + """ .selectable-text-flow .text-area, .selectable-text-flow .text-area .scroll-pane, .selectable-text-flow .text-area .scroll-pane .viewport, .selectable-text-flow .text-area .scroll-pane .viewport .content, .selectable-text-flow .text-area .scroll-pane .scroll-bar, .selectable-text-flow .text-area .scroll-pane .scroll-bar .increment-arrow, .selectable-text-flow .text-area .scroll-pane .scroll-bar .decrement-arrow, .selectable-text-flow .text-area .scroll-pane .scroll-bar .increment-button, .selectable-text-flow .text-area .scroll-pane .scroll-bar .decrement-button, .selectable-text-flow .text-area > .scroll-pane > .corner{ -fx-background-color: transparent !important; -fx-border-color: transparent !important; -fx-padding: 0px; -fx-background-insets: 0px !important; } .selectable-text-flow .text-area .scroll-pane .scroll-bar{ -fx-max-width:0px; -fx-max-height:0px; } .selectable-text-flow .text-area{ -fx-text-fill: transparent; } """; TextArea textArea = new TextArea(); public SelectableTextFlow() { getStyleClass().add("selectable-text-flow"); textArea.setWrapText(true); textArea.setManaged(false); textArea.setEditable(false); getChildren().add(textArea); getStylesheets().add(CSS); } @Override protected void layoutChildren() { StringBuilder txt = new StringBuilder(); List<Node> managed = getManagedChildren(); for (Node node : managed) { if (node instanceof Text) { Text text = (Text) node; txt.append(text.getText()); } } textArea.setText(txt.toString()); textArea.toFront(); super.layoutChildren(); textArea.setLayoutX(-3); // need to do some fine alignment dynamically textArea.setLayoutY(-3); textArea.resize(getWidth(), getHeight() + 6); } } class MyTextField extends TextField { /** * Field width mask. */ private String widthMask; public final void setWidthMask(final String aWidthMask) { widthMask = aWidthMask; if (widthMask != null && !widthMask.isEmpty()) { /* To indicate that the preferred dimensions should be used for that max and/or min constraint. */ setMinWidth(USE_PREF_SIZE); setMaxWidth(USE_PREF_SIZE); } } @Override protected final double computePrefWidth(final double height) { if (widthMask != null && !widthMask.isEmpty()) { /* If the prefWidth is not yet determined, compute and set the prefWidth. */ if (getPrefWidth() == USE_COMPUTED_SIZE) { setPrefWidth(computeWidth(this, widthMask)); } return getPrefWidth(); } return super.computePrefWidth(height); } } /** * Computes the width of a text field based on the string mask provided * * @param textField The text field to evaluate * @param textMask the text mask with which to calculate the max required width * @return the required width of the text field */ public static double computeWidth(final TextField textField, final String textMask) { /* * Getting the last Text node to ensure that the text node is related to the actual text and not the prompt * text. */ final Text text = (Text) textField.lookup(".text"); final String cache = text.getText(); /* * Unbinding the text property to ensure that it will not trigger the listeners of textField when computing * the mask width. */ text.textProperty().unbind(); text.setText(textMask); final double prefWidth = Math.ceil(textField.getInsets().getLeft()) + text.getLayoutBounds().getWidth() + Math.ceil(textField.getInsets().getRight()) + 2.0; text.setText(cache); /* Setting back the binding when the mask width computing is done. */ text.textProperty().bind(textField.textProperty()); return prefWidth; } }
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.