预加载器的多线程-Javafx

 2023-02-16    311  

问题描述

我正在开发一个Javafx应用程序,该应用程序需要在启动主应用程序阶段之前从文件加载资源.我完成此任务的解决方案是使用预加载器,以便用户在加载资源之前无法与应用程序进行交互(非常标准的内容).

我有一个类,该类扩展了预加载类,该类创建一个对象,该对象加载一个.fxml文件,这是预加载器场景将显示的内容.它可以正常工作和花花公子,直到我尝试插入代码加载文件为止.

预加载器的多线程-Javafx

我想同时执行此操作,以便在文件加载期间,状态将更新到屏幕上.我研究了这里使用任务和论坛,但没有任何帮助,因为我不知道将代码放在哪里.

类扩展预加载器:

public class SplashPreLoader extends Preloader {
    private Stage stage;
    private SplashScene loadScreen;

    public void start(Stage stage) throws Exception {
        SplashScene intro = new SplashScene();
        this.loadScreen = intro;
        this.stage = stage;
        stage.setScene(new Scene(intro, 475, 425));
        stage.initStyle(StageStyle.UNDECORATED);
        stage.show();
    }

    @Override
    public void handleProgressNotification(ProgressNotification pn) {
        //bar.setProgress(pn.getProgress());
    }

    @Override
    public void handleStateChangeNotification(StateChangeNotification evt) {
        if (evt.getType() == StateChangeNotification.Type.BEFORE_LOAD) {
            //loadScreen.setStatusMessage("Hello Mister");
        }
        if (evt.getType() == StateChangeNotification.Type.BEFORE_START) {
      /*      Task<Void> task = new Task<Void>() {
                @Override
                public Void call() {
                    updateMessage("this mesashlkjfhkjlsd");
                    return null ;
                }
            };
            statusMessage.textProperty().bind(task.messageProperty());
            task.messageProperty().addListener((obs, oldMessage, newMessage) -> loadScreen.setStatusMessage(newMessage));
            Thread th = new Thread(task);
            th.setDaemon(true);
            th.start();*/

            //loadScreen.loadWebDriver();

            stage.hide();
        }
}

场景组件:

public class SplashScene extends StackPane {

    @FXML public Label statusMessage;

    public SplashScene() {
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("splash_scene.fxml"));
        fxmlLoader.setRoot(this);
        fxmlLoader.setController(this);

        //statusMessage.setTextFill(Color.WHITE);

        try {
            fxmlLoader.load();
        } catch (IOException exception) {
            throw new RuntimeException(exception);
        }

    }

    public String getStatusMessage() { return statusMessageProperty().getValue(); }

    public void setStatusMessage(String value) {
        statusMessageProperty().set(value);
        System.out.println("at hert");
    }

    public StringProperty statusMessageProperty() { return statusMessage.textProperty(); }

    public void loadWebDriver() { 
        //This is the function that I want to call to load all the files. 
    }

statusMessage是我要在加载文件时要修改的标签.我尝试将任务(线程)放在loadWebDriver()函数中,在start()的末尾,如果子句,则将任务放在loadWebDriver()函数中,但没有产生我想要的结果.

我也觉得很奇怪,因为当我在没有task的情况下尝试此操作时,我在文件加载代码之前有标签更改代码,但是它们总是以相反的顺序执行.

我觉得这可以帮助文档,但这对我来说并不意味着什么.有人知道这意味着什么?

请注意,预加载器遵守与其他Javafx应用程序相同的规则
规则.特别是,将在非FX线程上调用类构造函数和init()方法
start()将在FX应用程序线程上执行.这也意味着应用程序constructor/init()将与预加载器start()同时运行.

我需要使用init()方法吗?

推荐答案

这是一个希望有所帮助的示例.您可以做的一件事是使用Task加载所有数据. Task完成后,请使用使用Javafx 通过到需要它的任何Controller.

main

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.io.IOException;
import javafx.concurrent.Task;

/**
 * JavaFX App
 */
public class App extends Application {



    @Override
    public void start(Stage primaryStage) throws IOException {
        FXMLLoader loader = new FXMLLoader(getClass().getResource("primary.fxml"));
        Parent root = loader.load();
        PrimaryController primaryController = loader.getController();

        primaryStage.setTitle("Hello World");
        primaryStage.setScene(new Scene(root, 300, 275));
        primaryStage.show();

        final Task<DataModel> task = new Task<DataModel>(){
            @Override
            protected DataModel call() throws Exception
            {
                updateProgress(0, 3);
                DataModel dataModel = new DataModel();
                dataModel.loadListViewData();
                Thread.sleep(2000);
                updateProgress(1, 3);
                dataModel.loadComoBoxData();
                Thread.sleep(2000);
                updateProgress(2, 3);
                dataModel.loadTextAreaData();
                Thread.sleep(2000);
                updateProgress(3, 3);
                Thread.sleep(1000);

                return dataModel;
            }
        };

        task.setOnSucceeded((event) -> {             
            try
            {   
                FXMLLoader secondaryLoader = new FXMLLoader(getClass().getResource("secondary.fxml"));
                Stage secondaryStage = new Stage();
                Parent secondaryRoot = secondaryLoader.load();
                SecondaryController secondaryController = secondaryLoader.getController();
                secondaryController.initModel(task.getValue());
                secondaryStage.setTitle("Scene One");
                secondaryStage.setScene(new Scene(secondaryRoot, 500, 500));
                secondaryStage.show();
                primaryStage.close();
            } catch (IOException e)
            {
                e.printStackTrace();
            }

        });

        primaryController.getPBSplashValue().progressProperty().bind(task.progressProperty());
        primaryController.getPISplash().progressProperty().bind(task.progressProperty());

        new Thread(task).start();
    }

