Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How To Align Ok Button Of A Dialog Pane In Javafx?

I want to align i.e Position CENTER an OK button of a DialogPane. I have tried the below code but its not working.

Dialog dialog = new Dialog();
DialogPane dialogPane = dialog.getDialogPane();
dialogPane.setStyle("-fx-background-color: #fff;");

        // Set the button types.
ButtonType okButtonType = new ButtonType("Ok", ButtonBar.ButtonData.OK_DONE);
ButtonType cancelButtonType = new ButtonType("Cancel", ButtonBar.ButtonData.CANCEL_CLOSE);
dialog.getDialogPane().getButtonTypes().addAll(okButtonType, cancelButtonType);
dialogPane.lookupButton(cancelButtonType).setVisible(false);

        // Testing
Button okButton = (Button) dialog.getDialogPane().lookupButton(okButtonType);
okButton.setAlignment(Pos.CENTER);
        // End Testing

dialog.showAndWait();
like image 391
Vikas Singh Avatar asked Mar 15 '16 11:03

Vikas Singh


2 Answers

Centering buttons in the ButtonBar of a Dialog is actually surprisingly difficult to achieve in a non-hacky way.

Below is the best solution I could come up with. It relies upon a dynamic CSS lookup of the HBox for the button container, to which it then adds a spacer region on the right to push the buttons to the left (the default ButtonSkin implementation already places an implicit spacer of the left which pushes the buttons to the right, which I determined using ScenicView). The combination of the left and right spacers end up aligning the buttons in the center. The solution also overrides the ButtonBar creation to stop the ButtonSkin internally reordering and performing additional layout of buttons, as, when it does that, you can't really reliably customize the layout yourself.

centered button

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;

import java.util.Optional;

public class CenteredDialogButtons extends Application {
    @Override
    public void start(Stage stage) {
        Button show = new Button("Show Dialog");

        Dialog<ButtonType> dialog = new Dialog<>();
        DialogPane dialogPane = new DialogPane() {
            @Override
            protected Node createButtonBar() {
                ButtonBar buttonBar = (ButtonBar) super.createButtonBar();
                buttonBar.setButtonOrder(ButtonBar.BUTTON_ORDER_NONE);

                return buttonBar;
            }
        };
        dialog.setDialogPane(dialogPane);
        dialogPane.getButtonTypes().addAll(ButtonType.OK);
        dialogPane.setContentText("Centered Button");

        Region spacer = new Region();
        ButtonBar.setButtonData(spacer, ButtonBar.ButtonData.BIG_GAP);
        HBox.setHgrow(spacer, Priority.ALWAYS);
        dialogPane.applyCss();
        HBox hbox = (HBox) dialogPane.lookup(".container");
        hbox.getChildren().add(spacer);

        show.setOnAction(e -> {
            Optional<ButtonType> result = dialog.showAndWait();
            if (result.isPresent() && result.get() == ButtonType.OK) {
                System.out.println("OK");
            }
        });

        StackPane layout = new StackPane(
                show
        );
        layout.setPadding(new Insets(50));

        Scene scene = new Scene(layout);

        stage.setScene(scene);
        stage.show();
    }

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

The reason I don't quite like this solution is that the dynamic CSS lookups kind of violate API encapsulation, as the CSS structure of the JavaFX scene graphs for controls such as button bars is not really part of their public API. However, I don't think it is really possible to get centered buttons in a ButtonBar using the existing public APIs for JavaFX 8 and a default ButtonBar skin.

An alternate approach would be to create a custom skin for the ButtonBar associated with the dialog, but that approach is quite difficult and I wouldn't recommend it for this task.

Basically, the takeaway from all this is, just leave the default button layout and order for dialogs whenever you can, rather than trying to customize the dialog button layout. If you do want to have completely customized layout to the level of things like button placement, then you may be better off just creating your own custom dialog class by subclassing Stage rather than basing your custom dialog implementation on the in-built dialog class.

Related, but slightly different information is in:

  • Enter Key Event Is Not Working On Dialog In Javafx?
like image 179
jewelsea Avatar answered Sep 20 '22 04:09

jewelsea


I tried to center OK button in Alert and I am not sure if this is bug or feature (Java8) but it was possible to center single button by setting new one:

alert.getButtonTypes().set(0, new ButtonType("OK", ButtonBar.ButtonData.LEFT));

As long as there is only one button with ButtonData.LEFT, it is centered in the middle of button panel. Obviously this solution does not work for panel with multiple buttons, but it might help to position single OK button.

like image 27
Griva Avatar answered Sep 20 '22 04:09

Griva