javafx: Progress bar to show the progress of the process? - javafx

I want to show progress bar while a functionality is running. What is the best way to show it? Basically I am building a program to send multiple mails on a single click. While sending the mail I want to show progress bar while sending the mails.

The best solution in this case is using a Task.
Example:
Task<Parent> yourTaskName = new Task<Parent>() {
#Override
public Parent call() {
// DO YOUR WORK
//method to set progress
updateProgress(workDone, max);
//method to set labeltext
updateMessage(message);
}
};
//ProgressBar
ProgressBar pBar = new ProgressBar();
//Load Value from Task
pBar.progressProperty().bind(yourTaskName.progressProperty());
//New Loading Label
Label statusLabel = new Label();
//Get Text
statusLabel.setText("Loading...");
//Layout
VBox root = new VBox(statusLabel, pBar);
//SetFill Width TRUE
root.setFillWidth(true);
//Center Items
root.setAlignment(Pos.CENTER);
//SetOnSucceeded methode
yourTaskName.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
#Override
public void handle(WorkerStateEvent event) {
System.out.println("Finish");
}
});
//Start Thread
Thread loadingThread = new Thread(yourTaskName);
loadingThread.start();
Hope this helps you.
P.S.: The code in the task run as a Thread...

I implemented what you want last time ,If you want to show progressIndicator or progressBar when sending is running ,try this part of code
senderThreadlive = new Thread(new Runnable() {
#Override
public void run() {
try {
Platform.runLater(new Runnable() {
#Override
public void run() {
ProgressIndicator WaitingSend=new ProgressIndicator();
WaitingSend.setProgress(ProgressIndicator.INDETERMINATE_PROGRESS);
WaitingBox.getChildren().add(WaitingSend);//this is an HBOX
SendMailButton.setDisable(true);
SendMailButton.setText("sending in progress");
}
});
//call Your method of sending
SimpleMail.EmailSender.sendEmail(MailSenderTxt.getText(), MotMailTxt.getText(), DestMailTxt.getText(), ObjetMailTxt.getText(), org.jsoup.Jsoup.parse(ContentMail.getHtmlText()).text());
Platform.runLater(new Runnable() {
#Override
public void run() {
WaitingSend.setProgress(0);
WaitingSend.setVisible(false);
SendMailButton.setDisable(false);
SendMailButton.setText("Send");
}
});
} catch (AuthenticationFailedException e) {
Platform.runLater(new Runnable() {
#Override
public void run() {
//Your popUp here
}
});
} catch (SendFailedException e) {
Platform.runLater(new Runnable() {
#Override
public void run() {
//Your popUp here
}
});
} catch (MessagingException e) {
Platform.runLater(new Runnable() {
#Override
public void run() {
//Your popUp here
}
});
} catch (Exception ex) {
Platform.runLater(new Runnable() {
#Override
public void run() {
//Your popUp here
}
});
}
}
});
senderThreadlive.start();

Just use javafx.scene.control.ProgressBar
Documentation:
http://docs.oracle.com/javafx/2/ui_controls/progress.htm

Related

JavaFX log4j in a textarea with a different thread

I'm trying to redirect log4j output to a textarea but this one get filled at the end of the action since I'm using Platform.runLater
Is there any way I can do it with a different thread ?
AppFX.java
public class AppFX extends Application {
public static void main(String[] args) {
ConfHandler.initConf();
launch(args);
}
#Override
public void start(Stage primaryStage)throws IOException {
primaryStage.getIcons().add(new Image("file:src/main/resources/images/frameIcon.png"));
FXMLLoader loader = new FXMLLoader();
String currentPath = System.getProperty("user.dir");
loader.setLocation(new URL("file:\\"+currentPath+"\\src\\main\\resources\\scenes\\TestsFrame.fxml"));
Parent content = loader.load();
primaryStage.setTitle("IGED Tests");
Scene scene = new Scene(content);
primaryStage.setScene(scene);
primaryStage.show();
TextAreaAppender.setTextArea(((EaaSCleanerController)loader.getController()).getLogTextArea());
}}
TextAreaAppender.java
public class TextAreaAppender extends WriterAppender {
private static volatile TextArea textArea = null;
public static void setTextArea(final TextArea textArea) {
TextAreaAppender.textArea = textArea;
}
#Override
public void append(final LoggingEvent loggingEvent) {
final String message = this.layout.format(loggingEvent);
try {
Platform.runLater(new Runnable() {
#Override
public void run() {
try {
if (textArea != null) {
if (textArea.getText().length() == 0) {
textArea.setText(message);
} else {
textArea.selectEnd();
textArea.insertText(textArea.getText().length(), message);
}
}
} catch (final Throwable t) {
System.out.println("Unable to append log to textarea:" + t.getMessage());
}
}
});
} catch (final IllegalStateException e) {
}
}}
log4j.properties
# Append the logs to the GUI
log4j.appender.gui=com.bp.nest.testauto.gui.TextAreaAppender
log4j.appender.gui.layout=org.apache.log4j.PatternLayout
log4j.appender.gui.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p - %m%n
You should put your actions on a separate thread. Then the logging can happen in parallel to your actions. You should never block the GUI-thread.

