I am looking for an approach for updating the maximum value of a progress bar. I would like to use a determine progress bar if that is the correct way to accomplish this. Which I have setup below
final JDialog dialog = new JDialog(frame, "Progress Dialog", true);
progressBar = new JProgressBar(0, 500);
progressBar.setIndeterminate(false);
dialog.add(BorderLayout.CENTER, progressBar);
dialog.add(BorderLayout.NORTH, new JLabel("Progress..."));
dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); dialog.setSize(300, 75);
dialog.setLocationRelativeTo(frame);
At this time I do not know what the maximum for the progress bar will be. In the block below runner is an subclass of a SwingWorker. It is not until after that process starts that I know what the maximum will be for the progress bar.
// run the report in its own thread
try {
runner = ReportFactory.create(reportName, startDate, endDate);
runner.addPropertyChangeListener(progressListener);
runner.execute();
} catch (Exception e1) {
logger.error(e);
System.exit(1);
}
I have tried this with and without the invoke later.
private class ProgressListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (runner.getProgress() == 0) {
// SwingUtilities.invokeLater(new Runnable() {
// public void run() {
progressBar.setMaximum(runner.getMaximumProgressSize());
// }
// });
}
progressBar.setValue(runner.getProgress());
}
}
To me, invokeLater will not work, because the task has not finished working. I have spent the better part of a day trying to get this progress bar to work. Any help or a change in direction would be greatly appreciated!
The comment above worked great!
Related
I am working on a swing project. There is a map, I have raster images of a given data for different times. Normally I change the time via a JSlider and it requests server for raster image. Then I add response image to map. There is a Play JButton, when pressed it will add those images one by one to raster layer of the map. It will be seen as an animation. In that JButton's actionPerfomed method I change the JSlider's value in a for loop.
My problem is when I press Play JButton, I can't see the data is played but I know code block works because I record each image(from server). I found out that it is becuse of JButton does not release Focus until its actionPerformed method ends. Because JButton looked like it was pressed until the end. So I only see the last image in the map.
First, I tried JButton.setFocusable(false) etc. but to no good.
Second, I tried using SwingWorker. I added it like this:
class PlayMvgmLayerWorker extends SwingWorker<Void, Void> {
public PlayMvgmLayerWorker(String title) {
super(title);
}
#Override
protected void done(Void aVoid) {
}
#Override
protected Void doInBackground() {
try{
BufferedImage[] image = new BufferedImage[24];
for(int i=0; i<24; i++) {
final int value = i - 48 + 24;
timeSlider.setValue( value );
Thread.sleep(10000l);
}
} catch(Exception ex) {
ex.printStackTrace();
}
return null;
}
}
private JButton animation = new JButton("");
animation.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
new PlayMvgmLayerWorker("title").execute();
}
});
private JSlider timeSlider = new JSlider();
timeSlider.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
// time consuming processes ( server call, add image to map, etc)
}
});
I tried to simplify it.
It is much better than before, but I still can not see the data played properly. Sometimes data is played after JSlider ticks. Could it be because my time consuming process is in the second components(JSlider) stateChanged event? Should I use a second SwingWorker in JSlider's event too? Any suggestions about what can I do?
Moreover, what would be the best way to disable all components before playing data, and enable them after playing data?
Thank you very much in advance
If you have two activities Activity A and Activity B which have to be run simultaneously, you need to create a thread for the second activity - the first activity will already be run in its own thread (the main program).
The scheme is as follows:
Program A:
create new Thread: Activity B
run allother tasks for Activity A
In more specific terms the following program will run your simulation and update the tick of the slider:
public P() {
animation.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
doInBackgroundImp();
}
});
setSize(500, 500);
setLayout(new FlowLayout());
add(animation);
add(timeSlider);
setVisible(true);
}
protected void doInBackgroundImp() {
Thread th=new Thread() {
public void run() {
try{
for(int i=0; i<24; i++) {
final int value = i - 48 + 24;
timeSlider.setValue( i );
System.out.println(timeSlider.getValue()+" "+value);
Thread.sleep(1000);
}
} catch(Exception ex) {
ex.printStackTrace();
}
}
};
th.start();
}
private JButton animation = new JButton("");
private JSlider timeSlider = new JSlider();
}
I'm new in java. I'm trying to understand thraeads and timers in java. It was big problem for me to undate ProgressBar from another thread. I read many posts and found answers. So can you say is this the best way to resolw my task. So, what I want is to run second thread and when it's done, stop progress bar and change text on the button. So I creat Frame with button and progress bar in Test class:
After I realize action listener for Button to run second thread:
public class Test extends javax.swing.JFrame {
RunBg thread = new RunBg();
....
// declaration for button, progressbar and main() method
....
private void jButton1MouseClicked(java.awt.event.MouseEvent evt) {
// needed to check is the thread running at first time else creat new object and rund hread again cause thread can be executed once
if(thread == null){
thread = new RunBg();
}
if (jProgressBar1.isIndeterminate()) {
jProgressBar1.setIndeterminate(false);
jButton1.setText("Run!");
thread.suspend();
} else {
jButton1.setText("Working...");
jProgressBar1.setIndeterminate(true);
// let us know is the second thread running or nope so we can know resume it or pause
if (thread.isAlive()) {
thread.resume();
} else {
thread.start();
}
timer.start();
}
}
/*
Then I creat timer to know is my thread still alive else change Progress bar and button
*/
Timer timer = new Timer(100, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(!thread.isAlive()){
thread.stop();
jProgressBar1.setIndeterminate(false);
jButton1.setText("Запустить!");
timer.stop();
// thread.interrupt();
thread = null;
}
}
});
...
// end of class
}
And my second class for another thread named RunBG:
public class RunBg extends Thread{
int i = 0;
public void run(){
while(i<20000){
System.out.println(">>>"+i);
i++;
}
System.out.println("<<<Finished>>>");
}
}
Everythig works fine , but I have question. Is there a better way to realize my task or maybe I made some mistakes. Also I thik that my code will help another beginners who looking for help to understand how it's work.
I use Swing Application Framework in my program. And I have some long-time work. I use org.jdesktop.application.Task for it. Another programmer wrote two Tasks before I took this project (I can not ask him about the programm). When Tasks are executing user sees progress bar without showing percent complete, but what shows "Wait" message and user can not click to a main window while Task does not ended. It is fine! But I could not find place where ProgressBars was created. May be it is described in some xml-file or property-file?
Also I wrote another Tasks and when they run, progress bar which I created is not displayed or displayed incorrectly. I read about ProgressBar and ProgressMonitor, but it does not help me.
Programm continue to run after someTask.execute(), but I want to it displays ProgressBar, ProgressMonitor or something else and user can not click the main window and window will display correctly. Now window has black "blocks" when user change it.
May be I need use org.jdesktop.application.TaskMonitor. I try to use it as here https://kenai.com/projects/bsaf/sources/main/content/other/bsaf_nb/src/examples/StatusBar.java?rev=235 , but my main window is displayed incorrectly and my ProgressBar is not displayed.
I need to when Task is running program waits it, but user can see ProgressBar, can cancel the operation and can not click to the main window. How can I do it?
Here my code:
public class A{
#Action(name = "ActionName", block = Task.BlockingScope.APPLICATION)
public RequestInfoTask requestInfo() {
RequestInfoTask task = new RequestInfoTask(Application.getInstance());
isSuccessedGetInfo=false;
task.addTaskListener(new TaskListener.Adapter<List<InfoDTO>, Void>() {
#Override
public void succeeded(TaskEvent<List<InfoDTO>> listTaskEvent) {
isSuccessedGetResources=true;
}
});
//Here I want to the program shows ProgressMonitor and user can not click to the main window.
//But small window with message "Progress..." is displayed for several seconds and disappear.
ProgressMonitor monitor = new ProgressMonitor(getMainView(), "Wait! Wait!", "I am working!", 0, 100);
int progress = 0;
monitor.setProgress(progress);
while(!task.isDone()){
monitor.setProgress(progress+=5);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
monitor.setProgress(100);
//This code must run after "task" finishes.
if(isSuccessedGetInfo){
MyTask2 task2 = new MyTask2(Application.getInstance());
isSuccessedTask2=false;
task2.addTaskListener(new TaskListener.Adapter<Map<?,?>, Void>(){
#Override
public void succeeded(TaskEvent<Map<String, ICredential>> arg0) {
isSuccessedTask2=true;
}
});
//Do something with results of task2.
}
return task;
}
}
public class RequestInfoTask extends Task<List<InfoDTO>, Void> {
public RequestInfoTask(Application application) {
super(application);
}
#Override
protected List<InfoDTO> doInBackground() throws Exception {
List<InfoDTO> result = someLongerLastingMethod();
return result;
}
}
Part of your problem sounds like it comes from not using the EDT correctly. Any long running task needs to be started in it's own thread to keep the GUI responsive and repainting.
Ideally you'd be following a MVC pattern. In that case you place your Progress Bar in the view, your flag (that indicates whether the task should be running still) in the control, and your long running task in in the Model.
From that point, if your model checks periodically if it should stop (Probably at good stopping points), you can reset everything.
Here's an example with MVC:
import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;
public class ProgressBarDemo{
public static class View extends JPanel{
Controller control;
public JProgressBar progressBar = new JProgressBar(0, 100);
JButton button = new JButton("Start Long Running Task");
public View(Controller controlIn){
super();
this.control = controlIn;
setLayout(new BorderLayout());
button.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
//Toggle between running or not
if(control.isRunning){
control.isRunning = false;
button.setText("Canceling...");
button.setEnabled(false);
} else{
control.isRunning = true;
button.setText("Cancel Long Running Task");
control.startTask();
}
}});
progressBar.setStringPainted(true);
add(progressBar);
add(button, BorderLayout.SOUTH);
}
}
//Communications gateway
public static class Controller{
View view = new View(this);
boolean isRunning = false;
public void updateProgress(final int progress){
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
view.progressBar.setValue(progress);
}});
}
public void reset(){
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
isRunning = false;
view.button.setText("Start Long Running Task");
view.progressBar.setValue(0);
view.button.setEnabled(true);
}});
}
public void startTask(){
LongRunningClass task = new LongRunningClass(this);
new Thread(task).start();
}
}
public static class LongRunningClass implements Runnable{
Controller control;
public LongRunningClass(Controller reference){
this.control = reference;
}
#Override
public void run() {
try {
for(int i = 0; i < 11; i++){
//Monitor the is running flag to see if it should still run
if(control.isRunning == false){
control.reset();
break;
}
control.updateProgress(i * 10);
Thread.sleep(3000);
}
control.reset();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
// Create and set up the window.
JFrame frame = new JFrame("LabelDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Add content to the window.
frame.add(new Controller().view);
// Display the window.
frame.pack();
frame.setVisible(true);
}
}
I have an application that copies files (via ADB) to an android tablet. It takes some time so I want to display a popup with an indeterminate progress bar on it. When the copy task is complete then I want to be able to stop the progress bar and let the user close the dialog.
At the moment I have not added the extra dialog box and am just trying to get the progress bar working. The problem I have is that the progress bar is not showing at the start of the task, but I dont know why. The progressbar shows when the dialog box saying sync complete appears. The code is:
progress = new JProgressBar(0, 100);
progress.setForeground(new Color(255, 99, 71));
progress.setIndeterminate(true);
progress.setValue(0);
progress.setPreferredSize( new Dimension( 300, 20 ) );
progress.setBounds( 278, 12, 260, 20 );
progress.setVisible(false);
progress.setString("Sync in progress");
progress.setStringPainted(true);
contentPane.add(progress);
pushtotab = new JButton("");
pushtotab.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
if (buildpathset==1){
try{
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
progress.setVisible(true);
wiredsync();
}finally{
JOptionPane.showMessageDialog(null, "sync complete. ",null, buildpathset);
setCursor(Cursor.getDefaultCursor());
progress.setVisible(false);
}}else{
//warning in here later - TO Do
}
}
});
public void wiredsync(){
try {
Process process = Runtime.getRuntime().exec("adb" + " push "+ buildpath + " " + adbtabletsync);
InputStreamReader reader = new InputStreamReader(process.getInputStream());
Scanner scanner = new Scanner(reader);
scanner.close();
int exitCode = process.waitFor();
System.out.println("Process returned: " + exitCode);
} catch(IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}//end
Thanks for the help,
Andy
pooyan has the right idea -- do the long running process in a background thread -- but gives the wrong library example, since your program is a Swing program and not an Android program. The canonical answer to this for Swing is to do your long-running task in the doInBackground() method of a SwingWorker.
Please hold while I find a better example...
Something like so:
if (buildpathset == 1) {
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
progress.setVisible(true);
// create my SwingWorker object
final SwingWorker<Void, Void> myWorker = new SwingWorker<Void, Void>() {
protected Void doInBackground() throws Exception {
// here is my long running task, calling in background
// thread
wiredsync();
return null;
};
};
// this allows me to be notified when the SwingWorker has
// finished
myWorker.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent pcEvt) {
// if the SwingWorker is done
if (pcEvt.getNewValue() == SwingWorker.StateValue.DONE) {
// notify the user
JOptionPane.showMessageDialog(null, "sync complete. ",
null, buildpathset);
setCursor(Cursor.getDefaultCursor());
progress.setVisible(false);
try {
// one way to catch any errors that occur in
// SwingWorker
myWorker.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
});
// run my SwingWorker
myWorker.execute();
} else {
// warning in here later - TO Do
}
For more on this, please check out: Lesson: Concurrency in Swing
i think your problem is that you don't use thread . I mean after you turn visibility of your progress bar to true , you should define your long task in a thread. I'm Not familiar with Swing But
take Look there for Swing (sorry if it's no use full):
http://www.java-tips.org/java-se-tips/javax.swing/how-to-handle-long-running-tasks-in-a-swing-applic.html
and there for android :http://www.mkyong.com/android/android-progress-bar-example/
I have a save button in a JFrame ;on clicking save the 'save' text sets to 'saving....'; I need to set that text as 'saved' after a delay of 10 seconds.How is it possible in java?
Please help...
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
This is what i did...but this wont shows as 'saving' during that delayed time.
If you want to provide the user with visual feedback that something is going on (and maybe give some hint about the progress) then go for JProgressBar and SwingWorker (more details).
If on the other hand you want to have a situation, when user clicks the button and the task is supposed to run in the background (while the user does other things), then I would use the following approach:
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
button.setEnabled(false); // change text if you want
new SwingWorker<Void, Void>() {
#Override
protected Void doInBackground() throws Exception {
// Do the calculations
// Wait if you want
Thread.sleep(1000);
// Dont touch the UI
return null;
}
#Override
protected void done() {
try {
get();
} catch (Exception ignore) {
} finally {
button.setEnabled(true); // restore the text if needed
}
}
}.execute();
}
});
Finally, the initial solution that was using the Swing specific timer:
final JButton button = new JButton("Save");
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// Take somehow care of multiple clicks
button.setText("Saving...");
final Timer t = new Timer(10000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
button.setText("Saved");
}
});
t.setRepeats(false);
t.start();
}
});
This question & first 3 answers are heading down the wrong track.
Use a JProgressBar to show something is happening. Set it to indeterminate if the length of the task is not known, but presumably you know how much needs to be saved and how much is currently saved.
Don't block the EDT (Event Dispatch Thread) - the GUI will 'freeze' when that happens. Use a SwingWorker for long running tasks. See Concurrency in Swing for more details.
The best is to use a timer and its method execute with a delay : http://developer.apple.com/library/mac/documentation/java/reference/javase6_api/api/java/util/Timer.html#schedule(java.util.TimerTask, long). Use a timertask to wrap your runnable and that's it.