I need some help, I have a method which is performed when a button is clicked, this method then opens a new window that updates a variable in another class, the method then gets this variable from the class and then uses it.
The window that is loaded is blank, and it seems as if the wait() function is causing the thread to cease before the new window is loaded.
private void autoFillUsersActionPerformed(java.awt.event.ActionEvent evt) {
publicLesson pL= new publicLesson();
new dateSelect().setVisible(true);
try{
synchronized(this){
this.wait();
}
}
catch(Exception e){
}
int var= pL.getAmount();
System.out.println("var ="+var);
DefaultTableModel defaultModel = (DefaultTableModel) pupilTable.getModel();
for (int i = 0; i <= (userCountAmount - 1); i++) {
defaultModel.setValueAt(var, 5, i);
System.out.println("BeingSet");
}
}
You are blocking the Event Dispatch Thread. By not allowing the EDT to move past the wait call, no events can be processed which means nothing can be painted.
Instead of using a new window, try using a modal dialog. Modal dialogs block all access to other top level components (depending on the modality type) until they are properly disposed of.
Yes, indeed. Waiting on the event dispatch thread makes it block completely, and thus prevents any repaint to happen. So the EDT can't paint anything anymore while you're waiting.
Long-running tasks, and even more blocking tasks, should not be done in the event dispatch thread. It's not clear at all why you're using wait() here, BTW.
And catching Exception and ignoring it completely is one of the worst things you could do.
wait method is inherited from Object() and the docs state
Causes current thread to wait until another thread invokes the
notify() method or the notifyAll() method for this object. In other
words, this method behaves exactly as if it simply performs the call
wait(0).
Hence, you must give it something to wait for, but as you are blocking the only thread, there's no way it paints something in the meanwhile.
Is it your aim to wait in your main JFrame until the User entered the data you need in another JFrame ?
if thats your aim just have a look at Dialog ModalityTypes.
http://download.java.net/jdk7/archive/b123/docs/api/java/awt/Dialog.ModalityType.html
When constructing the new Dialog just give the parent dialog as a prameter to the constructor and then call
super(parentDialog, Dialog.ModalityType.DOCUMENT_MODAL);
then your main JFrame will wait for your new JDialog to close until it runs the rest of the function.
Hope that helps.
You cannot do that way, because Swing runs on one thread only! You need to move the processing you are doing after wait, into that window you are creating. You cannot depend on wait.
Here is a good document to read:
http://www.javapractices.com/topic/TopicAction.do?Id=153
I agree with some answers: remove the try/catch/synchronized block and use javax.swing.JDialog to receive the user input.
Refer to the official Swing documentation, it provides good enough examples,
i.e. this one http://docs.oracle.com/javase/tutorial/uiswing/components/dialog.html regarding the JDialog.
Related
I have some trouble with my java swing program. I try to stop my main Frame thread when the ExportWithoutEntryPointFrm Frame appears in an own thread.
I implemented that with java.util.concurrent.Semaphore.
The appearing Frame shows only an empty Frame, the buttons, lables and so on won´t be shown and both threads are blocked. I think there is a deadlock but I don´t find it.
My code for the new warning Frame, which will be called from the main Frame:
public class ExportWithoutEntryPointFrm extends javax.swing.JFrame implements Runnable
{
private Semaphore sema;
private boolean decision = false;
public ExportWithoutEntryPointFrm(Semaphore semaphore)
{
initComponents();
this.setLocationRelativeTo(null);
this.sema = semaphore;
}
#Override
public void run()
{
this.setVisible(true);
try
{
sema.acquire();
}
catch (InterruptedException e)
{
this.decision = false;
this.sema.release();
this.setVisible(false);
}
}
}
And the calling code from the main Frame:
Semaphore waitForDecisionSema = new Semaphore(1, true);
ExportWithoutEntryPointFrm warningFrm = new ExportWithoutEntryPointFrm(waitForDecisionSema);
warningFrm.run();
waitForDecisionSema.acquire();
First of all, calling a run() method of a Runnable doesn't start a new thread.
Second, even if it did, Swing components like JFrame MUST be used from the event dispatch thread only.
Third: since everything is done from a single thread, the EDT, as soon as this line is executed:
waitForDecisionSema.acquire();
the EDT is blocked waiting for some other thread to release the semaphore, and that will never happen, so the EDT is blocked forever, making your GUI unresponsive.
You seriously need to reconsider your design. But I don't know what you're trying to achieve, so it's hard to advise. Given the name of your semaphore, I think that what you're looking for is a modal JDialog, that would prevent the user to use the parent frame of the dialog until the dialog is closed.
I try to stop my main Frame thread when the ExportWithoutEntryPointFrm Frame appears in an own thread
Well, that's a massive contradiction in terms, Swing is a single threaded framework, you can operate components/frames/windows in separate threads, it won't work and you'll end up within no end of issues, dead locks been the most obviously.
Start by having a look at Concurrency in Swing for more details.
Now, there a number of mechanisms you can use to off load long running or blocking code to a separate thread and still interact with Swing, a Swing Timer for regular scheduled callbacks, SwingWorker for long running or potentially blocking calls, but which supports callbacks to the EDT, making it easy to use and even SwingUtilities.invokeLater for those times you have no other choice.
Have a look at How to use Swing Timers and Worker Threads and SwingWorker for more details
Based on you description though, I would suggest that what you really want, is a modal dialog, which will block the current frame/code execution at the point the dialog is made visible, but which will allow the UI to continue responding to the user.
See How to Make Dialogs for more details
Im going through concurrency documentation and I can't quite understand what they mean with:
In an applet, the GUI-creation task must be launched from the init method using invokeAndWait; otherwise, init may return before the GUI is created, which may cause problems for a web browser launching an applet. In any other kind of program, scheduling the GUI-creation task is usually the last thing the initial thread does, so it doesn't matter whether it uses invokeLater or invokeAndWait.'
-What is the problem with the init being returned before GUI-creation?
-Why is the GUI-creation usually the last thing a thread does?
Tasks on the event dispatch thread must finish quickly; if they don't, unhandled events back up and the user interface becomes unresponsive.'
-How can you make it finish faster?
http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TumbleItemProject/src/components/TumbleItem.java
-Where is the EDT in the above example?
SwingWorker worker = new SwingWorker<ImageIcon[], Void>() {
#Override
public ImageIcon[] doInBackground() {
final ImageIcon[] innerImgs = new ImageIcon[nimgs];
for (int i = 0; i < nimgs; i++) {
innerImgs[i] = loadImage(i+1);
}
return innerImgs;
}
#Override
public void done() {
//Remove the "Loading images" label.
animator.removeAll();
loopslot = -1;
try {
imgs = get();
} catch (InterruptedException ignore) {}
catch (java.util.concurrent.ExecutionException e) {
String why = null;
Throwable cause = e.getCause();
if (cause != null) {
why = cause.getMessage();
} else {
why = e.getMessage();
}
System.err.println("Error retrieving file: " + why);
}
}
};
-Why is initialisation of 'worker' here followed by the overwriting of several methods instead of just ';'? I have never seen this kind of notation before...
-Are all methods that aren't the 'doInBackGround()' method ,executed under the event dispatch thread?
'All concrete subclasses of SwingWorker implement doInBackground; implementation of done is optional.'
-In the code example ,I don't see a subclass for SwingWorker , unless new SwingWorker <>() , counts as a subclass?
'Be careful when invoking either overload of get from the event dispatch thread; until get returns, no GUI events are being processed, and the GUI is "frozen". Don't invoke get without arguments unless you are confident that the background task is complete or close to completion.'
-How would you use get() in a non-EDT way ?
My apologies if some questions are obvious and thank you for your time!
What is the problem with the init being returned before GUI-creation? -Why is the GUI-creation usually the last thing a thread does?
It says it right there in the text. "It might cause problems for browsers". It may be because the caller of init requires the method to create a GUI and schedule it for gui messages, and if none is created the caller fails.
How can you make it finish faster?
It's not about making the threads run faster, it's rather that if you have a long-going task, do it in a background thread instead of the event (GUI) thread as to not make it freeze.
Where is the EDT in the above example?
It's nowhere.. The applet has a EDT which is used when you for instance click a button or interact with the applet in other ways. I don't really understand your question here.
Why is initialisation of 'worker' here followed by the overwriting of several methods instead of just ';'? I have never seen this kind of notation before... -Are all methods that aren't the 'doInBackGround()' method ,executed under the event dispatch thread?
It's an anonymous class declaration of the SwitchWorker class. No, the doInBackground does not execute on the EDT, it's performed in the background. done is however scheduled on the EDT. See http://docs.oracle.com/javase/7/docs/api/javax/swing/SwingWorker.html for reference.
In the code example ,I don't see a subclass for SwingWorker , unless new SwingWorker <>() , counts as a subclass?
It does.
How would you use get() in a non-EDT way ?
As the documentation specifies:
get()
Waits if necessary for the computation to complete, and then retrieves its result.
So you should not call it until the background method completes, as to avoid freezing of the GUI.
Is there a way to block the execution on the EDT, with still having a vivid gui?
I noticed that JDialog/JOptionPane has something similar, when calling setVisible(true).
Why would i need this?
My Class should satisfy to following interface:
interface Quitable {
boolean quit();
}
My Class needs a implementation like this:
class MyApp implements Quitable {
ExecutorService executor = Executors.newCachedThreadPool();
// ...
public boolean quit() {
FuturTask<Boolean> futureTask = new FutureTask<Boolean>(saveJob);
executor.execute(futureTask);
// TODO: keep gui vivid
boolean saveResult = futureTask.get();
return saveResult;
}
// ...
}
I need to return the result of the save process (which may take some time and may fail). Or would you suggest another solution? Thanks for any ideas. ;)
Dialog causes the an event loop to be executed whilst it is blocking. There is a filter that allows certain events through such as repaint requests, invocation events and events to the dialog window. The API for this is not exposed.
There was a library (Foxtrot, IIRC), that used a hack on Dialog to expose this behaviour.
I would strongly suggest structuring your program in such a way that this is not required. It's a very procedural rather than event-driven organisation. So queue your task on another thread (possible a thread pool/executor service or GUI-like event-loop), and then update the GUI with java.awt.EventQueue.invokeLater.
JDialog does not block the execution of EDT, EDT ignores events except jDialog's event when it is opened as modal.
I do suggest you to show progressbar as modal, before calling quit method.
I am using an API in a Java library which is called from the event dispatch thread and requires me to return a fully-initialized UI component. It looks like this:
public JDialog createDialog();
But I can only populate the dialog after loading from a database, which can take 10 seconds sometimes. Normally I would do that in a background thread but since this method is called from the EDT and since I have to return the dialog, that won't work. It's a third-party library so I can't change the method, but is there anything I can do to avoid blocking the EDT?
"Initialized" is not necessarily the same thing as "Populated". "Initialized" usually means that the object has been fully constructed, but may not have any data. "Populated" of course means that the data is present and any data-fetching tasks are complete. So it is possible to give your third-party library a fully initialized JDialog without any data at all.
The way I always like to solve this problem is to create a custom JDialog which displays a busy message or a progress bar or the like, and then request the data in another thread. When the data is returned, I replace the busy message with the data(On the EDT!). As to how you should perform your request in a background thread, I recommend using SwingWorkers. I like to use a private SwingWorker inside my custom JDialog which handles the request in the doInBackground() method, and handles the Display-related tasks in the done() method. Doing it this way will ensure that display-related tasks only occur on the EDT, and database-related tasks only occur OFF the EDT. If you'd like a reasonably good introduction to using SwingWorkers, check out Sun's tutorial on worker threads. A simple example would be:
public class DBDIalog extends JDialog{
private JLabel busyLabel = new JLabel("Fetching data from DataBase");
public DBDialog(){
//do your initialization stuff here
}
private class DBFetcher extends SwingWorker<Void,DBInfo>{
#Override
protected DBInfo doInBackground() throws Exception{
return fetchDataFromDB(); //or whatever database call to make
}
#Override
protected void done(){
try{
DBInfo info = get();
//replace your busy label with your DBInfo
}catch(InterruptedException e){
//do appropriate thread interrupted stuff
}catch(ExecutionException e){
//do appropriate general error handling stuff
}
}
}
}
A few things to remember, though: the done() method is NOT abstract, so you aren't required to override it. You should, though. If your doInBackground() implementation throws an exception, that exception will be swallowed unless done() has been overridden. Also, don't make changes to your GUI from inside the doInBackground(), unless you use SwingUtilities.invokeLater(Runnable), as doInBackground() is executed from a different thread than the EDT and making GUI changes from a background thread is asking for strange and inexplicable bugs.
When should this be used? Unlike other programming tasks, the point at which something takes too long to respond is a lot shorter in GUIs--The number I've usually seen written down is about 250ms. If your task takes longer than that, it should be in a background thread. In your case, 10 seconds should definitely be in a background thread, but then you already knew that :)
EDIT:
Seeing your comment, I see that most of my post is pretty moot. However, you can still use a SwingWorker:
Have your SwingWorker perform the data-retrieval, and in the done() method, have it construct the JDialog from the data and hand that dialog to your third-party library.
Construct the dialog without data, and then start a task to populate it.
From a user-experience perspective, anything that takes 10 seconds from initiation to completion is going to be an issue. It's best if you should them something right away, even if it's not in final form. If necessary, you could pop a modal dialog that simply says "Loading."
I'm Jason. I'm having a bit of a problem with the Substance look and feel (https://substance.dev.java.net/).
My problem is more general. I've already got my GUI written and it works fine, but when I use a Substance Look-and-feel, it requires all GUI initialization to take place in the EDT thread (Event Dispatching Thread or something).
Right now I'm using com.sun.java.swing.plaf.windows.WindowsLookAndFeel (not sure if I spelled that right) and it doesn't require anything of this sort.
So I put the main initialization into the EDT by calling SwingUtilities.invokeLater(). This made it work. However, the program also spawns several other windows during its execution. Right now I have code like:
SomeNewWindow window = new SomeNewWindow();
// ... some bs emitted
window.doStuff();
This code works fine because by the time window.doStuff() is called, it's already initialized. But Substance requires me to do something like this:
SwingUtilities.invokeLater(new Runnable(){
public void run(){
SomeNewWindow window = new SomeNewWindow();
}});
// ... bs emitted
window.doStuff();
Here it sometimes throws a NullPointerException because window is not initialized by the time window.doStuff() is called. I can't put window.doStuff() into the EDT thread because it usually takes several seconds to return and will hang the GUI.
I've tried putting Thread.sleep(1000) right after I invoke the EDT thread because it's probably initialized by then. But this seems awkward. I simply need a way for the main thread to 'know' when the SomeNewWindow initialization has returned so it can continue on without having to worry about a NullPointerException.
Thanks in advance.
You could switch from invokeLater to invokeAndWait, which will wait until the window is created. It's a bit cheesy, but not as bad as putting in a sleep.
I think the standard approach to this would be to make your EDT the "base thread" from which you start other worker threads to do stuff.
Another way would be to use a volatile flag that the initializer can set when it's done, so the other thread can check it in a loop and act on the new window once the flag is set.
Egwor suggest using a CountDownLatch instead. Definitely looks like it would simplify the situation.
This is a job for condition variables.
Basically, in run(), Lock the lock, construct some new window and signal the condition (and unlock the lock).
"Meanwhile", in the other thread, do your other "bs", lock the lock; if the window is null, wait() on the condition variable; unlock the lock; window.doStuff();
Is there a reason why you can't just move the doStuff() call into the invokeLater callback?
SwingUtilities.invokeLater(new Runnable(){
public void run(){
SomeNewWindow window = new SomeNewWindow();
window.doStuff();
}
});
If the above is impossible, I'd go with invokeAndWait() instead of invokeLater(), as Paul Tomblin already suggested.