    public static void main(String[] args) {
        launch();
    }

}

primary controller/splashscreen

import javafx.fxml.FXML;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.ProgressIndicator;

public class PrimaryController
{
    @FXML
    ProgressBar pbSplash;
    @FXML
    ProgressIndicator piSplash;


    public ProgressBar getPBSplashValue()
    {
        return pbSplash;
    }

    public ProgressIndicator getPISplash()
    {
        return piSplash;
    }

}

priendarfxml

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

<?import javafx.scene.control.ProgressBar?>
<?import javafx.scene.control.ProgressIndicator?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>

<StackPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sed.test.maventtestproject.PrimaryController">
   <children>
      <VBox maxHeight="-Infinity" maxWidth="-Infinity">
         <children>
            <ProgressBar fx:id="pbSplash" prefWidth="200.0" progress="0.0" />
            <ProgressIndicator fx:id="piSplash" progress="0.0" />
         </children>
      </VBox>
   </children>
</StackPane>

secondayController/firstSceneaftersPlashscreen

import javafx.fxml.FXML;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListView;
import javafx.scene.control.TextArea;

public class SecondaryController {
    @FXML ListView<String> lvMain;
    @FXML ComboBox<String> cbMain;
    @FXML TextArea taMain;

    private DataModel model ;

    public void initModel(DataModel model) {
        if (this.model != null) {
            throw new IllegalStateException("Model can only be initialized once");
        }
        this.model = model ;

        lvMain.setItems(this.model.getListViewData());
        cbMain.setItems(this.model.getComboBoxData());
        taMain.setText(this.model.getTextAreaData());
    }
}

Secondaryfxml

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

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.VBox?>

<VBox alignment="CENTER" spacing="20.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sed.test.maventtestproject.SecondaryController">
    <children>
      <ListView fx:id="lvMain" prefHeight="200.0" prefWidth="200.0" />
      <ComboBox fx:id="cbMain" prefWidth="150.0" />
      <TextArea fx:id="taMain" prefHeight="200.0" prefWidth="200.0" wrapText="true" />
    </children>
    <padding>
        <Insets bottom="20.0" left="20.0" right="20.0" top="20.0" />
    </padding>
</VBox>

模型

import java.util.ArrayList;
import java.util.List;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

/**
 *
 * @author blj0011
 */
public class DataModel
{
    private final ObservableList<String> listViewData = FXCollections.observableArrayList();
    private final ObservableList<String> comboBoxwData = FXCollections.observableArrayList();
    private final StringProperty textAreaDataProperty = new SimpleStringProperty();

    public DataModel()
    {
    }

    public void loadListViewData()
    {
        listViewData.addAll(retrieveListViewDataFromDB());
    }

    public ObservableList<String> getListViewData()
    {
        return listViewData;
    }

    public void loadComoBoxData()
    {
        comboBoxwData.addAll(retrieveComboBoxDataFromDB());        
    }

    public ObservableList<String> getComboBoxData()
    {
        return comboBoxwData;
    }    

    public void loadTextAreaData()
    {
        textAreaDataProperty.set(retrieveTextAreaDataFromDB());
    }

    public StringProperty getTextAreaDataProperty()
    {
        return textAreaDataProperty;
    }

    public String getTextAreaData()
    {
        return textAreaDataProperty.get();
    }


    //Private methods that fake retrieving data from the database.
    private List<String> retrieveListViewDataFromDB()
    {
        List<String> dataFromDB = new ArrayList();
        for(int i = 0; i < 1000; i++)
        {
            dataFromDB.add(Integer.toString(i));
        }

        return dataFromDB;
    }    

    private List<String> retrieveComboBoxDataFromDB()
    {
        List<String> dataFromDB = new ArrayList();
        dataFromDB.add("A");
        dataFromDB.add("B");
        dataFromDB.add("C");
        dataFromDB.add("D");
        dataFromDB.add("E");
        dataFromDB.add("F");

        return dataFromDB;
    }

    private String retrieveTextAreaDataFromDB()
    {
        return "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.";  
    }
}

以上所述是小编给大家介绍的预加载器的多线程-Javafx,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对77isp云服务器技术网的支持!

原文链接:https://77isp.com/post/33853.html

=========================================

https://77isp.com/ 为 “云服务器技术网” 唯一官方服务平台,请勿相信其他任何渠道。