JavaFX(8)警报:不同的按钮大小

JavaFX(8)警报:不同的按钮大小,javafx,dialog,javafx-8,Javafx,Dialog,Javafx 8,考虑一个带有两个按钮的JavaFX(8)警报对话框: 生成的对话框有两个按钮,两个按钮的宽度都相同,看起来很傻 是否有办法将两个按钮调整到实际文本长度?部分解决方案(不完全是文本长度,但您可以设置自己的大小): 下面是自定义对话框的示例。一个纯代码和一个MCV 纯代码 模型控制器视图(更像控制器视图) Main import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Pa

考虑一个带有两个按钮的JavaFX(8)警报对话框:

生成的对话框有两个按钮,两个按钮的宽度都相同,看起来很傻

是否有办法将两个按钮调整到实际文本长度?

部分解决方案(不完全是文本长度,但您可以设置自己的大小):


下面是自定义对话框的示例。一个纯代码和一个MCV

纯代码

模型控制器视图(更像控制器视图)

Main

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);
        }
    }    
}
import java.io.IOException;
导入java.net.URL;
导入java.util.ArrayList;
导入java.util.ResourceBundle;
导入java.util.stream.collector;
导入javafx.event.ActionEvent;
导入javafx.fxml.fxml;
导入javafx.fxml.fxmloader;
导入javafx.fxml.Initializable;
导入javafx.scene.Node;
导入javafx.scene.Parent;
导入javafx.scene.scene;
导入javafx.scene.control.Button;
导入javafx.stage.stage;
导入javafx.stage.StageStyle;
/**
*
*@author blj0011
*/
公共类FXMLDocumentController实现可初始化{
@FXML
私有无效把手按钮操作(ActionEvent事件){
showDialog((节点)event.getSource());
}
@凌驾
公共void初始化(URL、ResourceBundle rb){
//待办事项
}    
private Stage showDialog(Node sourceNode)//您可以添加字符串标题、字符串标题文本和字符串正文文本
{
阶段对话框=新阶段();
尝试
{
父rootDialog=FXMLLoader.load(getClass().getResource(“test.fxml”);
对话框.setTitle(“警报标题”);
initOwner(sourceNode.getScene().getWindow());
initStyle(StageStyle.UTILITY);
setScene(新场景(rootDialog));
ArrayList childrenNodes=getAllNodes(rootDialog);
Button yesButton=(Button)childrenNodes.stream().filter((node)->(Button和((Button)node的节点实例)。getText().equals((Yes)).Collector(Collectors.toList()).get(0);//在测试fxml中找到Yes按钮
Button noButton=(Button)childrenNodes.stream().filter((node)->(node instanceof Button&((Button)node.getText().contains(“No”)).collect(Collectors.toList()).get(0);//Fin测试fxml中的No按钮
//是按钮事件处理程序
yesButton.setOnAction((aEvent)->{
System.out.println(“继续重新启动!”);
dialog.close();
});
//无按钮事件处理程序
noButton.setOnAction((aEvent)->{
System.out.println(“继续而不重新启动!”);
//要重新启动的代码
dialog.close();
});  
dialog.show();
} 
捕获(IOEX异常)
{
System.out.println(例如toString());
}
返回对话框;
}
公共静态ArrayList getAllNodes(父根){
ArrayList节点=新的ArrayList();
addAllsubstants(根、节点);
返回节点;
}
私有静态void addallsubstants(父-父、ArrayList节点){
for(节点:parent.getChildrenUnmodifiable()){
nodes.add(node);
if(父节点的节点实例)
addAllSubstants((父)节点,个节点);
}
}    
}
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>
<?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>


在有人给出答案之前,这可能是一个解决办法。

一个扩展了
对话框的
警报
,包装了一个。
对话框窗格
分为不同的部分,其中一个部分是“按钮栏”。正如预期的那样,这一部分是所有按钮的位置。按钮栏可以是任意的
节点
,但是
对话框窗格
的默认实现使用适当命名的控件。这一点记录在(emphasismine)中:

此方法可以由子类重写以提供按钮栏。请注意,通过重写此方法,开发人员必须承担多重责任:

  • 开发人员必须立即遍历所有按钮类型,并依次调用createButton(ButtonType)
  • 开发人员必须向按钮类型列表添加一个侦听器,当该列表更改时,根据需要更新按钮栏
  • 同样,开发人员必须注意可扩展内容属性的更改,添加和删除详细信息按钮(通过createDetailsButton()方法创建)
  • 此方法的默认实现创建并返回一个新的ButtonBar实例。

    默认情况下,
    按钮栏
    将所有按钮的大小调整为最宽按钮的宽度

    均匀钮扣尺寸 默认情况下,所有按钮在ButtonBar中的大小是一致的,这意味着所有按钮都采用最宽按钮的宽度。可以在每个按钮的基础上选择不使用该选项,但使用布尔值false调用setButtonUniformSize(Node,boolean)方法

    如果某个按钮被排除在统一大小之外,则该按钮的大小将被排除在其首选大小之外,也将被排除在测量过程之外,因此其大小不会影响为ButtonBar中的所有按钮计算的最大大小

    正如上面Javadoc中提到的,可以使用静态方法禁用此行为。只需使用
    getButtonTypes()
    lookupButton(ButtonType)
    在按钮上循环,并将每个按钮的统一大小设置为
    false

    Alert alert = ...;
    DialogPane pane = alert.getDialogPane();
    pane.getButtonTypes().stream()
            .map(pane::lookupButton)
            .forEach(btn-> ButtonBar.setButtonUniformedSize(btn, false));
    
    请注意,如果不使用默认设置,则需要事先配置
    按钮类型

    如果涉及自定义
    对话框窗格
    s,则这取决于实现。例如,可能自定义的
    对话框窗格
    没有使用
    按钮栏
    。但是,您的代码没有显示使用自定义
    对话框窗格的指示,因此上述解决方案应该可以正常工作。

    I n
    <?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>
    
    <?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>
    
    Alert alert = ...;
    DialogPane pane = alert.getDialogPane();
    pane.getButtonTypes().stream()
            .map(pane::lookupButton)
            .forEach(btn-> ButtonBar.setButtonUniformedSize(btn, false));