考虑带有两个按钮的JavaFX(8)Alert对话框:
Alert alert = new Alert(AlertType.CONFIRMATION);
ButtonType bttYes = new ButtonType("Yes");
ButtonType bttNo = new ButtonType("No, continue without restart");
alert.getButtonTypes().clear();
alert.getButtonTypes().addAll(bttYes, bttNo);
alert.showAndWait();
生成的对话框有两个按钮,两个宽度相同,看起来很傻。
有没有办法将两个按钮调整为实际文字长度?
答案 0 :(得分:2)
扩展Alert
的{{1}}包裹DialogPane
。 Dialog
分为不同的部分,其中一部分是"按钮栏"。正如预期的那样,此部分是所有按钮的所在位置。按钮栏可以是任意DialogPane
,但Node
的默认实现使用恰当命名的ButtonBar
控件。这在DialogPane.createButtonBar()
(强调我的)中记录:
子类可以重写此方法以提供按钮栏。请注意,通过重写此方法,开发人员必须承担多项职责:
- 开发人员必须立即遍历所有按钮类型,并依次为每个按钮类型调用createButton(ButtonType)。
- 开发人员必须在按钮类型列表中添加一个侦听器,当此列表发生更改时,请根据需要更新按钮栏。
- 同样,开发人员必须注意对可扩展内容属性的更改,添加和删除详细信息按钮(通过createDetailsButton()方法创建)。
醇>此方法的默认实现创建并返回一个新的ButtonBar实例。
默认情况下,DialogPane
会将所有按钮的大小调整为最宽的按钮的宽度。
统一按钮大小调整
默认情况下,所有按钮在ButtonBar中的大小均匀,这意味着所有按钮都采用最宽按钮的宽度。可以在每个按钮的基础上选择退出,但是使用布尔值false调用setButtonUniformSize(Node,boolean)方法。
如果某个按钮被排除在均匀尺寸之外,则不会将其从尺寸调整中排除,也不会从测量过程中排除,因此其尺寸不会影响为ButtonBar中的所有按钮计算的最大尺寸。
如上面的Javadoc所述,可以使用静态方法ButtonBar.setButtonUniformSize(Node, boolean)
禁用此行为。只需使用ButtonBar
和getButtonTypes()
循环按钮,并为每个按钮设置统一大小调整为lookupButton(ButtonType)
。
false
请注意,如果不使用默认设置,则需要事先配置Alert alert = ...;
DialogPane pane = alert.getDialogPane();
pane.getButtonTypes().stream()
.map(pane::lookupButton)
.forEach(btn-> ButtonBar.setButtonUniformedSize(btn, false));
。
如果涉及自定义ButtonType
,这将变为依赖于实现。例如,自定义DialogPane
可能不使用DialogPane
。但是,您的代码没有显示使用自定义ButtonBar
的指示,因此上述解决方案应该可以正常工作。
答案 1 :(得分:1)
以下是自定义对话框的示例。一个纯代码和一个MCV。
Pure Code
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.stage.Window;
/**
*
* @author blj0011
*/
public class JavaFXApplication7 extends Application {
@Override
public void start(Stage primaryStage) {
Button button = new Button("press me");
button.setOnAction((event)->{
showDialog(primaryStage);
});
VBox root = new VBox();
root.getChildren().add(button);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
private Stage showDialog(Window parent)
{
final Stage dialog = new Stage();
dialog.setTitle("Test Dialog");
dialog.initOwner(parent);
dialog.initStyle(StageStyle.DECORATED);
//Create Header
Label lblHeaderText = new Label("Header Text Goes Here!");
lblHeaderText.setFont(new Font("System", 16));
lblHeaderText.setPadding(new Insets(0, 0, 0, 20));
StackPane headerLabelContainer = new StackPane();
headerLabelContainer.getChildren().add(lblHeaderText);
ImageView ivHeaderImageView = new ImageView();
ivHeaderImageView.setFitHeight(80);
ivHeaderImageView.setFitWidth(80);
HBox hBoxHeader = new HBox();
hBoxHeader.setMinHeight(80);
hBoxHeader.setMaxHeight(80);
hBoxHeader.setStyle("-fx-background-color: #E4E4E4");
hBoxHeader.getChildren().addAll(headerLabelContainer, ivHeaderImageView);
//Create Body
Label lblBodyText = new Label("Body Text Goes Here!");
lblBodyText.setPadding(new Insets(0, 0, 0, 20));
lblBodyText.wrapTextProperty().set(true);
AnchorPane.setTopAnchor(lblBodyText, 0.0);
AnchorPane.setBottomAnchor(lblBodyText, 0.0);
AnchorPane.setLeftAnchor(lblBodyText, 0.0);
AnchorPane.setRightAnchor(lblBodyText, 0.0);
AnchorPane apBodyLabelContainer = new AnchorPane();
apBodyLabelContainer.setMinHeight(130);
apBodyLabelContainer.getChildren().add(lblBodyText);
Button yesButton = new Button("Yes");
Button noButton = new Button("No, continue without restart");
yesButton.setOnAction((aEvent)->{
System.out.println("continue with restart!");
dialog.close();
});
noButton.setOnAction((aEvent)->{
System.out.println("continue without restart!");
//code to restart
dialog.close();
});
HBox hBoxBodyFooter = new HBox();
hBoxBodyFooter.setSpacing(10);
hBoxBodyFooter.setPadding(new Insets(0, 20, 10, 0));
hBoxBodyFooter.alignmentProperty().set(Pos.CENTER_RIGHT);
hBoxBodyFooter.getChildren().addAll(yesButton, noButton);
VBox vBoxBody = new VBox();
vBoxBody.getChildren().addAll(apBodyLabelContainer, hBoxBodyFooter);
VBox rootLayout = new VBox();
rootLayout.getChildren().addAll(hBoxHeader, vBoxBody);
Scene scene = new Scene(rootLayout, 400, 250);//You can adjust this!
dialog.setScene(scene);
dialog.showAndWait();
return dialog;
}
}
模型 - 控制器 - 视图(更像是Controller-View)
主要强>
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
/**
*
* @author blj0011
*/
public class JavaFXApplication8 extends Application {
@Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
<强>控制器强>
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.ResourceBundle;
import java.util.stream.Collectors;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
/**
*
* @author blj0011
*/
public class FXMLDocumentController implements Initializable {
@FXML
private void handleButtonAction(ActionEvent event) {
showDialog((Node)event.getSource());
}
@Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
}
private Stage showDialog(Node sourceNode)//You can add String title and String headerText and String bodyText
{
Stage dialog = new Stage();
try
{
Parent rootDialog = FXMLLoader.load(getClass().getResource("test.fxml"));
dialog.setTitle("Title of Alert");
dialog.initOwner(sourceNode.getScene().getWindow());
dialog.initStyle(StageStyle.UTILITY);
dialog.setScene(new Scene(rootDialog));
ArrayList<Node> childrenNodes = getAllNodes(rootDialog);
Button yesButton = (Button)childrenNodes.stream().filter((node) -> (node instanceof Button && ((Button)node).getText().equals("Yes"))).collect(Collectors.toList()).get(0);//Find the yes button in the test fxml
Button noButton = (Button)childrenNodes.stream().filter((node) -> (node instanceof Button && ((Button)node).getText().contains("No"))).collect(Collectors.toList()).get(0);//Fin the no button in the test fxml
//Yes button event handler
yesButton.setOnAction((aEvent)->{
System.out.println("continue with restart!");
dialog.close();
});
//No button event handler
noButton.setOnAction((aEvent)->{
System.out.println("continue without restart!");
//code to restart
dialog.close();
});
dialog.show();
}
catch (IOException ex)
{
System.out.println(ex.toString());
}
return dialog;
}
public static ArrayList<Node> getAllNodes(Parent root) {
ArrayList<Node> nodes = new ArrayList();
addAllDescendents(root, nodes);
return nodes;
}
private static void addAllDescendents(Parent parent, ArrayList<Node> nodes) {
for (Node node : parent.getChildrenUnmodifiable()) {
nodes.add(node);
if (node instanceof Parent)
addAllDescendents((Parent)node, nodes);
}
}
}
<强> FXML 强>
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxapplication8.FXMLDocumentController">
<children>
<Button layoutX="126" layoutY="90" text="Click Me!" onAction="#handleButtonAction" fx:id="button" />
<Label layoutX="126" layoutY="120" minHeight="16" minWidth="69" fx:id="label" />
</children>
</AnchorPane>
Dialog FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.text.Font?>
<VBox alignment="CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="250.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1">
<children>
<HBox maxHeight="80.0" style="-fx-background-color: #E4E4E4;">
<children>
<StackPane prefWidth="300.0" style="-fx-background-color: #E4E4E4;">
<children>
<Label text="Header Text Goes Here!" StackPane.alignment="CENTER_LEFT">
<padding>
<Insets left="20.0" />
</padding>
<font>
<Font size="16.0" />
</font>
</Label>
</children>
</StackPane>
<ImageView fitHeight="80.0" fitWidth="80.0" pickOnBounds="true" preserveRatio="true" />
</children>
</HBox>
<VBox maxHeight="170.0" style="-fx-background-color: #F8F8F8;">
<children>
<AnchorPane minHeight="130.0">
<children>
<Label alignment="TOP_LEFT" text="Body Text Goes Here!" wrapText="true" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<padding>
<Insets left="20.0" top="15.0" />
</padding>
</Label>
</children>
</AnchorPane>
<HBox alignment="CENTER_RIGHT" spacing="10.0">
<children>
<Button mnemonicParsing="false" text="Yes" />
<Button mnemonicParsing="false" text="No, continue without restart" />
</children>
<padding>
<Insets bottom="10.0" right="20.0" />
</padding>
</HBox>
</children>
</VBox>
</children>
</VBox>
这可能会成为一种解决方法,直到有人提出答案。
答案 2 :(得分:0)
部分解决方案(不完全是文本长度,但您可以设置自己的大小):
((Button) alert.getDialogPane().lookupButton(bttYes)).setMaxWidth(50);