如何在 Javafx 中对齐对话框窗格的确定按钮?
How To Align Ok Button Of A Dialog Pane In Javafx?
我想对齐,即 Position CENTER 和 DialogPane 的 OK 按钮。我试过下面的代码,但它不起作用。
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();
这是一种 hack,但您可以这样做:
okButton.translateXProperty().bind(okButton.prefWidthProperty().divide(-2));
DialogPane 是水平居中的,所以减去 okButton 的一半宽度就可以了。
但我认为这是一个非常肮脏的解决方案 ;-)
在对话框的 ButtonBar 中居中按钮实际上非常难以以非 hacky 方式实现。
以下是我能想到的最佳解决方案。它依赖于 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)。左右垫片的组合最终使按钮居中对齐。该解决方案还覆盖 ButtonBar 创建以停止 ButtonSkin 内部重新排序和执行额外的按钮布局,因为当它这样做时,您无法真正可靠地自己自定义布局。
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);
}
}
我不太喜欢这个解决方案的原因是动态 CSS 查找有点违反 API 封装,因为控件的 JavaFX 场景图的 CSS 结构比如按钮栏并不是他们真正的一部分 public API。但是,我认为使用 JavaFX 8 的现有 public APIs 和默认的 ButtonBar 外观真的不可能在 ButtonBar 中获得居中按钮。
另一种方法是为与对话框关联的 ButtonBar 创建自定义外观,但这种方法非常困难,我不推荐将其用于此任务。
基本上,所有这一切的要点是,尽可能保留对话框的默认按钮布局和顺序,而不是尝试自定义对话框按钮布局。如果你确实想要完全自定义布局到按钮放置等级别,那么你最好通过 subclassing Stage 创建你自己的自定义对话框 class 而不是基于你的自定义对话框在内置对话框 class.
上实现
相关但略有不同的信息位于:
- Enter Key Event Is Not Working On Dialog In Javafx?
根据@ManuelSeiche 的回答,以下是计算到中心的精确距离的方法:
@FXML private Dialog<ButtonType> dialog;
@FXML private ButtonType btClose;
@FXML
private void initialize()
{
dialog.setOnShown(event ->
{
Platform.runLater(() ->
{
Button btnClose = (Button) dialog.getDialogPane().lookupButton(btClose);
HBox hBox = (HBox) btnClose.getParent();
double translateAmount = hBox.getWidth() / 2.0 - btnClose.getWidth() / 2.0 - hBox.getPadding().getLeft();
btnClose.translateXProperty().set(-translateAmount);
});
});
}
我试图在 Alert
中将“确定”按钮居中,但我不确定这是错误还是功能 (Java8),但可以通过设置新按钮将单个按钮居中:
alert.getButtonTypes().set(0, new ButtonType("OK", ButtonBar.ButtonData.LEFT));
只要有一个带ButtonData.LEFT
的按钮,它就位于按钮面板的中间。显然,此解决方案不适用于具有多个按钮的面板,但它可能有助于定位单个 OK 按钮。
将此方法添加到您的代码中,并在您需要对齐对话框或警报中的按钮时调用它:
private void centerButtons(DialogPane dialogPane) {
Region spacer = new Region();
ButtonBar.setButtonData(spacer, ButtonBar.ButtonData.BIG_GAP);
HBox.setHgrow(spacer, Priority.ALWAYS);
dialogPane.applyCss();
HBox hboxDialogPane = (HBox) dialogPane.lookup(".container");
hboxDialogPane.getChildren().add(spacer);
}
这样称呼:centerButtons(dialog.getDialogPane);
我想对齐,即 Position CENTER 和 DialogPane 的 OK 按钮。我试过下面的代码,但它不起作用。
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();
这是一种 hack,但您可以这样做:
okButton.translateXProperty().bind(okButton.prefWidthProperty().divide(-2));
DialogPane 是水平居中的,所以减去 okButton 的一半宽度就可以了。 但我认为这是一个非常肮脏的解决方案 ;-)
在对话框的 ButtonBar 中居中按钮实际上非常难以以非 hacky 方式实现。
以下是我能想到的最佳解决方案。它依赖于 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)。左右垫片的组合最终使按钮居中对齐。该解决方案还覆盖 ButtonBar 创建以停止 ButtonSkin 内部重新排序和执行额外的按钮布局,因为当它这样做时,您无法真正可靠地自己自定义布局。
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);
}
}
我不太喜欢这个解决方案的原因是动态 CSS 查找有点违反 API 封装,因为控件的 JavaFX 场景图的 CSS 结构比如按钮栏并不是他们真正的一部分 public API。但是,我认为使用 JavaFX 8 的现有 public APIs 和默认的 ButtonBar 外观真的不可能在 ButtonBar 中获得居中按钮。
另一种方法是为与对话框关联的 ButtonBar 创建自定义外观,但这种方法非常困难,我不推荐将其用于此任务。
基本上,所有这一切的要点是,尽可能保留对话框的默认按钮布局和顺序,而不是尝试自定义对话框按钮布局。如果你确实想要完全自定义布局到按钮放置等级别,那么你最好通过 subclassing Stage 创建你自己的自定义对话框 class 而不是基于你的自定义对话框在内置对话框 class.
上实现相关但略有不同的信息位于:
- Enter Key Event Is Not Working On Dialog In Javafx?
根据@ManuelSeiche 的回答,以下是计算到中心的精确距离的方法:
@FXML private Dialog<ButtonType> dialog;
@FXML private ButtonType btClose;
@FXML
private void initialize()
{
dialog.setOnShown(event ->
{
Platform.runLater(() ->
{
Button btnClose = (Button) dialog.getDialogPane().lookupButton(btClose);
HBox hBox = (HBox) btnClose.getParent();
double translateAmount = hBox.getWidth() / 2.0 - btnClose.getWidth() / 2.0 - hBox.getPadding().getLeft();
btnClose.translateXProperty().set(-translateAmount);
});
});
}
我试图在 Alert
中将“确定”按钮居中,但我不确定这是错误还是功能 (Java8),但可以通过设置新按钮将单个按钮居中:
alert.getButtonTypes().set(0, new ButtonType("OK", ButtonBar.ButtonData.LEFT));
只要有一个带ButtonData.LEFT
的按钮,它就位于按钮面板的中间。显然,此解决方案不适用于具有多个按钮的面板,但它可能有助于定位单个 OK 按钮。
将此方法添加到您的代码中,并在您需要对齐对话框或警报中的按钮时调用它:
private void centerButtons(DialogPane dialogPane) {
Region spacer = new Region();
ButtonBar.setButtonData(spacer, ButtonBar.ButtonData.BIG_GAP);
HBox.setHgrow(spacer, Priority.ALWAYS);
dialogPane.applyCss();
HBox hboxDialogPane = (HBox) dialogPane.lookup(".container");
hboxDialogPane.getChildren().add(spacer);
}
这样称呼:centerButtons(dialog.getDialogPane);