How to update text box in JavaFX Application after 5 seconds of running? - javafx

I have a single controller class "FXController.java" and my FXApplication.java that extends "Application" and contains the launch code. In a separate class "TestFX.java" I call the start method in the "FXApplication.java" that starts the gui. I want to be able to access its controller so that I can change the text within a textfield of the controller. In my FXApplication.java, within the "launch" method I create a variable for the FXLoader and use the "getController" method and set it to a public variable: public FXController theController.
Within the TestFX.java, after I call the "start" method in the main method that launches FXApplication.java in a new runnable, I try to access the controller to change the contents of a single textfield, I get an exception that says controller is null. What is the proper way for me to change the contents of the textfield? I feel that the threading is causing problems.
What I am trying to do in my main method is:
Launch the JavaFX Application/GUI
5 seconds later (sleep), change the text of the text field in FXController.java to "Hello World".
Note that the fxml file loaded/used by FXApplication.java is pointed correctly to the FXController.java. Am wondering if there is some way to access the controller despite having spawned a new runnable for the FX application.
FXApplication.java
public class FXApplication extends Application {
public FXController theController;
public void start() {
Application.launch(FXApplication.class, args);
}
#Override
public void start(Stage stage) throws Exception {
FXMLLoader fxmll = new FXMLLoader(getClass().getResource("fxml_example.fxml"));
Parent root = fxmll.load();
theController = fxmll.getController();
stage.setTitle("FXML Welcome");
stage.setScene(new Scene(root, 300, 275));
stage.show();
}
}
My TestFX.java
public class TestFX {
public static FXApplication fxApp = new FXApplication();
public ExecutorService execs;
public Future<?> fut;
TestFX(ExecutorService execs) {
this.execs = execs;
}
public void start() {
fut = execs.submit(new Runnable() {
#Override
public void run() {
fxApp.start();
}
});
}
public static void main(String[] args) {
ExecutorService execs = Executors.newCachedThreadPool();
TestFX testFx = new TestFX(execs);
testFx.start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//fxApp.theController.setTextBoxText("Hello Word");
Platform.runLater(() -> fxApp.theController.setTextBoxText("Hello Word"));
}

Stuff that you want to do like this, you should use the Task class. This does all the heavy lifting for you and all you have to do is set up the code you want to run the FXAT when the task completes. Here's an example, I've left out the controller stuff, because it just clutters up the concepts:
import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.concurrent.WorkerStateEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class HelloWorld extends Application {
private static Label label;
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Hello World!");
label = new Label();
label.setText("Waiting...");
StackPane root = new StackPane();
root.getChildren().add(label);
primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.show();
Task<Void> sleeper = new Task<Void>() {
#Override
protected Void call() throws Exception {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
return null;
}
};
sleeper.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
#Override
public void handle(WorkerStateEvent event) {
label.setText("Hello World");
}
});
new Thread(sleeper).start();
}
}
The "sleeper" Task doesn't do anything except sleep, but it's going to sleep on a new thread so the FXAT can keep on responding to screen activity. Then when the sleep finishes, the event handler for the succeed will run on the thread that instantiated the Task, in this case the FXAT.

Your code has two problems.
First, you are calling the static FXMLLoader.load(URL) method, instead of calling load on your FXMLLoader instance. Consequently, the FXMLLoader instance never gets to initialize its controller. You need
FXMLLoader fxmll = new FXMLLoader(getClass().getResource("fxml_example.fxml"));
Parent root = fxmll.load();
The second issue is that you are then changing the text of the text box from a background thread, instead of from the FX Application Thread. (Unless you're handling this in the controller class: you don't show the code for that.) You need
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Platform.runLater(() -> fxApp.theController.setTextBoxText("Hello Word"));
You can also do this with a PauseTransition:
PauseTransition pause = new PauseTransition(Duration.seconds(5));
pause.setOnFinished(event -> fxApp.theController.setTextBoxText("Hello Word"));
pause.play();

Related

