Progress Dialog in Swing - java

How can I make a modal JDialog without buttons appear for the duration it takes a Runnable instance to complete and have that instance update a progress bar/message on that dialog?
Clearly spaghetti code might work, but I'm looking for a clean design if one exists.

You might want to look into ProgressMonitor. It automatically pops up a dialog with a progress bar if the operation is taking a long time; see How to Use Progress Monitors.

Look at the project described at the following URL:
http://digilander.libero.it/carlmila/compmon/main.html
It is a free Java library alternative to the Swing ProgressMonitor.

Use a monitor class whit a global instance and which your code keeps up to date (I'm starting, I'm working, I'm at xxx%, I'm done).
The monitor can then decide to show the dialog and keep it current. Later, you can simply replace the dialog with a progress bar in the status bar, for example. Use an interface for the monitor (methods: start(), update(), end(), error(), isAborted()) so you can replace it with something else, too.
You can extend the monitor to wait for 500ms after start() if there is an end() and not show the dialog in this case, etc.
This is how Eclipse does it and it works well.

Related

Java 8 + Swing: Modal Dialog Theory

I am working on an application that will have the following feature:
The application will have a "Load Image" button to open an image and settings modal dialog. It will need to block until that dialog returns, either with the results of the processing or null if the user changed his mind.
The image and settings dialog will allow the user to select an image using a JFileChooser dialog and to specify to what level of detail to process the image. Clicking a "Load" button will open a load dialog.
The load dialog needs to be a custom-designed dialog that reports in detail about the time-consuming processing of the image. If the user allows the processing to finish, it needs to close and return the object back to the original dialog, which needs to close and return that object back to the application. If the user decides it is taking too long to perform the processing, he can cancel the load, closing the loading dialog and returning to the image and settings dialog.
Conceptually, this does not seem so difficult to me. However, when I try to determine how to get this to work within Swing, somehow I cannot put it together. From what I've read, GUI components need to be instantiated in Swing's event thread since many of them are not thread-safe. These same components need to block on calls similar to (but not the same as, since I need to write custom components) the JOptionPane.showInputDialog() methods. But these calls need to instantiate new components in the event thread and wait for events to occur in the event thread before returning a value to the application. Compounding this with the fact that I need a dialog to pop up from a dialog, I feel quite lost.
I have read the Java Tutorial on dialogs and several posts on StackOverflow and other sites trying to determine how I can design classes that work correctly. Somehow, I just don't understand how this can work at all (isn't the event thread going to sleep after the first blocking call?), and how I can write the custom classes I need to make this work. Frankly, I am not certain I understand my confusion enough that I was able to explain it.
Could someone please explain what goes on under the hood when modal dialogs have been instantiated? How I can write dialog classes that behave the way I need as described above?
The application will have a "Load Image" button to open an image and settings modal dialog. It will need to block until that dialog returns, either with the results of the processing or null if the user changed his mind.
OK, so this dialog will need to be modal. That much we know.
The image and settings dialog will allow the user to select an image using a JFileChooser dialog and to specify to what level of detail to process the image. Clicking a "Load" button will open a load dialog.
OK, so the load dialog will need to be modal off of the image and settings dialog. No biggie there either.
The load dialog needs to be a custom-designed dialog that reports in detail about the time-consuming processing of the image. If the user allows the processing to finish, it needs to close and return the object back to the original dialog, which needs to close and return that object back to the application. If the user decides it is taking too long to perform the processing, he can cancel the load, closing the loading dialog and returning to the image and settings dialog.
OK, so the load dialog code will need to instantiate and execute a SwingWorker to do the time-consuming image processing in a background thread, and then have the SwingWorker use its publish/process method pair to push information about the processing details back to the load dialog.
...From what I've read, GUI components need to be instantiated in Swing's event thread since many of them are not thread-safe.
Correct.
These same components need to block on calls similar to (but not the same as, since I need to write custom components) the JOptionPane.showInputDialog() methods.
And this is what a modal JDialog allows you to do. Another option to keep in mind is to use a JOptionPane and pass in a JPanel with whatever GUI you want the JOptionPane to display. JOptionPanes are surprisingly flexible and useful.
But these calls need to instantiate new components in the event thread and wait for events to occur in the event thread before returning a value to the application. Compounding this with the fact that I need a dialog to pop up from a dialog, I feel quite lost.
Again it's simple. The load dialog will call a SwingWorker which will communicate back to the load dialog.
Could someone please explain what goes on under the hood when modal dialogs have been instantiated?
Now you may be asking a bit too much for the volunteers on this site to do, since this question would probably require someone to write a complete tutorial to answer, and it has been asked and answered before, so the information should be discoverable by you. If you really want to see what is going on under the hood, you should first do the preliminary research on the subject yourself, look at the source code, and if still stuck, ask a much more specific and answerable question after first doing your own due diligence work.
Modal dialogs started from the primary event loop spawn a secondary event loop that remains active while the primary loop is blocked. See java.awt.SecondaryLoop.

Disable dialog close for ProgressMonitor

