Javafx 2 如何拉伸TextArea以填充内容,并在此过程中展开父级?

Javafx 2 如何拉伸TextArea以填充内容,并在此过程中展开父级?,javafx-2,javafx-8,Javafx 2,Javafx 8,因此,我有一个文本区域,当用户将段落粘贴到其中,或者只是在其中写入时,我希望它垂直扩展以显示所有可用的文本。也就是说,不要在文本字段本身中使用滚动条。。。就像许多网页上发生的事情一样。包括我在内的许多用户不喜欢被迫在一个小窗口中进行编辑。Facebook状态更新框的工作原理 我试过了 myTextArea.autoSize() 裹着 myTextArea.textProperty().addListener(新的ChangeListener()…) 但这不起作用。我认为它很高兴自动调整到当前大

因此,我有一个文本区域,当用户将段落粘贴到其中,或者只是在其中写入时,我希望它垂直扩展以显示所有可用的文本。也就是说,不要在文本字段本身中使用滚动条。。。就像许多网页上发生的事情一样。包括我在内的许多用户不喜欢被迫在一个小窗口中进行编辑。Facebook状态更新框的工作原理

我试过了

myTextArea.autoSize()
裹着

myTextArea.textProperty().addListener(新的ChangeListener()…)

但这不起作用。我认为它很高兴自动调整到当前大小

左锚、右锚和顶锚都设置为其父锚平面。我试过了,底部连着,没有连着。理想情况下,我希望随着文本区域的增长而增长锚定窗格

我不介意阅读TextProperty并计算我自己设置的触发器大小。。。但是,如果已经有了最佳实践,那么这似乎是一种不成熟的方法。javafx的属性和子对象的数量足以让人望而生畏,因此在这里提出这个问题似乎是一个好问题,而不是试图找出字体/段落等占用了多少像素

更新:


所以我想也许我想得太多了,我所需要做的就是关掉滚动条,剩下的事情就会发生。唉,在寻找“滚动”、“垂直”、“vbar”的可用字段和方法时,我找不到可用的字段和方法。ScrollTopProperty看起来像是用于其他用途。

在等待更好的解决方案时,我使用了这个黑客解决方案

  • 查找文本区域的垂直滚动条
  • 让它透明
  • 倾听它的可见属性
  • 当滚动条可见时,我会在文本区域中添加一行
守则:

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.geometry.Orientation;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ScrollBar;
import javafx.scene.control.TextArea;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;