Switching views/fxml on gluon Application

I am developing a gluon application with JavaFX but i can't understand very well how to switch scene (or view?) by clicking a button.
If i click the button "load from file" in the image below, my code should perform some tasks, and then it should change the view, loading a new fxml, that i've added to the app manager.
Screenshoot
main class that extends Application:
package com.knnapplication;
import com.knnapplication.views.ExampleView;
import com.knnapplication.views.PrimaryView;
import com.knnapplication.views.SecondaryView;
import com.gluonhq.charm.glisten.application.AppManager;
import com.gluonhq.charm.glisten.visual.Swatch;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Stage;
import static com.gluonhq.charm.glisten.application.AppManager.HOME_VIEW;
public class KNNApplication extends Application {
public static final String PRIMARY_VIEW = HOME_VIEW;
public static final String SECONDARY_VIEW = "Secondary View";
public static final String EXAMPLE_VIEW = "Example View";
private final AppManager appManager = AppManager.initialize(this::postInit);
#Override
public void init() {
appManager.addViewFactory(PRIMARY_VIEW, () -> new PrimaryView().getView());
appManager.addViewFactory(SECONDARY_VIEW, () -> new SecondaryView().getView());
appManager.addViewFactory(EXAMPLE_VIEW, () -> new ExampleView().getView());
DrawerManager.buildDrawer(appManager);
}
#Override
public void start(Stage primaryStage) throws Exception {
appManager.start(primaryStage);
}
private void postInit(Scene scene) {
Swatch.BLUE.assignTo(scene);
scene.getStylesheets().add(KNNApplication.class.getResource("style.css").toExternalForm());
((Stage) scene.getWindow()).getIcons().add(new Image(KNNApplication.class.getResourceAsStream("/icon.png")));
}
public static void main(String args[]) {
launch(args);
}
}
event that handles the button click
#FXML
void LoadFile(ActionEvent event) {
//connection to server
InetAddress addr;
try {
addr = InetAddress.getByName("127.0.0.1");
} catch (UnknownHostException e) {
System.out.println(e.toString());
return;
}
Client c;
try {
c=new Client("127.0.0.1", 2025, label);
/*
HERE I SHOULD SWITCH VIEW
*/
AppManager.getInstance().switchView("EXAMPLE_VIEW");
} catch (IOException e) {
label.setText(e.toString());
System.out.println(e.toString());
return;
} catch (NumberFormatException e) {
label.setText(e.toString());
System.out.println(e.toString());
return;
} catch (ClassNotFoundException e) {
label.setText(e.toString());
System.out.println(e.toString());
return;
}
//label.setText("KNN caricato da file");
}
Searching on the web i've found this kind of method, using this line of code " AppManager.getInstance().switchView("EXAMPLE_VIEW");", but it still not work and i can't understand very well how does it works.
I hope you can help me. Thank you so much!
To load a new view you should make a view object and load the FXML/ the nodes on it. Then you can switch to that view by calling home.getAppManager().switchView("your view here"). like in the following example:
FloatingActionButton fab = new FloatingActionButton(MaterialDesignIcon.ADD.text,
e -> home.getAppManager().switchView(ADDHUB_VIEW));
fab.showOn(your view);
also you need to add this view to the app manager in init in main
appManager.addViewFactory(YOUR_VIEW, () -> new YourView().getView());

Update UI in method called from ActionEvent thread using JavaFX

