JavaFX 加载 FXML 的性能问题

JavaFX loading performance problems with FXML

我有一个带有切换按钮的主文件,单击其中一个按钮后,我会启动一个新的 FXMLLoader,其中包含大约 10 个 SVG、15 个文本字段和 6 个微调器。此外,它有 CSS 相应地渲染节点...它加载正常,没有错误或任何问题,但在显示场景之前需要一两秒。

我猜这是由于同时初始化的节点数量所致。有没有办法在节点开始初始化之前显示场景?

注意:我的项目需要我在点击时导航到不同的场景。

ToggleButton 从它被选中的地方

   if(settings.isSelected()){
        Stage stage = (Stage) mainWrapper.getScene().getWindow();
        Parent root = FXMLLoader.load(getClass().getResource("/fxmlFiles/settings.fxml"));
        stage.setScene(new Scene(root, Screen.getPrimary().getVisualBounds().getWidth(),
                Screen.getPrimary().getVisualBounds().getHeight()));
        stage.centerOnScreen();
        //stage.setMaximized(true);
        stage.show();
    }

fxml文件

    <FlowPane xmlns:fx="http://javafx.com/fxml"
    fx:controller="controllers.motelInfoController"
    stylesheets="/cssFiles/motelInfo.css"
    fx:id="content">

    <VBox fx:id="mainWrapper">
    <VBox fx:id="validationWrapper">
        <Label fx:id="validationLabel" visible="false"/>
    </VBox>
    <VBox fx:id="generalInfo">
    <HBox> <!--First Row-->
            <HBox>
            <Group>
                <SVGPath fx:id="iconMotelName" scaleX="0.05" scaleY="0.05" fill="white"/>
            </Group>
            <Group>
                <TextField fx:id="miName" promptText="Motel Name"/>
            </Group>
            </HBox>
            <HBox>
                <Group>
                    <TextField fx:id="miFranchiseName" promptText="Franchise Name"/>
                </Group>
            </HBox>
        </HBox>
    <HBox> <!--Second Row-->
            <HBox>
                <Group>
                    <SVGPath fx:id="iconMotelAddress" scaleX="0.05" scaleY="0.05" fill="white"/>
                </Group>
                <Group>
                    <TextField fx:id="miAddress" promptText="Street Name"/>
                </Group>
            </HBox>
            <HBox>
                <Group>
                <TextField fx:id="miCity" promptText="City/Town Name"/>
                </Group>
            </HBox>
        </HBox>
    <HBox><!--Third Row-->
            <HBox style="-fx-spacing: 25px;">
                <Label></Label> <!--Empty label for purpose of leaving icon gap since N/A here-->
                <Group>
                    <TextField fx:id="miState" promptText="State"/>
                </Group>
            </HBox>
            <HBox>
                <Group>
                    <TextField fx:id="miZipCode" promptText="Zip Code"/>
                </Group>
            </HBox>
            <HBox>
                <Group>
                    <SVGPath fx:id="iconMotelContact" scaleX="0.05" scaleY="0.05" fill="white"/>
                </Group>
                <Group>
                    <TextField fx:id="miContact" promptText="Contact no."/>
                </Group>
            </HBox>
        </HBox>
    <HBox> <!--Fourth Row-->
            <HBox>
                <Group>
                    <SVGPath fx:id="iconMotelFax" scaleX="0.05" scaleY="0.05" fill="white"/>
                </Group>
                <Group>
                    <TextField fx:id="miFax" promptText="Fax no."/>
                </Group>
            </HBox>
            <HBox>
                <Group>
                    <SVGPath fx:id="iconMotelEmail" scaleX="0.05" scaleY="0.05" fill="white"/>
                </Group>
                <Group>
                    <TextField fx:id="miEmail" promptText="Email id"/>
                </Group>
            </HBox>
            <HBox>
                <Group>
                    <SVGPath fx:id="iconMotelNoOfRooms" scaleX="0.05" scaleY="0.05" fill="white"/>
                </Group>
                <Group>
                    <TextField fx:id="miNOR" promptText="No. of Rooms"/>
                </Group>
            </HBox>
        </HBox>
    <HBox style="-fx-spacing: 50px"> <!--Fifth Row-->
            <HBox>
                <Group>
                    <SVGPath fx:id="iconMotelCheckInTime" scaleX="0.05" scaleY="0.05" fill="white"/>
                </Group>
                <Group>
                    <Spinner fx:id="hourSpinnerCIT"/>
                </Group>
                <Group>
                    <Spinner fx:id="minSpinnerCIT"/>
                </Group>
                <Group>
                    <Spinner fx:id="secSpinnerCIT"/>
                </Group>
            </HBox>
            <HBox>
                <Group>
                    <SVGPath fx:id="iconMotelCheckOutTime" scaleX="0.05" scaleY="0.05" fill="white"/>
                </Group>
                <Group>
                    <Spinner fx:id="hourSpinnerCOT"/>
                </Group>
                <Group>
                    <Spinner fx:id="minSpinnerCOT"/>
                </Group>
                <Group>
                    <Spinner fx:id="secSpinnerCOT"/>
                </Group>
            </HBox>
        </HBox>
    </VBox>
    <VBox fx:id="roomOccupancy">
    <HBox> <!--First Row-->
            <Label fx:id="labelMaxGuestSelection"
                   text="Maximum Allowed Guest in individual Rooms. Please state the max count in adjacent cells"/>
            <VBox>
                <HBox>
                    <Group>
                        <SVGPath fx:id="iconMotelSingleBed" scaleX="0.05" scaleY="0.05" fill="white"/>
                    </Group>
                    <Group>
                        <TextField fx:id="miSB" promptText="Single Bed"/>
                    </Group>
                </HBox>
                <HBox>
                    <Group>
                        <SVGPath fx:id="iconMotelTwoBeds" scaleX="0.05" scaleY="0.05" fill="white"/>
                    </Group>
                    <Group>
                        <TextField fx:id="miTB" promptText="Two Beds"/>
                    </Group>
                </HBox>
                <HBox>
                    <Group>
                        <SVGPath fx:id="iconMotelfamilyRoom" scaleX="0.05" scaleY="0.05" fill="white"/>
                    </Group>
                    <Group>
                        <TextField fx:id="miFR" promptText="Family Room"/>
                    </Group>
                </HBox>
            </VBox>
        </HBox>
    <HBox> <!--Second Row-->
            <Label fx:id="labelMaxGuestCharged"
                    text="Rate Charged per Guest after max. allowed guest exceeds in a room"/>
            <HBox>
                <Group>
                    <SVGPath fx:id="iconMotelGuestExceedRate" scaleX="0.05" scaleY="0.05" fill="white"/>
                </Group>
                <Group>
                    <TextField fx:id="miGER" promptText="Rate/Guest Exceeded"/>
                </Group>
            </HBox>
        </HBox>
    </VBox>
    <VBox fx:id="submissionWrapper">
    <Group>
    <Button fx:id="submit" text="UPDATE" onAction="#saveData"/>
    </Group>
    </VBox>
    </VBox>

    </FlowPane>

