首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >来自PreLoader - JavaFX的多线程

来自PreLoader - JavaFX的多线程
EN

Stack Overflow用户
提问于 2020-01-27 20:34:09
回答 1查看 473关注 0票数 3

我正在开发一个JavaFX应用程序,它需要在启动主应用程序阶段之前从文件中加载资源。我完成这一任务的解决方案是使用PreLoader,以便在加载了资源(非常标准的内容)之后,用户才能与应用程序交互。

我有一个类扩展了PreLoader类,它创建了一个加载.fxml文件的对象,这就是PreLoader场景将显示的内容。在我尝试插入代码来加载文件之前,这一切都很不错。

我希望同时这样做,以便在加载文件时,状态被更新到屏幕上。我已经研究过在这里使用任务和论坛,但是没有任何帮助,因为我不知道在哪里放置代码。

类扩展PreLoader:

代码语言:javascript
复制
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();
        }
}

场景组件:

代码语言:javascript
复制
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()的末尾和if子句的前面,但它没有产生我想要的结果。

我也觉得奇怪,因为当我尝试不使用task时,在文件加载代码之前有标签更改代码,但是它们总是以相反的顺序执行。

我觉得这可以从文件中得到帮助,但对我来说没有任何意义。有人知道这意味着什么吗?

注意,预加载器受与其他JavaFX应用程序(包括FX线程规则)相同的规则的约束。特别是,将在非FX线程上调用类构造函数和init()方法,并在FX应用程序线程上执行start()。这也意味着应用程序构造函数/init()将与预加载器start()并发运行。

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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-01-27 23:02:34

下面是一个希望能有所帮助的例子。您可以做的一件事是使用Task加载所有数据。当Task完成后,使用来自Applying MVC with JavaFX的想法将Model传递给任何需要它的Controller

代码语言:javascript
复制
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();
    }

}

PrimaryController/SplashScreen

代码语言:javascript
复制
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;
    }

}

PrimaryFXML

代码语言:javascript
复制
<?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

代码语言:javascript
复制
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

代码语言:javascript
复制
<?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>

模型

代码语言:javascript
复制
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.";  
    }
}
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59938519

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档