问题描述
我需要在JavaFX 2.1中动态创建窗格上的矩形。接下来我需要在Rectangle上居中/包装/截断Text。文本必须适合矩形。我能够使用以下代码对文本进行居中和包装,但是,如果文本长度太长,它将显示在矩形之外。我想在StackPane中创建类似Label的行为,基本上如果Rectangle增长,Text将随之增长但始终保持在Rectangle的中心,如果Text不能适合Rectangle,它将相应地被截断。
I need to dynamically create Rectangles over Pane in JavaFX 2.1. Next I need to center/wrap/truncate Text over the Rectangle. The text has to fit within the rectangle. I am able to center and wrap the text with the following code, however, if the text length is too long, it will appear out of the rectangle. I want to create the behavior like Label within StackPane, essentially if the Rectangle grows, the Text will grow with it but always remain in the center of the Rectangle and if the Text cannot fit within the Rectangle, it will be truncated accordingly.
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);
我可以使用哪些属性来实现这一目标,还是有更好的方法?
What properties can I use to achieve that or is there a better way of doing this?
推荐答案
下面是一个示例替代实现。
Here is a sample alternate implementation.
它使用 Group
的子类,其中包含 layoutChildren
实现而不是绑定api。
It uses a subclass of Group
with a layoutChildren
implementation rather than the binding 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);
}
}
}
示例应用的示例输出:
几个笔记:
-
通常最好使用
标签
而不是尝试重新创建Label的部分功能。
It is usually best to use a
Label
rather than trying to recreate part of a Label's functionality.
中的布局layoutChildren
方法类似于JavaFX团队在实现JavaFX控件库时使用的方法。他们可能会使用 layoutChildren
而不是绑定布局,但我不知道所有这些原因是什么。
The layout in layoutChildren
approach is a similar to that used by the JavaFX team in implementing the JavaFX control library. There are probably reasons they use layoutChildren
rather than binding for layout, but I am not aware of what all of those reasons are.
我找到了简单的布局,使用JavaFX库中的预构建控件和布局管理器是最好的(例如,上面的控件可以使用只是StackPane中的标签或文本)。我无法从内置布局获得我需要的布局,然后我将使用绑定来补充它们的使用,我发现它也很容易使用。我不需要那么多使用 layoutChildren
。这可能只是扩展到布局复杂节点组的问题 - 最有可能在 layoutChildren
方法中执行计算的效果更好,并且在应用时可能更容易使用和调试复杂的节点组。
I find for simple layouts, using the pre-built controls and layout managers from the JavaFX library is best (for instance the above control could have been implemented using just a Label or Text in StackPane). Where I can't quite get the layout I need from the built-in layouts, then I will supplement their usage with bindings, which I find also very easy to work with. I don't run into the need to use layoutChildren
that much. It's probably just a question of scaling up to lay out complex node groups - most likely doing the calculations in the layoutChildren
method performs better and may be easier to work with and debug when applied to complex node groups.
而不是通过计算文本大小并从中删除多余的字符来截断 Text
一个字符串
作为标签
,代码调用 setClip
在文本节点上以可视方式将其剪切为矩形的大小。如果您希望截断 Text
更像是 Label
,那么您可以查看 JavaFX实用程序类,用于计算剪切文本。
Rather than truncating Text
by calculating a text size and eliding extra characters from a String
as a Label
does, the code instead calls setClip
on the text node to visually clip it to the rectangle's size. If instead you would like to truncate Text
more like a Label
, then you could look at the code for the JavaFX utility class which does the computation of clipped text.
问题中的示例代码无法编译,因为它缺少 wrappingWidthProperty
表达式的括号,它使用 getValue
和 getWidth
绑定表达式中的方法,这是不可能的 - 而是需要在 boundsInLocalProperty
上使用监听器。
The sample code in the question does not compile because it is missing a bracket on the wrappingWidthProperty
expression and it uses getValue
and getWidth
methods inside a bind expression, which is not possible - instead it needs to use a listener on the boundsInLocalProperty
.
此外,还创建了一个演示将放置在带有矩形背景的Label中的文本添加到窗格,通过绑定精确控制标记矩形的x,y位置。
Also, created a small sample app demoing adding text placed in a Label with a rectangular background to a Pane with precise control over the x,y position of the labeled rectangle via binding.
这篇关于如何居中/包装/截断Text以适应JavaFX 2.1中的Rectangle?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!