FXML 控制器

@Override
public void initialize(URL location, ResourceBundle resources) {

    //Load the data if the motelInfo file exist
    File checkTemp = new File("motelDetails.ser");
    if(checkTemp.exists()){
        readDataFromFile();
    }

    //Getting Values for the spinner
    for(int i=0;i<24;i++){
        hourList.add(String.format("%02d", i));
    }
    final SpinnerValueFactory<String> hourValuesCIT = new SpinnerValueFactory.ListSpinnerValueFactory<>(hourList);
    final SpinnerValueFactory<String> hourValuesCOT = new SpinnerValueFactory.ListSpinnerValueFactory<>(hourList);
    for(int i=0; i<60; i++){
        minList.add(String.format("%02d", i));
        secList.add(String.format("%02d", i));
    }
    final SpinnerValueFactory<String> minValuesCIT = new SpinnerValueFactory.ListSpinnerValueFactory<>(minList);
    final SpinnerValueFactory<String> minValuesCOT = new SpinnerValueFactory.ListSpinnerValueFactory<>(minList);
    final SpinnerValueFactory<String> secValuesCIT = new SpinnerValueFactory.ListSpinnerValueFactory<>(secList);
    final SpinnerValueFactory<String> secValuesCOT = new SpinnerValueFactory.ListSpinnerValueFactory<>(secList);

    styleSpinner(hourSpinnerCIT, hourValuesCIT);
    styleSpinner(hourSpinnerCOT, hourValuesCOT);
    styleSpinner(minSpinnerCIT, minValuesCIT);
    styleSpinner(minSpinnerCOT, minValuesCOT);
    styleSpinner(secSpinnerCIT, secValuesCIT);
    styleSpinner(secSpinnerCOT, secValuesCOT);


} 

看来你有两个问题:

  1. 运行 在阻塞更新的 UI 线程上进行长时间操作 (readDataFromFile())
  2. 在 FXMLoader.load() 中完成所有操作,在完成之前不允许绘制任何东西

我建议通过 运行 在不同的线程中加载并在加载时显示加载屏幕来解决这两个问题。请参阅下一个示例:

public class Main extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        StackPane loadingRoot = new StackPane();

        loadingRoot.getChildren().setAll(new ProgressIndicator());
        final Scene scene = new Scene(loadingRoot);

        stage.setWidth(400);
        stage.setHeight(400);
        stage.setScene(scene);
        stage.show();

        new Thread(() -> {
            veryLongOperation();

            // we need to wrap UI code in Platform
            Platform.runLater(() -> {
                Parent root;
                try {
                    root = FXMLLoader.load(Main.class.getResource("FXMLDocument.fxml"));
                    scene.setRoot(root);
                } catch (IOException ex) {
                }
            });
        }).start();
    }

    public static void veryLongOperation() {
            try {
                // long-long operation
                Thread.sleep(5000);
            } catch (Exception ex) {
            }

    }
}