如何居中/包装/截断Text以适应JavaFX 2.1中的Rectangle?

时间:2012-05-17 00:18:44

标签: javafx javafx-2

我需要在JavaFX 2.1中动态创建窗格上的矩形。接下来我需要在Rectangle上居中/包装/截断Text。文本必须适合矩形。我能够使用以下代码对文本进行居中和包装,但是,如果文本长度太长,它将显示在矩形之外。我想在StackPane中创建类似Label的行为,基本上如果Rectangle增长,Text将随之增长但始终保持在Rectangle的中心,如果Text不能适合Rectangle,它将相应地被截断。

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);

我可以使用哪些属性来实现这一目标,还是有更好的方法来实现这一目标?

1 个答案:

答案 0 :(得分:5)

以下是替代实施示例。

它使用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. layoutChildren方法中的布局类似于JavaFX团队在实现JavaFX控件库时使用的布局。他们可能会使用layoutChildren而不是绑定布局,但我不知道所有这些原因是什么。

  3. 我找到了简单的布局,使用JavaFX库中的预构建控件和布局管理器是最好的(例如,上面的控件可能只使用StackPane中的Label或Text实现)。我无法从内置布局获得我需要的布局,然后我将使用绑定来补充它们的使用,我发现它也很容易使用。我不需要那么多地使用layoutChildren。这可能只是扩展到布局复杂节点组的问题 - 最有可能在layoutChildren方法中进行计算表现更好,并且在应用于复杂节点组时可能更容易使用和调试。

  4. 而不是通过计算文本大小并将Text中的额外字符作为String删除来截断Label,而是代码调用setClip文本节点可视地将其剪切为矩形的大小。如果您希望将Text更像Label,那么您可以查看JavaFX utility class的代码来执行剪切文本的计算。

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

  6. 此外,创建了一个small sample app演示文稿,将带有矩形背景的标签放置在窗格中,通过绑定精确控制标记矩形的x,y位置。