Update JavaFX ProgressBar without using a Task? - java

So I have a thread running and inside that thread, it updates my textArea and it should update my progressBar. I'd like to be able to update the progressBar by calling progressBar.setProgress(progress/totalProgress); without having to bind a task to it. Is this even possible?
Some sample/pseudocode because I can't actually upload the code that's being run...
private int progress;
private ProgressBar progressBar;
private int totalProgress;
public void init() {
progress = 0;
totalProgress = 10; // some max progress number
progressBar.setProgress(progress/totalProgress);
new Thread(new Runnable() {
public void run() {
try {
startThread();
} catch (Exception ex) {
System.out.println(ex);
}
}
}).start();
}
public void startThread() {
for(int i = 0; i < someSize; i++) {
textArea.append("some new message);
progress++;
progressBar.setProgress(progress/totalProgress);
}
}
When I print progress and progressBar.getProgress inside the for loop, I can see it incrementing and actually "updating" but I can't get the progressBar UI to update.
Similar to how Swing has a JProgressBar and you can update it via progressBar.setValue(counter); inside a thread that's already doing other things, I'd like to be able to update the ProgressBar for FX inside a thread that's also running other things.

Related

Trying To Delay In Java Multiple Times

Need To Do One Animation, Sleep 1000 Then Do The Next Sleep 1000 And So On, Instead It Sleeps For The Entire Time Then Plays All Animations At Once. No Idea What Im Doing.
Tried Timers, Running The Animation Before The tread.sleep And Using A While Loop Instead Of A For.
private void playLaunchAnimation()
{
final Animation animation = AnimationUtils.loadAnimation(this, R.anim.fadein);
for(int i=0; i < buttons.size();i++)
{
try {
Thread.sleep(1000);
buttons.get(i).startAnimation(animation);
} catch (Exception e){
/*
main declares that it throws InterruptedException. This is an exception that sleep throws when another thread interrupts the current thread while sleep is active. Since this application has not defined another thread to cause the interrupt, it doesn't bother to catch InterruptedException.
*/
}
}
}
Hi, Make sure this code helps you
public static void main(String[] args) throws Exception {
for(int i=0; i < 10;i++) {
try {
Thread.sleep(1000);
System.out.println(i);
if(i==9) {
i=0;
}
} catch (Exception e){
System.out.println("error");
}
}
}
(Answer assumes Android which wasn't entirely clear in OP.)
This is somewhat of a lazy way to do it - but maybe get you thinking. It would
be more interesting to have the handler invoke the next handler so only one handler is declared - but that would be a little more work.
private void playLaunchAnimation() {
final Animation animation = AnimationUtils.loadAnimation(this, R.anim.fadein);
for(int i=0; i < buttons.size();i++)
{
// Create a handler on the UI thread to execute after a delay.
// The delay is a function of loop index.
//
// It may be necessary to declare buttons final - but your
// OP did not list where it is defined.
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
#Override
public void run() {
buttons.get(i).startAnimation(animation);
}
}, ((i+1)*1000));
}
}
References:
How to call a method after a delay in Android
Android basics: running code in the UI thread
It sounds like you are calling Thread.Sleep from the User Interface thread. This will ultimately result in the entire User Interface freezing up for the duration of the sleep. What you really want is to launch sleep from a background thread.
For example:
AsyncTask.execute(new Runnable() {
#Override
public void run() {
for(int i=0; i < buttons.size();i++)
{
try {
Thread.sleep(1000);
activity.runOnUiThread(new Runnable() {
buttons.get(i).startAnimation(animation);
});
} catch (Exception e){}
}
});
Another way you could do this using post delay:
new android.os.Handler().postDelayed(
new Runnable() {
public void run() {
buttons.get(i).startAnimation(animation);
new android.os.Handler().postDelayed(this, 1000);
}
},
1000);

JavaFX UI Frozen when performing Task in new Thread

I have a problem getting the JavaFX UI to keep active while performing a background Task.
I have set up this very simple code -
#FXML
ProgressBar prgbProgress;
#FXML
private void onClick(ActionEvent event) {
Task <Void> t = new Task <Void> () {
#Override
protected Void call() throws Exception {
for (int i = 0; i < 10; i++) {
updateProgress(i, 9);
Thread.sleep(1000);
}
return null;
}
};
prgbProgress.progressProperty().bind(t.progressProperty());
new Thread(t).run();
}
What I expect to happen is to have the progress bar update every ~1 second until the task is complete. Instead, the UI completely freezes for 10 seconds, after which the progress bar appears completed.
Just to make it clear - the problem isn't only that all of the updates appear at once in the end, but also that the UI is completely unresponsive until then.
I have read just about any other question about this topic, but can't find an answer. What am I doing wrong?
Thanks.
Use start() instead of run()
#FXML
ProgressBar prgbProgress;
#FXML
private void onClick(ActionEvent event) {
Task <Void> t = new Task <Void> () {
#Override
protected Void call() throws Exception {
for (int i = 0; i < 10; i++) {
updateProgress(i, 9);
Thread.sleep(1000);
}
return null;
}
};
prgbProgress.progressProperty().bind(t.progressProperty());
//new Thread(t).run(); // wrong
new Thread(t).start(); // right
}

Java JProgressBar does not show up by setVisible(true)

I have a method like below.
ProgressWindow is a sub class of JFrame containing JProgressBar.
addProgress() increments a value in the JProgressBar.
If I call this method from a method in another class, a frame of ProgressWindow will show up but not JProgressBar and some JLabels inside the frame. They show up after the last line (System.out.println("finish")).
If I call this method in a main method in the class containing this method, then every component (Bar, labels...) instantly shows up.
What can I do for showing the window correctly?
static void search(){
ProgressWindow window = new ProgressWindow();
window.setVisible(true);
ExecutorService execs = Executors.newFixedThreadPool(Runtime
.getRuntime().availableProcessors());
Collection<Callable<Void>> processes = new LinkedList<>();
for (int i = 0; i < 100; i++) {
processes.add(new Callable<Void>() {
#Override
public Void call() throws Exception {
progressWindow.addProgress(); // increment progress value
return null;
}
});
}
try {
execs.invokeAll(processes);
} catch (Exception e) {
e.printStackTrace();
} finally {
execs.shutdown();
}
System.out.println("finish");
The main problem is you seem to be calling search from the context of the Event Dispatching Thread.
The problem occurs because you are using execs.invokeAll which blocks until all the callables have finished running.
This means that the EDT is unable to process new events in Event Queue, including repaint events, this is why your UI is coming to a stand still...
There are a number of issues you are now going to face...
You should never update/modify a UI component from any thread other than the EDT
You should block the EDT for any reason
You seem to want to know when the search is complete, so you know need some kind of event notification...
The first thing we need is some way to be notified that the search has completed, this means you can no longer rely on search returning when the search is complete...
public interface SearchListener {
public void searchCompleted();
}
Next we need an intermeditate search method that builds the UI and ensure that the search is launched within it's own Thread...
static void search(final SearchListener listener) {
final ProgressWindow window = new ProgressWindow();
window.setVisible(true);
Thread t = new Thread(new Runnable() {
#Override
public void run() {
search(listener, window);
}
});
t.start();
}
Then we need to modify the original search method to utilise the SearchListener interface to provide notification when the search is complete...
static void search(final SearchListener listener, final ProgressWindow window){
ExecutorService execs = Executors.newFixedThreadPool(Runtime
.getRuntime().availableProcessors());
Collection<Callable<Void>> processes = new LinkedList<>();
for (int i = 0; i < 100; i++) {
processes.add(new Callable<Void>() {
#Override
public Void call() throws Exception {
// This method needs to ensure that
// what ever it does to the UI, it is done from within
// the context of the EDT!!
progressWindow.addProgress();
return null;
}
});
}
try {
execs.invokeAll(processes);
} catch (Exception e) {
e.printStackTrace();
} finally {
execs.shutdown();
}
System.out.println("finish");
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
listener.searchCompleted();
}
});
}
Now, without the source code for addProgress, I might be tempted to use
processes.add(new Callable<Void>() {
#Override
public Void call() throws Exception {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
progressWindow.addProgress();
}
});
return null;
}
});
}
Instead...
Take a look at Concurrency in Swing for more details
Sounds like you what you're wanting to do is invoke the setVisible on the Swing UI thread, you can do this with invokeAndWait or invokeLater.
So something like:
final ProgressWindow window = new ProgressWindow();
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
window.setVisible(true);
}
});

