JavaFX BorderPane multi FXML space排列和过渡效果

JavaFX BorderPane multi FXML space arrangement and transition effect

我想设计一个GUI,在容器的顶部有一个BorderPane,有一个MenuBar,在容器的左边有一个手风琴,带有不同的按钮,可以改变容器中心的内容以适应不同的FXML 文件,有点像 Spotiffy 的桌面应用

我得到了一个工作原型,它看起来像这样

FXML 发生变化并且按钮响应非常好,我遇到的问题是填充 BoderPane 中心部分的 FXML 不会自动调整,如果是 FXML 的大部分则不会显示并且如果 FXML 小于中间部分留下的 space 保持相同的小尺寸并且留下很多 space 没有任何东西

这是我调用新 FXML 的代码

public void lanzaUno(){
        try {
            // load first FXML
            FXMLLoader loader = new FXMLLoader();

            loader.setLocation(Coordinador.class.getResource(
                    "VistaControlador/Usuario/Uno.fxml"));

            /*i put the AnchorPane inside of a 
            ScrollPane  for the desire funcionality of alot 
            of vertical space for many nodes in a single FXML file  
            */
            ScrollPane unoAnchorPane = (ScrollPane) loader.load();

            UnoController controller = loader.getController();
            //example method for passing variables to the FXML controler 
            controller.pasoPrincipal(this, primaryStage, "Rhutt");
            //puts the FXML in the center of the BorderPane
            rootLayout.setCenter(unoAnchorPane);
            //this if for trying to accommodate the content en the BorderPane 
            BorderPane.setAlignment(unoAnchorPane, Pos.TOP_LEFT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

我的第一个问题是,在调用 BorderPane 中可用的 space 内容的 FXML 时,我遗漏了什么?

我的第二个线索是关于 FXML 的变化,当我从一个传递到另一个时,BorderPane 中的变化是瞬间发生的,看起来很糟糕有没有一种方法可以使转换像 FXML 内容的转换那就是调用将 FXML 的内容推送到中心?,它不必非常详细,只是让转换更好一些

编辑

我有一个协调器 class,我在其中发送和接收所有 FXML 的参数,并在其中声明调用新 FXML 的方法,所以我有一个协调器 class,一个 FXML 根它的控制器和两个 FXML 及其控制器,每个控制器都有不同的东西,这两个 FXML 是在根的 BorderPane 中心发生变化的

这是协调员class

//Variables
        private Stage primaryStage;
        private BorderPane rootLayout;

    /**
     * launh 
     * @param primaryStage
     *  
     */
    @Override
    public void start(Stage primaryStage) throws Exception{
        // Inicializa la escena
        this.primaryStage = primaryStage;
        this.primaryStage.setTitle("Login");
        this.primaryStage.centerOnScreen();
        //star method 
        iniLogin();
    }

     /**
     *load the root scene
     */
    public void iniLogin(){
        try {
            // Carga el loader.
            FXMLLoader loader = new FXMLLoader();
            loader.setLocation(com.aohys.rehabSys.MVC.Coordinador.class.getResource(
                    "VistaControlador/Pricipal/Principal.fxml"));
            rootLayout = (BorderPane) loader.load();
            //the root scene
            Scene scene = new Scene(rootLayout);
            primaryStage.setScene(scene);
            // Da acceso al programa principal.
            PrincipalController controller = loader.getController();
            controller.pasoPrincipal(this, primaryStage);
            primaryStage.centerOnScreen();
            // Muesta la escena,
            primaryStage.show();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

在这个方法之后有两个相同的方法,就像开头的那个,我称之为 2 改变 FXML 调用 LanzaUno,LanzaDos

这是我的 Rood FXML 控制器

public class PrincipalController implements Initializable {
    //variable of the coordinator class
    private Coordinador cordi;
    private Stage stage;

    /**
     * method for passing parameters to the FXML
     * @param cordi
     * @param stage 
     */
    public void pasoPrincipal(Coordinador cordi, Stage stage) {
        this.cordi = cordi;
        this.stage = stage;
    }

    //FXML in root 
    @FXML private Button btt1;
    @FXML private Button btt2;
    @FXML public static StackPane stackPane;

    /**
     * Initializes the controller class.
     */
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        //Call the firts FXML
        btt1.setOnAction((evento)->{
            cordi.lanzaUno();
        });

        //Call the second FXML
        btt2.setOnAction((evento)->{
            cordi.lanzaDos();
        });
    }  

目前两个 FXML 上的控制器没有做任何事情

您应该阅读 Adam Bien's AfterburnerFX 用于管理应用程序中的依赖项注入和控制器的库。它改变了我的生活。 :)

对于转换,我使用此代码。这是一个很好的 fade-out/fade-in 从一个屏幕到另一个屏幕。在这种情况下,stackPane 是 FXML 中定义的 BorderPane 中心的 StackPane

这是一个带有上述 stackPane 的简单 FXML:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.text.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>

<BorderPane fx:id="borderPane" minHeight="-Infinity" minWidth="-Infinity" prefHeight="768.0" prefWidth="1280.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.tada.gui.tada.TadaPresenter">
   <center>
      <StackPane fx:id="stackPane" minHeight="-Infinity" minWidth="-Infinity" prefHeight="240.0" prefWidth="320.0" BorderPane.alignment="CENTER" />
   </center>
</BorderPane>

并传入更改为新的setScreen方法:

/**
 * Set Screen 
 * 
 * @param view
 * @return boolean
 */
public boolean setScreen(Parent view) {       
    final DoubleProperty opacity = stackPane.opacityProperty();

    if (!stackPane.getChildren().isEmpty()) {    //if there is more than one screen
        Timeline fade = new Timeline(
                new KeyFrame(Duration.ZERO, new KeyValue(opacity, 1.0)),
                new KeyFrame(new Duration(TRANSITION_TIMER), new EventHandler<ActionEvent>() {
                    @Override
                    public void handle(ActionEvent t) {
                        stackPane.getChildren().remove(0);        //remove the displayed screen
                        stackPane.getChildren().add(0, view);     //add the screen
                        Timeline fadeIn = new Timeline(
                                new KeyFrame(Duration.ZERO, new KeyValue(opacity, 0.0)),
                                new KeyFrame(new Duration(TRANSITION_TIMER), new KeyValue(opacity, 1.0)));
                        fadeIn.play();
                    }
                }, new KeyValue(opacity, 0.0)));
        fade.play();

    } else {
        stackPane.setOpacity(0.0);
        stackPane.getChildren().add(view);       //no one else been displayed, then just show
        Timeline fadeIn = new Timeline(
                new KeyFrame(Duration.ZERO, new KeyValue(opacity, 0.0)),
                new KeyFrame(new Duration(TRANSITION_TIMER), new KeyValue(opacity, 1.0)));
        fadeIn.play();
    }
    return true;
}

您的控制器中还需要这个...

private static final double TRANSITION_TIMER = 200;

编辑:

我试着整理了一个非常基本的 "application"。它很简陋,但我认为它很好地说明了 AfterburnerFX 的使用和屏幕淡入淡出过渡。 AfterburnerFX 还有很多。我只是在没有依赖注入的情况下使用了视图切换,这在您开始想要处理应用程序中的对象时非常重要。此外,属性 绑定对于良好的用户体验非常重要。无论如何,这是 GitHub 上的 link 到 my example