Dave The Dane
Dave The Dane

Reputation: 869

How to set JavaFX Dialog Label width

I'm trying to set the width of a JavaFX Dialog to fit my Text.

I know how to do it, but there is a "Fudge Factor" of 32 that I would like to understand.

Can anyone explain how I can determine the value empirically?

I'm using the Zulu OpenJDK 17 with bundled JavaFX under Windows 10.

Here's some example code:

import static javafx.scene.control.Alert.AlertType.INFORMATION;

import javafx.application.Application;
import javafx.scene.control.*;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class AlertWide extends Application {

    private static final String INFO_TEXT = """
            A couple of lines...
            1) Line 1 is quite short
            2) Line 2 is too wide to fit in the standard Alert Label, so it needs to be widened manually, that is to say, once a year
            3) the last line
            """;

    public static void main(final String[] args) {
        launch(args);
    }

    @Override
    public void start(final Stage primaryStage) throws Exception {

        final var infoWidth = new Text(INFO_TEXT).getBoundsInLocal().getWidth();

        final var alert     = new Alert(INFORMATION);
        ;         alert.setContentText(INFO_TEXT);

        ;                                        alert.showAndWait();
        setLabelWidth(alert, infoWidth     );    alert.showAndWait();
        setLabelWidth(alert, infoWidth + 32);    alert.showAndWait(); // TODO why 32?
    }

    private void setLabelWidth(final Alert alert, final double preferredLabelWidth) {
        alert.getDialogPane().getChildren().forEach(node -> {
            if (node  instanceof  Label  nodeLabel) {
                nodeLabel.setPrefWidth(preferredLabelWidth);
            }
        });
    }
}

Upvotes: 2

Views: 124

Answers (1)

Dave The Dane
Dave The Dane

Reputation: 869

Having delved into the depths of Dialog, I found a very simple solution.
Rather than iterating through the DialogPane's children, I simply replaced the Label with a new Instance.

P.S. "replaced" is not strictly speaking correct: the built-in DialogPane Label is set to unmanaged & invisible & so takes no part in the rendering.

The following was just fine for my purposes:

import static javafx.scene.control.Alert.AlertType.INFORMATION;

import javafx.application.Application;
import javafx.scene.control.*;
import javafx.stage.Stage;

public class AlertWideSetContent extends Application {

    private static final String INFO_TEXT = """
            A couple of lines...
            1) Line 1 is quite short
            2) Line 2 is too wide to fit in the standard Alert Label, so it needs to be widened manually, that is to say, once a year
            3) the last line
            """;

    public static void main(final String[] args) {
        launch(args);
    }

    @Override
    public void start(final Stage primaryStage) throws Exception {

        final var alert = new Alert(INFORMATION);
        ;         alert.getDialogPane().setContent(new Label(INFO_TEXT));
        ;         alert.showAndWait();
    }
}

But, as @kleopatra observed, setting the Preferred Width to -1 (USE_COMPUTED_SIZE) does it too:

import static javafx.scene.control.Alert.AlertType.INFORMATION;

import javafx.application.Application;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.stage.Stage;

public class AlertWideUseComputedSize extends Application {

    private static final String INFO_TEXT = """
            A couple of lines...
            1) Line 1 is quite short
            2) Line 2 is too wide to fit in the standard Alert Label, so it needs to be widened manually, that is to say, once a year
            3) the last line
            """;

    public static void main(final String[] args) {
        launch(args);
    }

    @Override
    public void start(final Stage primaryStage) throws Exception {

        final var alert = new Alert   (INFORMATION);
        ;         alert.setContentText(INFO_TEXT );

        for (final Node node : alert.getDialogPane().getChildren()) {
            if (node  instanceof  Label  nodeLabel) {
                nodeLabel.setPrefWidth(Label.USE_COMPUTED_SIZE);
            }
        }
        alert.showAndWait();
    }
}

Upvotes: 2

Related Questions