JProgressBar not working properly

So my JProgressBar I have set up doesn't work the way I want it. So whenever I run the program it just goes from 0 to 100 instantly. I tried using a ProgressMonitor, a Task, and tried a SwingWorker but nothing I tried works.
Here is my program:
int max = 10;
for (int i = 0; i <= max; i++) {
final int progress = (int)Math.round(
100.0 * ((double)i / (double)max)
);
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(BandListGenerator.class.getName()).log(Level.SEVERE, null, ex);
}
jProgressBar2.setValue(progress);
}
});
}
#MadProgrammer Here is my attempt at making a swing worker and writing each name to the document and updating the progress bar. The program gets to around 86 percent and stops, never creating the finished document. The program creates a blank document. Here are the two methods first is the SwingWorker object I made:
public class GreenWorker extends SwingWorker<Object, Object> {
#Override
protected Object doInBackground() throws Exception {
int max = greenList.size();
XWPFParagraph tmpParagraph;
XWPFRun tmpRun;
FileInputStream file =
new FileInputStream(location + "GreenBandList.docx");
gDocument = new XWPFDocument(OPCPackage.open(file));
for (int i = 0; i < max; i++) {
tmpParagraph = gDocument.getParagraphs().get(0);
tmpRun = tmpParagraph.createRun();
if (greenList.get(i).length() == 1) {
tmpRun.setBold(true);
tmpRun.setText(greenList.get(i));
tmpRun.setBold(false);
} else {
tmpRun.setText(greenList.get(i));//Write the names to the Word Doc
}
int progress = Math.round(((float) i / max) * 100f);
setProgress(progress);
}
return null;
}
}
And here is the code for the button that starts it and has my property change event.
private void GenerateGreenList() throws IOException, InterruptedException {
//Need to fix the bug that removes the Letter Header in Yellow Band list
//********************************************************************\\
//Delete the old list and make a new one
File templateFile = new File(location + "\\backup\\GreenTemplate.docx");
FileUtils.deleteQuietly(new File(location + "GreenBandList.docx"));
FileUtils.copyFile(templateFile, new File(location +
"GreenBandList.docx"));
//Get the New Entries
String[] entries = jTextPane3.getText().split("\n");
for (String s : entries) {
if (s != null) {
greenList.add(s);
}
}
//Resort the list
Collections.sort(greenList);
//Write the names to the document
GreenWorker worker = new GreenWorker();
worker.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if ("progress".equals(evt.getPropertyName())) {
jProgressBar2.setValue((Integer) evt.getNewValue());
}
}
});
worker.execute();
if (worker.isDone()) {
try {
gDocument.write(new FileOutputStream(new File(location + "GreenBandList.docx")));
////////////////////////////////////////////////////////////
} catch (IOException ex) {
Logger.getLogger(BandListGenerator.class.getName()).log(Level.SEVERE, null, ex);
}
JOptionPane.showMessageDialog(null, "Green Band List Created!");
jProgressBar2.setValue(0);
}
}
I used the property change listener from one of your other posts but I don't really understand what the one you wrote does or what it does in general?
Swing is a single threaded environment, that is, there is a single thread which is responsible for processing all the events that occur within the system, including repaint events. Should anything block this thread for any reason, it will prevent Swing from processing any new events, including, repaint events...
So all this ...
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(BandListGenerator.class.getName()).log(Level.SEVERE, null, ex); }
jProgressBar2.setValue(progress);
}
});
Is constantly pausing the Event Dispatching Thread, preventing it from actually doing any updates (or at least spacing them randomly)...
It's also likely that your outer loop is been run from within the context of the EDT, meaning that until it exists, nothing in the Event Queue will be processed. All your repaint requests will be consolidated down to a single paint request and voila, instant filled progress bar...
You really should use a SwingWorker - I know you said you tried one, but you've not shown any code as to your attempt in this regards, so it's difficult to know why it didn't work, however...
SwingWorker and JProgressBar example
SwingWorker and JProgressBar example
SwingWorker and JProgressBar example
SwingWorker and JProgressBar example
SwingWorker and dual welding JProgressBar example
SwingWorker and JProgressBar example
And forgive me if we haven't said this a few times before :P
You are evoking Thread.sleep inside the EvokeLater which means that it is running on another thread than your for loop. i.e., your for loop is completing instantaneously (well, however long it takes to loop from 1 to 100, which is almost instantaneously).
Move Thread.sleep outside of EvokeLater and it should work as you intend.
int max = 10;
for (int i = 0; i <= max; i++) {
final int progress = (int)Math.round(
100.0 * ((double)i / (double)max)
);
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
jProgressBar2.setValue(progress);
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(BandListGenerator.class.getName()).log(Level.SEVERE, null, ex);
}
}
Edit: agree with #MadProgrammer. It appears this is just an illustrative question, but you should make sure whatever you're trying to accomplish here you use a SwingWorker for.

