1

我有一个简单的控件,它只是一个标签和一个 VBox。目的是通知用户程序中的事物。我想做到这一点,以便标签可以正确地随场景缩放。我有完成这项任务的方法(我认为,无论如何):

public void reScaleX(){
    this.Message.setScaleX(( //Message is the Label Variables name.
        this.getWidth() - 40 //40 is the 20 + 20 padding given to the control.
        ) / this.Message.getBoundsInLocal().getWidth()
    );
}

public void reScaleY(){
    this.Message.setScaleY((
        this.getHeight() - 40 //40 is the 20 + 20 padding given to the control.
        ) / this.Message.getBoundsInLocal().getHeight()
    );
}

我在 Initialize 方法中为控件的 Width 和 Height 属性添加了一个侦听器:

@Override public void initialize(URL location, ResourceBundle resources){
    this.widthProperty().addListener((
        ObservableValue<? extends Number> obsV, Number oldV, Number newV
    ) -> this.reScaleX());
    this.heightProperty().addListener((
        ObservableValue<? extends Number> obsV, Number oldV, Number newV
    ) -> this.reScaleY());
}

但问题是它的行为很奇怪(有时它会重新缩放,有时它不会)。我还尝试将侦听器添加到放置控件的舞台的高度和宽度属性,以使其在控件调整大小时重新缩放:

    this.PreviewStage.widthProperty().addListener((
        ObservableValue<? extends Number> obsV, Number oldV, Number newV
    ) ->
        this.PreviewPlaque.reScaleX()
    ); this.PreviewStage.heightProperty().addListener((
        ObservableValue<? extends Number> obsV, Number oldV, Number newV
    ) ->
        this.PreviewPlaque.reScaleY()
    ); 

但它的行为仍然不正确。

我觉得我做错了,但我不知道如何做对。在这样的表单上重新缩放控件的正确方法是什么?有没有更好的方法来实现我正在寻找的结果?

4

2 回答 2

3

如果缩放标签,它将对其父级产生布局影响,再次导致宽度/高度属性发生变化,从而触发致命的布局递归。

我不是 100% 确定你想要实现什么。

a) 使文本以某种方式居中在可用空间中:

void testLabelPlains1(VBox box) {
    box.setFillWidth(true);

    Label first = new Label("first");
    first.setAlignment(Pos.CENTER);
    first.setMaxWidth(Double.MAX_VALUE);
    first.setMaxHeight(Double.MAX_VALUE);
    VBox.setVgrow(first, Priority.ALWAYS);

    box.getChildren().addAll(first);
}

b)在可调整大小的标签内缩放字体大小:

void testLabelPlains2(VBox box) {
    box.setFillWidth(true);

    Label first = new Label("first");
    first.setAlignment(Pos.CENTER);
    first.setMaxWidth(Double.MAX_VALUE);
    first.setMaxHeight(Double.MAX_VALUE);
    VBox.setVgrow(first, Priority.ALWAYS);

    first.heightProperty().addListener(p -> {
        first.setFont(first.getFont().font(first.getHeight()*0.7));
    });

    box.getChildren().addAll(first);
}

c) 在 X/Y 方向上真正线性缩放文本

void testLabelPlains3(VBox box) {        
    Text first = new Text("first");

    box.heightProperty().addListener(p -> {
        first.setScaleY(0.8*box.getHeight()/20);
        first.setTranslateY(box.getHeight()/2);
    });
    box.widthProperty().addListener(p -> {
        first.setScaleX(0.8*box.getWidth()/30);
        first.setTranslateX(box.getWidth()/2);
    });

    box.getChildren().addAll(first);
}

...当然,硬编码的数字必须来自文本的实际布局大小。

于 2014-11-06T08:00:09.363 回答
1

好的,所以我对这个问题的解决方案有两个:

1(最关键):我一直忘记记住,为了缩放控件,尺寸必须是相对静态的:也就是说,不要将最大宽度/高度设置为大数字。此外,不要让控件垂直或水平增长。这是我的第一个(也是最常见和最令人沮丧的错误)。

2:绑定 scaleX 和 scaleY 属性:这来自我最近对属性知识的了解。有很多方法可以完成缩放方法,但这对我来说感觉最干净。

this.Message.scaleXProperty().bind(Bindings.createDoubleBinding(() -> {
    return (this.getWidth() - 40.0) / this.Message.getWidth();
}, this.widthProperty())
); this.Message.scaleYProperty().bind(Bindings.createDoubleBinding(() -> {
    return (this.getHeight() - 40.0) / this.Message.getHeight();
}, this.heightProperty()));

所以回顾一下: 1:要缩放的控件的大小必须是静态的。2:绑定控件scaleX和scaleY属性。

于 2014-11-06T13:39:05.733 回答