I want to change the stage when a user logs in the application.
I have created a thread in the Action and inside it I use Platform.runLater to update the stage and show the new one. This is done in the called method.
So I have the following code:
Logincontroller
private Stage primaryStage
#FXML
void btnLoginAction(ActionEvent event) throws ClassNotFoundException {
Runnable loginRunnable = new Runnable() {
public void run() {
....
if (user exists and password ok){
loadMainwindow();
}else{
show alert
}
};
Thread loginThread = new Thread(loginRunnable);
loginThread.start();
}
private void loadMainWindow() throws IOException {
dummyStage = (Stage) (btnLogin.getScene()).getWindow();
//I get the root borderpain from the Main class
BorderPane root = Main.getRoot();
//I load the anchorpanes i will use in the new stage
AnchorPane menuPane =
FXMLLoader.load(getClass().getResource("/views/Menu.fxml"));
AnchorPane centerPane =
FXMLLoader.load(getClass().getResource("/views/Home.fxml"));
//I set the anchorpanes to the root
root.setLeft(menuPane);
root.setCenter(centerPane);
Platform.runLater(new Runnable() {
public void run() {
primaryStage.show();
}
});
}
And I´m having the following error:
Exception in thread "Thread-3" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-3
at javafx.graphics/com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:291)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:423)
at javafx.graphics/javafx.scene.Parent$3.onProposedChange(Parent.java:493)
at javafx.base/com.sun.javafx.collections.VetoableListDecorator.add(VetoableListDecorator.java:206)
at javafx.graphics/javafx.scene.layout.BorderPane$BorderPositionProperty.invalidated(BorderPane.java:692)
at javafx.base/javafx.beans.property.ObjectPropertyBase.markInvalid(ObjectPropertyBase.java:112)
at javafx.base/javafx.beans.property.ObjectPropertyBase.set(ObjectPropertyBase.java:147)
at javafx.graphics/javafx.scene.layout.BorderPane.setLeft(BorderPane.java:325)
at com.sener.dbgui.controller.LoginController.loadMainWindow(LoginController.java:90)
at com.sener.dbgui.controller.LoginController.access$4(LoginController.java:81)
at com.sener.dbgui.controller.LoginController$1.run(LoginController.java:63)
at java.base/java.lang.Thread.run(Thread.java:844)
Line 81 is the "root.setLeft(menuPane)" line.
So I guess the problem is that when modifying the root borderpane the JAVAFX thread must be running. This is, I must include the "root.set..." statements in the Platform.runLater method.
Nonetheless, this would imply in setting multiple variables for root, menuPane and centerPane to private in the controller class so that Platform.runLater process could access them and all the FXMLLoader, getwindow() and getRoot() methods could be decoupled from Platform.runLater.
So, is it better to create set this variables to private or just call the method inside the Platform.runLater?
OPTION 1. CALL METHOD INSIDE Platform.runLater
#FXML
void btnLoginAction(ActionEvent event) throws ClassNotFoundException {
Runnable loginRunnable = new Runnable() {
public void run() {
....
if (user exists and password ok){
Platform.runLater(new Runnable() {
public void run() {
loadMainwindow();
}
});
}else{
show alert
}
};
Thread loginThread = new Thread(loginRunnable);
loginThread.start();
}
If decoupling FXMLLoader, getWindow() and getRoot methods from Platform.runLater the code of the method would look like this (I would first create private variables for AnchorPanes "menuPane" and "centerPane", BorderPane "root" just like with "primaryStage" variable):
OPTION 2. CALL METHOD AND DECOUPLE FMLXLOADERS, GETROOT() AND GETWINDOW() METHODS FROM Platform.runLater()
private AnchorPane menuPane, centerPane;
private Stage dummyStage;
private BorderPane root;
#FXML
void btnLoginAction(ActionEvent event) throws ClassNotFoundException {
Runnable loginRunnable = new Runnable() {
public void run() {
....
if (user exists and password ok){
loadMainwindow();
}else{
show alert
}
};
Thread loginThread = new Thread(loginRunnable);
loginThread.start();
}
private void loadMainWindow() throws IOException {
root = Main.getRoot();
primaryStage = (Stage) (btnLogin.getScene()).getWindow();
menuPane = FXMLLoader.load(getClass().getResource("/views/Menu.fxml"));
centerPane = XMLLoader.load(getClass().getResource("/views/Home.fxml"));
Platform.runLater(new Runnable() {
public void run() {
root.setLeft(menuPane);
root.setCenter(centerPane);
primaryStage.toFront();
primaryStage.show();
}
});
}
I would like to know which option is the correct one. Or maybe these are wrong and there´s another solution to this.

Multiple independent stages in JavaFX

Is there a way to launch multiple independent stages in JavaFX? By independent I mean that the stages are all created from the main thread.
At the moment my application is more or less an algorithm where I would like to plot some charts and tables during execution (mainly to check whether the results are correct/ to debug).
The problem is that I cannot figure out how to create and show multiple stages independently, i.e. I would like to do something like this
public static void main(){
double[] x = subfunction.dosomething();
PlotUtil.plot(x); //creates a new window and shows some chart/table etc.
double[] y = subfunction.dosomethingelse();
PlotUtil.plot(y); //creates a new window and shows some chart/table etc.
.....
}
which would allow to use PlotUtil as one would use the plotting functions in other scripting languages (like Matlab or R).
So the main question is how to "design" PlotUtils? So far I tried two things
PlotUtils uses Application.launch for each plot call (creating a new stage with a single scene every time) --> does not work as Application.launch can only be invoked once.
Create some kind of "Main Stage" during the first call to PlotUtils, get a reference to the created Application and start subsequent stages from there --> does not work as using Application.launch(SomeClass.class) I am not able to get a reference to the created Application instance.
What kind structure/design would allow me to implement such a PlotUtils function?
Update 1:
I came up with the following idea and was wondering whether there are any major mistakes in this solution.
Interface to be implemented by all "Plots"
public abstract class QPMApplication implements StageCreator {
#Override
public abstract Stage createStage();
}
Plotting functionality:
public class PlotStage {
public static boolean toolkitInialized = false;
public static void plotStage(String title, QPMApplication stageCreator) {
if (!toolkitInialized) {
Thread appThread = new Thread(new Runnable() {
#Override
public void run() {
Application.launch(InitApp.class);
}
});
appThread.start();
}
while (!toolkitInialized) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Platform.runLater(new Runnable() {
#Override
public void run() {
Stage stage = stageCreator.createStage();
stage.show();
}
});
}
public static class InitApp extends Application {
#Override
public void start(final Stage primaryStage) {
toolkitInialized = true;
}
}
}
Using it:
public class PlotStageTest {
public static void main(String[] args) {
QPMApplication qpm1 = new QPMApplication() {
#Override
public Stage createStage() {
Stage stage = new Stage();
StackPane root = new StackPane();
Label label1 = new Label("Label1");
root.getChildren().add(label1);
Scene scene = new Scene(root, 300, 300);
stage.setTitle("First Stage");
stage.setScene(scene);
return stage;
}
};
PlotStage.plotStage(qpm1);
QPMApplication qpm2 = new QPMApplication() {
#Override
public Stage createStage() {
Stage stage = new Stage();
StackPane root = new StackPane();
Label label1 = new Label("Label2");
root.getChildren().add(label1);
Scene scene = new Scene(root, 300, 200);
stage.setTitle("Second Stage");
stage.setScene(scene);
return stage;
}
};
PlotStage.plotStage(qpm2);
System.out.println("Done");
}
}
The easiest approach here would be just to refactor your application so that it is driven from the FX Application thread. For example, you could rewrite your original code block as
public class Main extends Application {
#Override
public void start(Stage primaryStageIgnored) {
double[] x = subfunction.dosomething();
PlotUtil.plot(x); //creates a new window and shows some chart/table etc.
double[] y = subfunction.dosomethingelse();
PlotUtil.plot(y); //creates a new window and shows some chart/table etc.
// .....
}
public static void main(String[] args) {
launch(args);
}
}
Now PlotUtil.plot(...) merely creates a Stage, puts a Scene in it, and show()s it.
This assumes the methods you're calling don't block, but if they do you just have to wrap them in a Task and call PlotUtils.plot(...) in the onSucceeded handler for the task.
If you really want to drive this from a non-JavaFX application, there's a fairly well-known hack to force the JavaFX Application thread to start if it's not already started, by creating a new JFXPanel. A JFXPanel should be created on the AWT event dispatch thread.
Here's a very basic example of the second technique. Start the application and type "show" into the console. (Type "exit" to exit.)
import java.util.Scanner;
import java.util.concurrent.FutureTask;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javax.swing.SwingUtilities;
public class Main {
private JFXPanel jfxPanel ;
public void run() throws Exception {
boolean done = false ;
try (Scanner scanner = new Scanner(System.in)) {
while (! done) {
System.out.println("Waiting for command...");
String command = scanner.nextLine();
System.out.println("Got command: "+command);
switch (command.toLowerCase()) {
case "exit":
done = true;
break ;
case "show":
showWindow();
break;
default:
System.out.println("Unknown command: commands are \"show\" or \"exit\"");
}
}
Platform.exit();
}
}
private void showWindow() throws Exception {
ensureFXApplicationThreadRunning();
Platform.runLater(this::_showWindow);
}
private void _showWindow() {
Stage stage = new Stage();
Button button = new Button("OK");
button.setOnAction(e -> stage.hide());
Scene scene = new Scene(new StackPane(button), 350, 75);
stage.setScene(scene);
stage.show();
stage.toFront();
}
private void ensureFXApplicationThreadRunning() throws Exception {
if (jfxPanel != null) return ;
FutureTask<JFXPanel> fxThreadStarter = new FutureTask<>(() -> {
return new JFXPanel();
});
SwingUtilities.invokeLater(fxThreadStarter);
jfxPanel = fxThreadStarter.get();
}
public static void main(String[] args) throws Exception {
Platform.setImplicitExit(false);
System.out.println("Starting Main....");
new Main().run();
}
}
Here is something more along the lines I would actually follow, if I wanted the user to interact via the OS terminal (i.e. using System.in). This uses the first technique, where the application is driven by an FX Application subclass. Here I create two background threads, one to read commands from System.in, and one to process them, passing them via a BlockingQueue. Even though nothing is displayed in the main FX Application Thread, it is still a very bad idea to block that thread waiting for commands. While the threading adds a small level of complexity, this avoids the "JFXPanel" hack, and doesn't rely on there being an AWT implementation present.
import java.util.Scanner;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class FXDriver extends Application {
BlockingQueue<String> commands ;
ExecutorService exec ;
#Override
public void start(Stage primaryStage) throws Exception {
exec = Executors.newCachedThreadPool(runnable -> {
Thread t = new Thread(runnable);
t.setDaemon(true);
return t ;
});
commands = new LinkedBlockingQueue<>();
Callable<Void> commandReadThread = () -> {
try (Scanner scanner = new Scanner(System.in)) {
while (true) {
System.out.print("Enter command: ");
commands.put(scanner.nextLine());
}
}
};
Callable<Void> commandProcessingThread = () -> {
while (true) {
processCommand(commands.take());
}
};
Platform.setImplicitExit(false);
exec.submit(commandReadThread);
exec.submit(commandProcessingThread);
}
private void processCommand(String command) {
switch (command.toLowerCase()) {
case "exit":
Platform.exit();
break ;
case "show":
Platform.runLater(this::showWindow);
break;
default:
System.out.println("Unknown command: commands are \"show\" or \"exit\"");
}
}
#Override
public void stop() {
exec.shutdown();
}
private void showWindow() {
Stage stage = new Stage();
Button button = new Button("OK");
button.setOnAction(e -> stage.hide());
Scene scene = new Scene(new StackPane(button), 350, 75);
stage.setScene(scene);
stage.show();
stage.toFront();
}
public static void main(String[] args) {
launch(args);
}
}

Javafx service to update GUI objects status

I'm trying to update the GUI status based on a time consuming task. When I push on a button, I want the button to be inactive and the cursor to change until the job is completed. I've come up with this code that mostly works as needed.
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Cursor;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;
public class TestWait2 extends Application {
#Override
public void start(Stage primaryStage) {
FlowPane root = new FlowPane();
primaryStage.setScene(new Scene(root));
MyService myService = new MyService();
primaryStage.getScene().getRoot().cursorProperty()
.bind(Bindings.when(myService.runningProperty())
.then(Cursor.WAIT).otherwise(Cursor.DEFAULT));
Button startButton = new Button();
startButton.setText("Button");
startButton.disableProperty().bind(myService.runningProperty());
root.getChildren().add(startButton);
startButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
myService.start();
}
});
primaryStage.show();
}
private class MyService extends Service<Void> {
#Override
protected Task<Void> createTask() {
return new Task<Void>() {
#Override
protected Void call() throws Exception {
Thread.sleep(5000);
return null;
}
};
}
}
public static void main(String[] args) {
launch(args);
}
}
When I launch it works great the first time. The problem is that if I click on the button a second time it get an error.
Exception in thread "JavaFX Application Thread" java.lang.IllegalStateException: Can only start a Service in the READY state. Was in state SUCCEEDED
Any thoughts on how to get around that issue?
I'm running on Java 8u5.
The problem with your code that you try to call myService.start(); when its on SUCCEEDED state(since you started it already once).
this is according to javadoc of Service start method
Starts this Service. The Service must be in the READY state to succeed in * *this call.
This method should only be called on the FX application thread.
to make your code work, you need to you call myService.restart().
since you are planning to use your service over and over you can do the following:
startButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
//replace this line
// myService.start();
//with this
myService.restart();
}
});
Adding this to the program seemed to solve this.
myService.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
#Override
public void handle(WorkerStateEvent t) {
myService.reset();
}
});
I also found I can add the following directly to the MyService class.
#Override
protected void succeeded() {
reset();
}
There doesn't seem to be any other way to have it go to the ready state after completing it's work.

