如何在JavaFX 2.1中将文本居中/换行/截断以适应矩形?

3

我需要在JavaFX 2.1中动态创建Pane上的矩形。接下来,我需要在矩形上居中/换行/截断文本。文本必须适合矩形内。我能够通过以下代码对文本进行居中和换行,但是如果文本长度过长,它将出现在矩形外面。我想创建类似于StackPane内的标签的行为,实际上,如果矩形增长,则文本会随之增长,但始终保持在矩形的中心,如果文本无法适合矩形,则相应地被截断。

Rectangle r;

Text t;

...

//center and wrap text within rectangle

t.wrappingWidthProperty().bind(rect.widthProperty().multiply(0.9);

t.xProperty().bind(rect.xProperty().add(rect.widthProperty().subtract(t.boundsInLocalProperty().getValue().getWidth().divide(2)));

t.yProperty().bind(rect.yProperty().add(rect.heightProperty().divide(2)));

t.setTextAlignment(TextAlignment.CENTER);

t.setTextOrigin(VPos.CENTER);

我该使用什么属性来实现这样的效果,或者有更好的方法吗?

为什么不使用带有背景色的标签? - jewelsea
1个回答

6
这是一个示例替代实现。
它使用 Group 的子类,具有 layoutChildren 实现,而不是绑定 API。
import javafx.application.Application;
import javafx.beans.property.StringProperty;
import javafx.geometry.VPos;
import javafx.scene.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.*;
import javafx.stage.Stage;

public class TextInRectangle extends Application {
  public static void main(String[] args) throws Exception { launch(args); }
  public void start(final Stage stage) throws Exception {
    TextBox text = new TextBox("All roads lead to Rome", 100, 100);
    text.setLayoutX(30);
    text.setLayoutY(20);
    final Scene scene = new Scene(text, 160, 140, Color.CORNSILK);
    stage.setScene(scene);
    stage.show();
  }

  class TextBox extends Group {
    private Text text;
    private Rectangle rectangle;
    private Rectangle clip;
    public StringProperty textProperty() { return text.textProperty(); }

    TextBox(String string, double width, double height) {
      this.text = new Text(string);
      text.setTextAlignment(TextAlignment.CENTER);
      text.setFill(Color.FORESTGREEN);
      text.setTextOrigin(VPos.CENTER);
      text.setFont(Font.font("Comic Sans MS", 25));
      text.setFontSmoothingType(FontSmoothingType.LCD);

      this.rectangle = new Rectangle(width, height);
      rectangle.setFill(Color.BLACK);

      this.clip = new Rectangle(width, height);
      text.setClip(clip);

      this.getChildren().addAll(rectangle, text);
    }

    @Override protected void layoutChildren() {
      final double w = rectangle.getWidth();
      final double h = rectangle.getHeight();
      clip.setWidth(w);
      clip.setHeight(h);
      clip.setLayoutX(0);
      clip.setLayoutY(-h/2);

      text.setWrappingWidth(w * 0.9);
      text.setLayoutX(w / 2 - text.getLayoutBounds().getWidth() / 2);
      text.setLayoutY(h / 2);
    }
  }
}

示例应用程序的样本输出:

enter image description here

几点注意:

  1. 通常最好使用 Label 而不是尝试重新创建 Label 的一部分功能。

  2. 在实现 JavaFX 控件库时,JavaFX 团队使用的布局方式与 layoutChildren 方法类似。他们可能有使用 layoutChildren 而不是绑定进行布局的原因,但我不知道所有原因。

  3. 对于简单的布局,我发现使用 JavaFX 库中预先构建的控件和布局管理器最好(例如上面的控件可以使用 StackPane 中的 Label 或 Text 来实现)。当我无法从内置布局中获取所需的布局时,我会使用绑定来补充它们的使用,我发现这也非常容易使用。我不经常需要使用 layoutChildren。这可能只是一个关于扩展以布置复杂节点组的问题 - 最可能的是,在 layoutChildren 方法中执行计算并应用于复杂节点组时,性能更好,而且可能更容易使用和调试。

  4. 代码不会像 Label 那样通过计算文本大小并省略字符串中的额外字符来截断 Text,而是调用文本节点上的 setClip 方法将其视觉裁剪到矩形的大小。如果您想更像 Label 那样截断 Text,则可以查看 JavaFX 实用程序类 的代码,该类执行截断文本的计算。

  5. 问题中的示例代码无法编译,因为在 wrappingWidthProperty 表达式上缺少一个括号,并且它在绑定表达式中使用了 getValuegetWidth 方法,这是不可能的 - 相反,它需要在 boundsInLocalProperty 上使用监听器。

此外,创建了一个小示例应用程序,演示如何将放置在带有矩形背景的标签中的文本添加到面板中,并通过绑定精确控制标记矩形的x、y位置。

在正常情况下,我很乐意使用Label或现有布局类和Label的组合来完成这个任务,但我需要精确控制标记矩形的x、y位置,因此将矩形绑定到基本Pane上。我希望我能够使用Text类做同样的事情,使用属性API将其绑定到矩形上。所示的文本绑定代码实际上是在监听器方法中调用的,当矩形宽度属性发生变化时...我将研究使用Group。感谢大家的评论。 - Jason
更新答案以引用一个演示基于绑定方法的小样例应用程序。 - jewelsea
jewelsea,感谢您抽出时间分享如此精美的代码。我现在改用Label了。 - Jason

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接