Create Splashscreen to show file copy progress

Asked

Viewed 329 times

4

I’m trying to create a splashscreen because when my application is open I perform some time-consuming actions, such as:

  • Copy files
  • Run a . exe

My Main is like this:

import com.sun.javafx.application.LauncherImpl;

@SuppressWarnings("restriction")
public class Main 
{
   public static void main(String[] args) 
   {
      LauncherImpl.launchApplication(MyApplication.class, SplashScreenLoader.class, args);
   }
}

The class MyApplication calls my program start screen and class SplashScreenLoader would be responsible for being mine splash is like this:

import java.net.URL;

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

public class SplashScreenLoader extends Preloader {

    private Stage splashScreen;

    @Override
    public void start(Stage stage) throws Exception {
        URL arquivo = getClass().getResource("SplashScreen.fxml");
        Parent parent = FXMLLoader.load(arquivo);
        splashScreen = stage;
        splashScreen.setTitle("Iniciando..");
        splashScreen.setScene(new Scene(parent));
        splashScreen.setResizable(false);
        splashScreen.show();
        splashScreen.show();
    }


    @Override
    public void handleApplicationNotification(PreloaderNotification notification) {
        if (notification instanceof StateChangeNotification) {
            splashScreen.hide();
        }
    }

}

The controller of my fxml, your method initialize is responsible for carrying out the copy of my files, it owns the following code snippet:

try
{
    this.lblTitle.setText(Confg.project);
    if(this.verifyArchives(Confg.origin, "php", Confg.pathPHP))
    {
        boolean start = false;
        do
        {
            try
            {
                this.runPHP(Confg.localhost);
                start = true;
            } catch (Exception e) { }
        }while(!start);
        this.verifyArchives(Confg.pathWWW + Confg.project, "www", Confg.pathWWW + Confg.project);
    }
}
catch (Exception e) { this.lblStatus.setText(e.getMessage()); }

The method verifyArchives is responsible for checking if the files already exist, and if there is no method called copyAll, passing parameters such as source and destination, and the label of my SplashScreen who will be responsible for displaying the status of the process.

public static boolean copyAll(File origin, File destiny, boolean overwrite, Label info) throws IOException, UnsupportedOperationException
{
    if (!destiny.exists())
        destiny.mkdir();

    if (!origin.isDirectory())
        throw new UnsupportedOperationException("Origem deve ser um diretório");

    if (!destiny.isDirectory())
        throw new UnsupportedOperationException("Destino deve ser um diretório");

    File[] files = origin.listFiles();
    for (int i = 0; i < files.length; ++i)
    {
        if (files[i].isDirectory())
            copyAll(files[i], new File(destiny + "\\" + files[i].getName()), overwrite, info);
        else
        {
            System.out.println("Copiando arquivo: " + files[i].getName());
            info.setText("Copiando arquivo: " + files[i].getName());
            copy(files[i], new File(destiny + "\\" + files[i].getName()), overwrite);
        }
    }
    return true;
}

At the end of the method I have one println and a setText that should transform the text of my label in the current status of the process. But when starting the program for the first time (that’s when it will copy the files), the messages from println are displayed on the console, for example: "Copying file: blablabla.txt". And only after copying all the files that mine splash is opened, with the label with the message "Copying file: last-file.txt".

The question is exactly this, as I exhibit the splashscreen just before running the copy of the files, so you can see the copying process on my splash?

  • If you create an interface to notify status does not work? A System ?

  • I’m not sure I understand it very well, but I don’t think.

  • On the screen itself I was trying to do something to delay the copy of the files, such as a Sleep or a Wait, this.Wait() worked but even putting a time to wait it was paused, without calling the method of copying file.

  • "The controller of my fxml finally, in its method initialize is responsible for making a copy of my files". - You could post more about your controller and about your fxml? I’m pretty sure that’s what the problem is.

  • I believe that the problem is not the fxml, he’s just one panel with a webview within, with the controller set correctly. And da splash is a panel with two label only. Already the controller has only the statements of the screen objects(web view in the case of my home page, and the Labels in the case of my splash). And both have only the initialize method, which on the splash tries to call the file copy methods and the one on the homepage just loads a link in my webview, the runphp method is not important. I think the problem is in verifyArchuve or Copyall

  • They are running before the screen opens, and should be run after opening.

Show 1 more comment

1 answer

3


I can’t tell if yours PreLoader is configured correctly, mainly because of this:

import com.sun.javafx.application.LauncherImpl;

Normally, you use the launch of own Application.

Now, what is recommended to perform long tasks is to create a method that runs on a thread, and warn the PreLoader when everything is right, something like:

public class MyApplication extends Application {

    Stage stage;
    BooleanProperty ready = new SimpleBooleanProperty(false);

    private void chamadaDemorada() {
        Task task = new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                //por exemplo, a sua função que copia arquivos
                copyAll(origin, destiny, overwrite, info);
                // se quiser enviar o progresso                         
                notifyPreloader(new ProgressNotification(progresso));
                //e quando estiver pronto
                ready.setValue(Boolean.TRUE);
                notifyPreloader(new StateChangeNotification(
                    StateChangeNotification.Type.BEFORE_START));
                return null;
            }
        };
        new Thread(task).start();
    }

    @Override
    public void start(final Stage stage) throws Exception {
        chamadaDemorada();

        Parent root = FXMLLoader.load(getClass().getResource("FXMLdaApp.fxml"));
        Scene scene = new Scene(root);
        stage.setScene(scene);

        ready.addListener(new ChangeListener<Boolean>() {
            public void changed(
                ObservableValue<? extends Boolean> ov, Boolean t, Boolean t1) {
                if (Boolean.TRUE.equals(t1)) {
                    Platform.runLater(new Runnable() {
                        public void run() {
                            stage.show();
                        }
                    });
                }
            }
        });

    }
}

and this method should be called the start of Application.

If you would like to try other methods, I suggest checking the document on Preloaders (in English).

  • I just couldn’t understand the ProgressNotification

  • Use ProgressNotification the way I showed it there, it doesn’t make sense. I left it only as a reference of what you can do. The right thing would be to call notifyPreloader(new ProgressNotification(progresso)); within its method copying files. Every step completes by running this notification.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.