How cancel network request in retrofit and rxjava

I have a multiple buttons; When I press new button, previous(with another button) running request should be interrupted and new runs. How to realize it?
for (button : Buttons) {
button.setOnClickListener(b -> networkApi.getLongContentFromUrl(url)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<JsonElement>() {
#Override
public void onCompleted() {}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(JsonElement jsonElement) {
//do with result
}
}));
}
You can have a common SerialSubscription and assign your subscriber to it on button click. It will unsubscribe and thus cancel your previous stream:
SerialSubscription serial = new SerialSubscription();
for (Button btn : buttons) {
btn.setOnClickListener(e -> {
Subscriber<JsonElement> s = new Subscriber<JsonElement>() {
#Override
public void onCompleted() {}
#Override
public void onError(Throwable e) {}
#Override
public void onNext(JsonElement jsonElement) {
//do with result
}
};
serial.set(s);
networkApi.getLongContentFromUrl(url)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(s);
});
}

Dispose JavaFX Tasks

I have a static BorderPane with ContextMenu insight Task
Task task = new Task()
{
#Override
protected Void call() throws Exception
{
Platform.runLater(new Runnable()
{
#Override
public void run()
{
try
{
contextMenu = new ContextMenu();
MenuItem item1 = new MenuItem("About");
item1.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent e)
{
System.out.println("About");
}
});
MenuItem item2 = new MenuItem("Preferences");
item2.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent e)
{
System.out.println("Preferences");
}
});
MenuItem item3 = new MenuItem("Close");
item3.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent e)
{
}
});
contextMenu.getItems().addAll(item1, item2, item3);
bp.setOnContextMenuRequested(new EventHandler<ContextMenuEvent>()
{
#Override
public void handle(ContextMenuEvent event)
{
contextMenu.show(bp, event.getScreenX(), event.getScreenY());
event.consume();
}
});
bp.addEventHandler(MouseEvent.MOUSE_PRESSED, new EventHandler<MouseEvent>()
{
#Override
public void handle(MouseEvent event)
{
contextMenu.hide();
}
});
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
}
}
});
return null;
}
};
new Thread(task).start();
I noticed that when I close the component which holds the BorderPane the Java Threads are not disposed they are still initialized into the memory. I'm not sure is this caused by the static BorderPane. After the Task is completed the Java Thread should be disposed. Any idea why is this happening?
The problem is not a Task, but the anonymous classes in your Runnable.
In the next piece of code:
bp.setOnContextMenuRequested(new EventHandler<ContextMenuEvent>()
{
#Override
public void handle(ContextMenuEvent event) {
//...
}
});
you introduce an anonymous class extending EventHandler which holds inner link to a Runnable. To solve that you can use nested static class instead.
P.S.: Unfortunately you can't make anonymous class static in Java, see Is it possible to make anonymous inner classes in Java static?

Context Menu in JavaFX Task