I'm working with Swing's ProgressMonitor.
This produces this nice dialog box for me:
Honestly, I think there's a flaw in the design of ProgressMonitor: What do you think happens if the user closes the dialog box by pressing the red/white cross ? Yep, you guessed it: It simply closes/hides the dialog and whatever job you have going in the background of course continues. There's no way to get the dialog box back, afaik.
Closing the window should either mean "cancel" or simply not be allowed, because I need the user to either wait for the task to complete or cancel it. How do I achieve either of this?
If I could just get a reference to that JDialog then I could do:
dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
but I can't get that reference.
UPDATE AND FINAL ANSWER
So, I wasn't telling you the full story. In fact I use ProgressMonitorInputStream which of course under the covers use ProgressMonitor, so I thought it didn't matter for the case at hand. But it does!
Andrew is right when he says that ProgressMonitor sets the isCancelled flag when the dialog is closed. This can be verified by looking at the JDK sources. But in order to catch that event you'll need a PropertyChangeListener. When working with a ProgressMonitorInputStream you are likely not to have one (like me) because updating the ProgressMonitor is all taken care of by ProgressMonitorInputStream so you won't have to do that part yourself. I was under the assumption that ProgressMonitorInputStream's raison d'etre was in not having to do boilerplate coding.
I have to say that I find the benefits of using a ProgressMonitorInputStream to be extremely small or even negative compared to a DIY approach.
Check ProgressMonitor.isCanceled(), which indeed, the ProgressMonitorDemo does.

How to Update Swing JProgressBar in Java

I'm really new to Java, especially working with GUI in Java.
I want to put a progress bar in my program, where it updates its value each time after certain amount of work has been done. Right now I have a button that executes a method when pressed, and I put setValue() function (with the value that I want) each time after certain work has been done in that method. However, when I press the button, the button seems to be stuck pressed while the method continues (the method takes a while to finish executing), and the progress bar doesn't get updated until all the other things has been done in the ButtonListener, so it goes directly to 100% after it's done).
What am I doing wrong?
Thanks in advance.
That is, most probably, because you are doing all work in main thread so it hangs your UI until all work is done. You should not do this. You should use separate EDT for such operations. What you should try is do your update progressBar job in separate EDT. Use SwingUtilities.invokeLater(Runnable r) for this.

Java swing progress bar from EDT problem

This is for the swing experts out there. I have spent considerable time on this problem, so it is going to take me a few lines to explain the problem.
I have a standalone java swing application (java 6). In my application, I have a frame with a radio button group. I have a single action linked to all the buttons in the group. The action checks to see which radio button is selected and performs some work. The "work" involves some background computation as well as some painting in two other frames in my application. The background computation is multi-threaded.
I would like to display a progress bar when the user selects one of the radio buttons.
However, when a radio button is selected, while the action to the radio button is happening, the progress bar never appears. I have tried jdialog type progress bars, glass panes, etc. None of them appear until the "work" is all completed. This seems to be because Swing does not finish painting the radio button until the "work" in the corresponding action is completed. And since the EDT only does one thing at a time, the progress bar dialog (or glass pane) is never displayed.
I then tried to use a SwingWorker to do all this "work". Start the progress bar (or activate a glass pane), start the SwingWorker and close the progress bar (or deactivate the glass pane) in the done() method for the SwingWorker. This seems to bring up the progress bar fine, but the painting which is part of the "work" is sometimes not completed, leaving me with some painting artifacts (the paintComponent method is pretty complicated, so do not want to reproduce here). The artifacts disappear if I resize the window. In fact, this happens if I use a class which extends Thread instead of SwingWorker too. This is all because Swing is not threadsafe and I am trying to do GUI work from a thread other than the EDT. I understand that part.
What do I do? "work" takes about 30 seconds and that seems too long to go without showing the user some kind of indication that the program is working. I have also tried changing the cursor to a wait cursor and have run into the same problems as above. The only thing that I can do is disable the frame and set the title of the frame to some text like "working..."
Anybody seen this problem before?
I think you are right to do the work in the SwingWorker thread, but you shouldn't be trying to do your painting there.
I'd be inclined to:
Have the ActionListener show() the progress bar, set off the swingworker then exit
Have the worker thread do the work, and periodically call repaint() on the progress bar component (this is guaranteed to be thread safe)
Progress bar has it's own paintComponent (which will be automatically called on the EDT). If necessary, this can read some variable that is updated by the worker thread to measure progress
When the worker thread finishes, have it call invokeLater() to run a final close down function on the EDT, which will hide the progress bar and do any other GUI-related cleanup / show a completion message to the user etc.
When you moved the work from the EDT to the swing worker (which was the right thing to do), it sounds like both the work and the painting moved to the swing worker. The painting should still happen on the EDT. You can achieve this by using SwingUtilities.invokeLater to invoke a repaint from the background thread, or by using the SwingWorker.publish(V...), which will take notifications from your worker thread and make them available on the EDT via the SwingWorker.process(V...) template method (which you override). Your process override can handle the intermediate notifications by repainting a portion of the screen, updating progress, or taking some other appropriate action as desired. Any UI changes done here will be visible without waiting for the rest of the work to complete.

Timed popup in Android

I am creating a matching game for Android, and when the user gets a match, a dialog box should pop up saying "Match!" I cannot figure out how to do this though. If I use Thread.currentthread().sleep, the dialog never appears.
android.app.AlertDialog a = new android.app.AlertDialog.Builder(match.this).setTitle("Match!").show();
Thread.currentthread().sleep(1000);
a.dismiss();
Nothing happens - the program just hangs for a second. I would like it to pop up for just 1 second, or if there is another sort of popup type thing, that would be good too.
You're trying to show a text message in a popup for a short period of time on the screen?
For these kind of alerts toasts are great:
Toast.makeText(this, "Match!", Toast.LENGTH_LONG).show();
Is that what you are looking for?
Here is the Java Doc.
The dialog is shown in the current thread but you are putting the thread to sleep so it never shows up. Other than event throttling, there are few cases where you want to call sleep with a substantial delay from the UI thread.
In this case using a Toast is easiest as the previous poster suggested. A couple of other ways to handle work you want done in the future
Java Timers. The action will happen
on a different thread so you have to
be carefull what gui calls you make
Views have a postDelayed(Runnable action, long delayMillis) method will cause the Runnable to be executed on the UI thread after roughly delayMillis.

Categories

Resources