public class GrowGrowTextArea extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        AnchorPane root = new AnchorPane();
        root.setStyle("-fx-padding:20;-fx-background-color:dodgerblue;");
        final TextArea textArea = new TextArea();
        AnchorPane.setTopAnchor(textArea, 10.0);
        AnchorPane.setLeftAnchor(textArea, 10.0);
        AnchorPane.setRightAnchor(textArea, 10.0);
        root.getChildren().add(textArea);
        primaryStage.setScene(new Scene(root, 400, 300));
        primaryStage.show();
        ScrollBar scrollBar = lookupVerticalScrollBar(textArea);
        scrollBar.setOpacity(0.0);
        scrollBar.visibleProperty().addListener(new ChangeListener<Boolean>() {

            @Override
            public void changed(ObservableValue<? extends Boolean> source,
                                Boolean wasVisible,
                                Boolean isVisible) {
                if (isVisible) {
                    textArea.setPrefRowCount(textArea.getPrefRowCount() + 1);
                    textArea.requestLayout();
                }
            }
        });

    }

    private ScrollBar lookupVerticalScrollBar(Node node) {
        if (node instanceof ScrollBar && ((ScrollBar)node).getOrientation() == Orientation.VERTICAL) {
            return (ScrollBar) node;
        }
        if (node instanceof Parent) {
            ObservableList<Node> children = ((Parent) node).getChildrenUnmodifiable();
            for (Node child : children) {
                ScrollBar scrollBar = lookupVerticalScrollBar(child);
                if (scrollBar != null) {
                    return scrollBar;
                }
            }
        }
        return null;
    }
}
导入javafx.application.application;
导入javafx.beans.value.ChangeListener;
导入javafx.beans.value.observeValue;
导入javafx.collections.ObservableList;
导入javafx.geometry.Orientation;
导入javafx.scene.Node;
导入javafx.scene.Parent;
导入javafx.scene.scene;
导入javafx.scene.control.ScrollBar;
导入javafx.scene.control.TextArea;
导入javafx.scene.layout.ancorpane;
导入javafx.stage.stage;
公共类growtextarea扩展应用程序{
公共静态void main(字符串[]args){
发射(args);
}
@凌驾
public void start(Stage primaryStage)引发异常{
锚烷根=新锚烷();
root.setStyle(“-fx填充:20;-fx背景色:dodgerblue;”);
最终TextArea TextArea=新TextArea();
AnchorPane.setTopAnchor(文本区域,10.0);
AnchorPane.setLeftAnchor(文本区域,10.0);
AnchorPane.setRightAnchor(文本区域,10.0);
root.getChildren().add(textArea);
原始阶段。设置场景(新场景(根,400300));
primaryStage.show();
ScrollBar ScrollBar=lookupVerticalScrollBar(文本区域);
滚动条。设置不透明度(0.0);
scrollBar.visibleProperty().addListener(新的ChangeListener()){
@凌驾

public void已更改(ObservalEvalue此问题;当用户键入或复制粘贴文本时,textArea的高度需要增大或缩小。以下是另一种方法:

public class TextAreaDemo extends Application {

    private Text textHolder = new Text();
    private double oldHeight = 0;

    @Override
    public void start(Stage primaryStage) {
        final TextArea textArea = new TextArea();
        textArea.setPrefSize(200, 40);
        textArea.setWrapText(true);

        textHolder.textProperty().bind(textArea.textProperty());
        textHolder.layoutBoundsProperty().addListener(new ChangeListener<Bounds>() {
            @Override
            public void changed(ObservableValue<? extends Bounds> observable, Bounds oldValue, Bounds newValue) {
                if (oldHeight != newValue.getHeight()) {
                    System.out.println("newValue = " + newValue.getHeight());
                    oldHeight = newValue.getHeight();
                    textArea.setPrefHeight(textHolder.getLayoutBounds().getHeight() + 20); // +20 is for paddings
                }
            }
        });

        Group root = new Group(textArea);
        Scene scene = new Scene(root, 300, 250);
        primaryStage.setScene(scene);
        primaryStage.show();

        //  See the explanation below of the following line. 
        //  textHolder.setWrappingWidth(textArea.getWidth() - 10);  // -10 for left-right padding. Exact value can be obtained from caspian.css
    }

    public static void main(String[] args) {
        launch(args);
    }
}
primaryStage.show();
之后。它适用于用户不使用换行符的长时间打字。但是,这会产生另一个问题。当用户通过单击“backspace”删除文本时,会出现此问题。当textHolder高度发生更改,textArea的高度设置为新值时,问题就出现了。我认为这可能是一个错误,没有深入观察


在这两种情况下,复制粘贴都得到了正确的处理。

我在创建扩展TextArea时遇到了类似的问题。我创建的TextArea看起来像TextField,每次行中没有更多空间时都会垂直扩展。 我已经在stack和其他可用的源代码中测试了所有关于这个主题的解决方案。我发现很少有好的解决方案,但都不够好

经过几个小时的战斗,我想出了这个办法

我扩展了TextArea类,重写了layoutChildren()方法,并在文本高度上添加了一个侦听器

  @Override
  protected void layoutChildren() {
    super.layoutChildren();
    setWrapText(true);
    addListenerToTextHeight();
  }

  private void addListenerToTextHeight() {
    ScrollPane scrollPane = (ScrollPane) lookup(".scroll-pane");
    scrollPane.setHbarPolicy(ScrollBarPolicy.NEVER);
    scrollPane.setVbarPolicy(ScrollBarPolicy.NEVER);

    StackPane viewport = (StackPane) scrollPane.lookup(".viewport");

    Region content = (Region) viewport.lookup(".content");

    Text text = (Text) content.lookup(".text");
    text.textProperty().addListener(textHeightListener(text));
  }

  private InvalidationListener textHeightListener(Text text) {
    return (property) -> {
      // + 1 for little margin
      double textHeight = text.getBoundsInLocal().getHeight() + 1;

      //To prevent that our TextArena will be smaller than our TextField
      //I used DEFAULT_HEIGHT = 18.0
      if (textHeight < DEFAULT_HEIGHT) {
        textHeight = DEFAULT_HEIGHT;
      }

      setMinHeight(textHeight);
      setPrefHeight(textHeight);
      setMaxHeight(textHeight);
    };
  }
@覆盖
受保护的void layoutChildren(){
super.layoutChildren();
setWrapText(真);
addListenerToTextHeight();
}
私有void addListenerToTextHeight(){
滚动窗格滚动窗格=(滚动窗格)查找(“滚动窗格”);
scrollPane.setHbarPolicy(ScrollBarPolicy.NEVER);
scrollPane.setVbarPolicy(ScrollBarPolicy.NEVER);
StackPane viewport=(StackPane)scrollPane.lookup(“.viewport”);
区域内容=(区域)viewport.lookup(“.content”);
Text Text=(Text)content.lookup(“.Text”);
text.textProperty().addListener(textHeightListener(text));
}
私有无效侦听器文本高度侦听器(文本){
返回(属性)->{
//+1表示小余量
double textHeight=text.getBoundsInLocal().getHeight()+1;
//为了防止我们的TextArena比我们的TextField小
//我使用了默认的高度=18.0
如果(文本高度<默认高度){
text高度=默认高度;
}
设置最小高度(文本高度);
setPrefHeight(文本高度);
setMaxHeight(文本高度);
};
}

我使用了前面答案中的一些代码。 GrowthTextAreaIfRequired方法将增加textArea的高度,直到滚动条不可见为止(本例中限制为20行)

这种方法的问题是需要多次重新绘制窗口,直到找到理想的高度

private ScrollBar lookupVerticalScrollBar(Node node) {
    if (node instanceof ScrollBar && ((ScrollBar) node).getOrientation() == Orientation.VERTICAL) {
        return (ScrollBar) node;
    }
    if (node instanceof Parent) {
        ObservableList<Node> children = ((Parent) node).getChildrenUnmodifiable();
        for (Node child : children) {
            ScrollBar scrollBar = lookupVerticalScrollBar(child);
            if (scrollBar != null) {
                return scrollBar;
            }
        }
    }
    return null;
}

private void growTextAreaIfNecessary(TextArea textArea) {
    Platform.runLater(() -> {
        ScrollBar lookupVerticalScrollBar = lookupVerticalScrollBar(textArea);
        int prefRowCount = textArea.getPrefRowCount();

        if (lookupVerticalScrollBar.isVisible() && prefRowCount < 20) {
            textArea.setPrefRowCount(prefRowCount + 1);
            System.out.println("increasing height to: " + (prefRowCount + 1));
            growTextAreaIfNecessary(textArea);
        }
    });
}
private ScrollBar lookupVerticalScrollBar(节点){
if(滚动条的节点实例&((滚动条)节点).getOrientation()==Orientation.VERTICAL){
返回(滚动条)节点;
}
if(父节点的节点实例){
可观察儿童=((Pa)
private ScrollBar lookupVerticalScrollBar(Node node) {
    if (node instanceof ScrollBar && ((ScrollBar) node).getOrientation() == Orientation.VERTICAL) {
        return (ScrollBar) node;
    }
    if (node instanceof Parent) {
        ObservableList<Node> children = ((Parent) node).getChildrenUnmodifiable();
        for (Node child : children) {
            ScrollBar scrollBar = lookupVerticalScrollBar(child);
            if (scrollBar != null) {
                return scrollBar;
            }
        }
    }
    return null;
}

private void growTextAreaIfNecessary(TextArea textArea) {
    Platform.runLater(() -> {
        ScrollBar lookupVerticalScrollBar = lookupVerticalScrollBar(textArea);
        int prefRowCount = textArea.getPrefRowCount();

        if (lookupVerticalScrollBar.isVisible() && prefRowCount < 20) {
            textArea.setPrefRowCount(prefRowCount + 1);
            System.out.println("increasing height to: " + (prefRowCount + 1));
            growTextAreaIfNecessary(textArea);
        }
    });
}