JavaFX:带有自动换行的TextFlow的最佳宽度

时间:2013-10-26 22:28:49

标签: javafx word-wrap bounds javafx-8

使用Textflow.setMaxWidth(double)我可以实现文本换行。

但是我怎样才能调整TextFlow之后的宽度,使其基于实际的包裹位置?

换句话说,如何让TextFlow边界捕捉到它的所有子Text,这样就可以摆脱右边的空白区域:

actual vs. desired

**编辑** 我在这个问题上取得了一些进展。我的类派生自TextFlow现在包含:

    double maxChildWidth = 0;
    for (Node child : getManagedChildren()) {
        double childWidth = child.getLayoutBounds().getWidth();
        maxChildWidth = Math.max(maxChildWidth, childWidth);
    }
    double insetWidth = getInsets().getLeft() + getInsets().getRight();
    double adjustedWidth = maxChildWidth + insetWidth;
    setMaxWidth(adjustedWidth);

不幸的是,这种方法似乎还不准确,因为在某些情况下会导致第二次文本流更改。

1 个答案:

答案 0 :(得分:1)

您在问题中发布的解决方案似乎对我的测试工作正常。

在下面的图像中,场景已调整大小以触发TextFlow的换行(以红色显示)。在右侧,TextFlow并不完全包裹在最后一个可见字符处,因为行中的最后一个字符是空格,因此包装发生在空格之后。考虑到TextFlow边界是根据需要刷新所有文本。

wrapped box

如果松开最大宽度,则会获得文本框的默认行为,即宽度增大(如下所示)。

unclamped max width

import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.text.*;
import javafx.stage.Stage;

public class TextFlowWrapper extends Application {

  @Override
  public void start(Stage stage) {
    TextFlow textFlow = new TextFlow(
      new Text(
        "Box with long description that should be wrapped"
      )
    ) {
      @Override
      protected void layoutChildren() {
        super.layoutChildren();

        double maxChildWidth = 0;
        for (Node child : getManagedChildren()) {
          double childWidth = child.getLayoutBounds().getWidth();
          maxChildWidth = Math.max(maxChildWidth, childWidth);
        }
        double insetWidth = getInsets().getLeft() + getInsets().getRight();
        double adjustedWidth = maxChildWidth + insetWidth;

        setMaxWidth(adjustedWidth);
      }
    };

    textFlow.setStyle("-fx-background-color: red");
    textFlow.setMaxWidth(Control.USE_PREF_SIZE);
    textFlow.setMaxHeight(Control.USE_PREF_SIZE);

    Button unclamp = new Button("Unclamp max width");
    unclamp.setOnAction(e -> textFlow.setMaxWidth(Double.MAX_VALUE));

    StackPane wrappedText = new StackPane(textFlow);

    VBox vbox = new VBox(
        unclamp,
        wrappedText
    );
    VBox.setVgrow(wrappedText, Priority.ALWAYS);

    Scene scene = new Scene(
        vbox
    );

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

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

解决方案有点像黑客攻击,您可能想要问一位JavaFX开发人员对openjfx developer list的一些输入。也许一些额外的api就像一个布尔包属性,有条件地更新内部文本流布局算法以自动将文本流打包到最小尺寸将是一种更好地做到这一点的方法。部分困难在于,以这样一种方式编写这个问题很容易理解是一个难题。还很难说这是否是某种角落情况,或者是否会有更多人会遇到这种情况(因此可能证明额外API的复杂性)。