JavaFX 如何在更改文本后强制 Label 更新其 prefWidth?

JavaFX how to force Label to update its prefWidth after changing the text?

其实很简单:我希望我的 Label 更新它的 prefWidth 以在文本发生变化时使文本适应自身。

最初 Label 的文本是 nullprefWidth-1.0 没有手动设置。因此,当 Labels 文本在运行时更改时,prefWidth 仍然是 -1.0 并且 Label 显示“...”而不是设置文本,因为它太小了。

LabelHBox 内。 HBoxs prefWidth 绑定到其子 prefWidths 的总和,并且 HBox 有足够的 space 增长。 这是一些要重现的代码:

public class Spielwiese extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage window) {
        Label label = new Label();
        Button button = new Button("Fill Label");
        button.setOnAction(e -> label.setText("Some Text"));
        HBox box = new HBox(label, button);
        box.prefWidthProperty().bind(label.prefWidthProperty().add(button.prefWidthProperty()));

        window.setScene(new Scene(new StackPane(box)));
        window.setWidth(800);
        window.setHeight(600);
        window.show();
    }
}

如何让 Label 更新其宽度以适合其文本?

编辑:场景的根是 StackPane 而不是 Pane

尝试在 min/pref/max 大小的窗格上使用绑定来执行布局从来都不是一个好主意。 HBox 已经知道如何计算其首选宽度,并且默认情况下完全按照您的要求进行(简单版本是将其计算为其子节点的首选宽度之和,但实际上它更复杂,因为它考虑了间距、填充等)。

控件和布局窗格的 prefWidth 默认值是标记值 Region.USE_COMPUTED_SIZE,它只是一个标志,告诉节点计算其首选大小,以便向正在放置的任何人报告出来。标签将通过检查显示其文本(和图形)所需的大小来计算其首选大小,类似于按钮,布局窗格将检查其子节点的首选大小。 Region.USE_COMPUTED_SIZE is -1.0 的实际值,这就是为什么您在调用 getPrefWidth().

时总是看到该值的原因

HBox 被展开以填充堆栈窗格的原因是因为这正是 StackPane 的行为。来自 docs:

The stackpane will attempt to resize each child to fill its content area.

您可以通过使用不具有该行为的不同根窗格来防止这种情况(例如普通 Pane 或另一个 HBox 等):

public class Spielwiese extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage window) {
        Label label = new Label();
        Button button = new Button("Fill Label");
        button.setOnAction(e -> label.setText("Some Text"));
        HBox box = new HBox(label, button);

        window.setScene(new Scene(new HBox(box)));
        window.setWidth(800);
        window.setHeight(600);
        window.show();
    }
}

或者将您的 HBox 包裹在另一个窗格中(因此包裹它的窗格将填充 StackPane,但您的 box 不会填充其父窗格):

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class Spielwiese extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage window) {
        Label label = new Label();
        Button button = new Button("Fill Label");
        button.setOnAction(e -> label.setText("Some Text"));
        HBox box = new HBox(label, button);

        window.setScene(new Scene(new StackPane(new HBox(box))));
        window.setWidth(800);
        window.setHeight(600);
        window.show();
    }
}

或者强制 box 不超过其首选大小,将其 maxWidth 设置为使用首选大小:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class Spielwiese extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage window) {
        Label label = new Label();
        Button button = new Button("Fill Label");
        button.setOnAction(e -> label.setText("Some Text"));
        HBox box = new HBox(label, button);
        box.setMaxWidth(Region.USE_PREF_SIZE);

        window.setScene(new Scene(new StackPane(box)));
        window.setWidth(800);
        window.setHeight(600);
        window.show();
    }
}

您没有在问题中说明 为什么 您想要使用 StackPane 作为 HBox 的父项。由于 StackPane 的唯一功能是按 z 顺序将其子节点堆叠在一起,如果您使用堆叠窗格,您可能会在其顶部或后面添加其他节点。因此,实际上可能根本没有必要阻止 HBox 调整大小(因为它不会影响堆叠),但也许仅仅确保 HBox 的对齐 属性 就足够了](以及 StackPane 的其他子节点)设置为与 StackPane 相同(默认情况下居中)。 IE。你可能只需要 box.setAlignment(Pos.CENTER).