JavaFX preloader not updating progress

I'm having trouble with the JavaFX Preloader. During the start phase the application will have to connect to a DB and read many so I thought it would be nice to display a splash screen during this time. The problem is the ProgressBar automaticly goes to 100% and I don't understand why.
Application class. Thread sleep will be replaced by real code later (DB connection etc)
public void init() throws InterruptedException
{
notifyPreloader(new Preloader.ProgressNotification(0.0));
Thread.sleep(5000);
notifyPreloader(new Preloader.ProgressNotification(0.1));
Thread.sleep(5000);
notifyPreloader(new Preloader.ProgressNotification(0.2));
}
Preloader
public class PreloaderDemo extends Preloader {
ProgressBar bar;
Stage stage;
private Scene createPreloaderScene() {
bar = new ProgressBar();
bar.getProgress();
BorderPane p = new BorderPane();
p.setCenter(bar);
return new Scene(p, 300, 150);
}
#Override
public void start(Stage stage) throws Exception {
this.stage = stage;
stage.setScene(createPreloaderScene());
stage.show();
}
#Override
public void handleStateChangeNotification(StateChangeNotification scn) {
if (scn.getType() == StateChangeNotification.Type.BEFORE_START) {
stage.hide();
}
}
#Override
public void handleProgressNotification(ProgressNotification pn) {
bar.setProgress(pn.getProgress());
System.out.println("Progress " + bar.getProgress());
}
For some reason I get the following output:
Progress 0.0
Progress 1.0
I had same problem and I found solution after two hours of searching and 5 minutes of carefully reading of JavaDoc.:)
Notifications send by notifyPreloader() method can be handled only by Preloader.handleApplicationNotification() method and it doesn't matter which type of notification are you sending.
So change you code like this:
public class PreloaderDemo extends Preloader {
.... everything like it was and add this ...
#Override
public void handleApplicationNotification(PreloaderNotification arg0) {
if (arg0 instanceof ProgressNotification) {
ProgressNotification pn= (ProgressNotification) arg0;
bar.setProgress(pn.getProgress());
System.out.println("Progress " + bar.getProgress());
}
}
}

Resources