Following this topic Context menu insight JavaFX Task I want to create Context Menu in JavaFX Task. I tested this code:
static private StringBuilder stringBuilder = new StringBuilder();
private static ContextMenu contextMenu;
private static CountDownLatch menuCreated = new CountDownLatch(1);
static synchronized void writeString(String s)
{
stringBuilder.append(s).append("\n");
}
public static BorderPane init(BorderPane bp) throws Exception
{
System.out.println("***** CALLED");
Task task = new Task()
{
#Override
protected Void call() throws Exception
{
writeString("Task started");
writeString(Thread.currentThread().getName() + " is fx thread: "
+ Platform.isFxApplicationThread());
Platform.runLater(new Runnable()
{
#Override
public void run()
{
writeString(Thread.currentThread().getName() + " is fx thread: "
+ Platform.isFxApplicationThread());
try
{
contextMenu = new ContextMenu();
contextMenu.setId("Test ID");
writeString("Created context menu");
menuCreated.countDown();
}
catch (Exception ex)
{
writeString(ex.getMessage());
ex.printStackTrace();
}
finally
{
writeString("Test");
}
}
});
writeString("Task finished");
return null;
}
};
new Thread(task).start();
MenuItem item1 = new MenuItem("About");
item1.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent e)
{
System.out.println("About");
}
});
MenuItem item2 = new MenuItem("Preferences");
item2.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent e)
{
System.out.println("Preferences");
}
});
MenuItem item3 = new MenuItem("Close");
item3.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent e)
{
//flow.getChildren().remove(bp);
}
});
contextMenu.getItems().addAll(item1, item2, item3);
bp.setOnContextMenuRequested(new EventHandler<ContextMenuEvent>()
{
#Override
public void handle(ContextMenuEvent event)
{
//contextMenu.hide();
System.out.println("*********************** Shown Context Menu ***!!!!!!!");
contextMenu.show(bp, event.getScreenX(), event.getScreenY());
event.consume();
}
});
bp.addEventHandler(MouseEvent.MOUSE_PRESSED, new EventHandler<MouseEvent>()
{
#Override
public void handle(MouseEvent event)
{
contextMenu.hide();
}
});
menuCreated.await();
return bp;
}
With this code I set Context Menu for BorderPane. When I click with the right mouse button I see the debug message *********************** Shown Context Menu ***!!!!!!! but there is no context menu. Can you help me to fix this code?

Progress bar with thread

Now a days it's my first step in android. I am simply trying to implement progress bar with with a "Download" Button. When i press download button progress bar keep on progressing but when the whole progress gets over i am not able to hide progress bar. Here is my code. please help me.
public class ProgressBarDemo extends Activity
{
ProgressBar pb;
Button bt;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.progressbar);
pb = (ProgressBar) findViewById(R.id.progressBar1);
bt = (Button) findViewById(R.id.button1);
pb.setVisibility(View.VISIBLE);
bt.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
Thread timer = new Thread()
{
public void run()
{
try
{
for(int i=0; i<=50; i ++)
{
pb.incrementProgressBy(i);
sleep(1000);
}
pb.setVisibility(View.INVISIBLE);
Toast.makeText(ProgressBarDemo.this, "Thank you for downloading", Toast.LENGTH_SHORT).show();
}catch(Exception e){}
}
};
timer.start();
}
});
}
}
You should only modifiy ui elements from the mainThread (the UI Thread) try
pb.post(new Runnable() {
#Override
public void run() {
pb.setVisibility(View.INVISIBLE);
}
})
instead.
Maybe u have to use the same thing for incrementing your progressbar. Alternativley you could use the AsyncTask http://developer.android.com/reference/android/os/AsyncTask.html class. onProgressUpdate and onPostExecute are called in the UIThread automatically.
you can also use AsynTask that is a better solution...
public class ProgressBarDemo extends Activity
{
ProgressBar pb;
Button bt;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
pb = (ProgressBar) findViewById(R.id.progressBar1);
bt = (Button) findViewById(R.id.button1);
pb.setVisibility(View.VISIBLE);
bt.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
new AsynTasks().execute();
}
});
}
class AsynTasks extends AsyncTask<Void, Integer, Void>
{
#Override
protected Void doInBackground(Void... params) {
for(int i=1;i<=100;i++)
{
SystemClock.sleep(1000);
publishProgress(i);
}
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
pb.setVisibility(View.INVISIBLE);
Toast.makeText(ProgressBarDemo .this, "Thank you for downloading", Toast.LENGTH_SHORT).show();
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
pb.setProgress(values[0]);
}
}
}
You should not do UI task from different thread.Use this...
public class ProgressBarDemo extends Activity
{
ProgressBar pb;
Button bt;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
pb = (ProgressBar) findViewById(R.id.progressBar1);
bt = (Button) findViewById(R.id.button1);
pb.setVisibility(View.VISIBLE);
bt.setOnClickListener(new OnClickListener()
{
public void onClick(View v)
{
Thread timer = new Thread()
{
public void run()
{
try
{
for(int i=1; i<=100; i ++)
{
pb.setProgress(i);
sleep(100);
}
}catch(Exception e){}
finally{
runOnUiThread( new Runnable() {
public void run() {
pb.setVisibility(View.INVISIBLE);
Toast.makeText(ProgressBarDemo .this, "Thank you for downloading", Toast.LENGTH_SHORT).show();
}
});
}
}
};
timer.start();
}
});
}
}

Resources