thread in Java Swing don't work

I have some simple code with a for loop. In each pass of the loop I must increment the JProgressBar; however, this isn't working. See below:
public void atualizarBarraDeProgresso(final int valorGeral, final int valorAtual) {
Thread threadProgressoCarregamento = new Thread() {
#Override
public void run() {
jProgressBarPersistindo.setValue(valorAtual);
}
};
threadProgressoCarregamento.start();
}
I'm calling the method "atualizarBarraDeProgresso" in a loop like below:
progressBar.setMinimum(0);
progressBar.setMaximum(qtd);
for(int i = 0; i < qtd; i++) {
atualizarBarraDeProgresso(qtd, i + 1);
doSomething();
}
But nothing happens with my progressBar.
try adding a thread before a for statment. I hope it works
progressBar.setMinimum(0);
progressBar.setMaximum(qtd);
new Thread(){
#Override
public void run() {
for(int i = 0; i < qtd; i++) {
atualizarBarraDeProgresso(qtd, i + 1);
doSomething();
}
}
}.start();
This should be easily managed with a SwingWorker implementation. SwingWorkers are useful when you need to "do something" but don't want to block the GUI while doing it. The class also gives you a useful API for communicating back to the EDT when you need to update a GUI component while doing other work via the publish()/process() methods.
The below implementation handles your loop on a worker thread so that it does not block the EDT (the GUI thread). Calls to publish(Integer...) are relayed to the EDT as a call to process(List) which is where you want to update your JProgressBar, because like all Swing components you should only update a JProgressBar on the EDT.
public class MySwingWorker extends SwingWorker<Void, Integer> {
private final int qtd;
private final JProgressBar progressBar;
public MySwingWorker(JProgressBar progressBar, int qtd){
this.qtd = qtd;
this.progressBar = progressBar;
}
/* This method is called off the EDT so it doesn't block the GUI. */
#Override
protected Void doInBackground() throws Exception {
for(int i = 0; i < qtd; i++) {
/* This sends the arguments to the process(List) method
* so they can be handled on the EDT. */
publish(i + 1);
/* Do your stuff. */
doSomething();
}
return null;
}
/* This method is called on the EDT in response to a
* call to publish(Integer...) */
#Override
protected void process(List<Integer> chunks) {
progressBar.setValue(chunks.get(chunks.size() - 1));
}
}
You can start it like this
int qtd = ...;
progressBar.setMinimum(0);
progressBar.setMaximum(qtd);
SwingWorker<? ,?> worker = new MySwingWorker(progressBar, qtd);
worker.execute();

Categories