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
Related
I have three questions which are closely related in that they are born out of each other and represent a train of thought, so I am posting them under one question. It would not help me construct the big picture of my question if I posted them separately.
1) Could you please explain in simple language what SwingUtilities.invokeLater does? I understand threading, dare I say quite a bit, but still the language of the documentation confuses me. It says:
Causes doRun.run() to be executed asynchronously on the
AWT event dispatching thread. This will happen after all
pending AWT events have been processed. This method should
be used when an application thread needs to update the GUI.
In the following example the invokeLater call queues
the Runnable object doHelloWorld
on the event dispatching thread and
then prints a message.
If I put some effort in to make sense of what that says, I think here is what it says, but I couldn't be so sure about it. I think it says:
The invokeLater method schedules the main window creation and the setting up of its dispatcher / message pump on the primary thread of the application only and not on a separate thread. It does it by posting the message to create the window and set it up on the main / primary application thread. In other words, the main thread is saying to us, "The window you are asking me to create will be created after I am done doing everything else that is on my plate right now."
But then two things confuses me, which I list as the two questions below.
2) Then why do I need to implement the new window's message loop as a Runnable. This implies that I want a separate thread to execute that message loop.
3) I printed out the current thread Id's in the function that creates the window and the function that is the window's message loop, and they are both different threads. So, each window in Swing runs on its own thread? That is insane. Can you please explain to me what is happening here? And also if you could please explain in a paragraph or two the threading model of GUI applications created in Swing?
public static void main(String[] args) {
SwingUtilities.invokeLater(new MainWindowEventLoop());
System.out.println(String.format("Main thread %1$d started.",
Thread.currentThread().getId()));
}
public class MainWindowEventLoop implements Runnable {
#Override
public void run() {
JFrame mainWindow = new MainWindow("Main Window");
System.out.println(String.format("Main window loop running on thread %1$d.",
Thread.currentThread().getId()));
}
}
Output:
Main thread 1 started.
Main window loop running on thread 14.
It's a little complicated, but Swing is not thread safe. To run the GUI asynchronously and safely, Sun/Oracle uses a locking pattern called Ad-Hoc Thread Confinement. All Swing components must run on the AWT EDT (Event Dispatch Thread) or the result is not thread safe.
Here's a link to Oracle's tutorial. Try to read all of those sections, see if it makes more sense.
https://docs.oracle.com/javase/tutorial/uiswing/concurrency/
Each window does NOT run on its own separate thread. There is only one EDT. Each windows runs on the SAME thread, the EDT. Each Runnable you send to the EDT is executed sequentially, one after the other, when the EDT has the opportunity to do so. Hence the "later" part of invokeLater().
Basically all the swing windows are bounded to main thread. Every single component in swing runs as thread. After the completion of an event control again returns back to main thread which waits for an event to occur.
I have a java routine that takes several second to be completed. I'd like to load a GlassPane (possibly with a "prease wait" message inside) that prevents the user to modify the UI while that routine is under execution and that is automatically hidden when the routine finishes.
To do this, I use the following code:
Thread t = new Thread(new Runnable(){
#Override
public void run() {
/*
* `getPresentation().getFrame()` are methods that return the
* Frame which contains my UI
*/
getPresentation().getFrame().setGlassPane(myGlassPane);
getPresentation().getFrame().getGlassPane().setVisible(true);
}
});
t.start();
//this is the routine that takes several seconds to be executed
runCEM();
//hide the GlassPane
getPresentation().getFrame().getGlassPane().setVisible(false);
I set a specific java.awt.Cursor to myGlassPane. When I run the above code, I can see the new java.awt.Cursor appearing, but not the whole GlassPane with the "please wait" message and so on...
Any idea about what could cause this issue? Are there maybe other better ways to get what I'm looking for instead of using GlassPane and Thread?
Swing is not thread safe, so already, you're violating the single thread rules of Swing, possibly on two accounts. First, the glassPane should be shown and hidden from within the context of the EDT (Event Dispatching Thread).
Your long running process should be executed off the EDT.
The simplest solution I can think of is to use a SwingWorker. This provides a number of useful mechanisms which you can use to perform long running or blocking processes in another thread and update the UI safely with.
Take a look at Concurrency in Swing and Worker Threads and SwingWorker for more details
I'm attempting to add a fancy InfiniteProgressPanel as a GlassPane for my big Swing program. However, it does not appear. It looks similar to this:
...
InfiniteProgressPanel glassPane = new InfiniteProgressPanel();
setGlassPane(glassPane);
...
glassPane.start();
doSomeStuff();
glassPane.stop();
...
I believe it is running in the same thread as the long process it is meant to cover up. I'll admit, I don't know nearly enough about threads, and I should probably figure out how to run that InfiniteProgressPanel GlassPane in a separate thread, and the long process in its own thread, too.
Be sure to:
Run all long running code in a background thread. This is a must.
Sounds great! How do I do so? Encapsulate all of the long-running code inside of an .invokeLater method? And should that be SwingUtilities.invokeLater or EventQueue.invokeLater? And what's the difference, anyway?
No, by using SwingUtilities.invokeLater(new MyRunnable) you're doing exactly the opposite -- you're guaranteeing that the long-running code will be called on the Swing event thread -- the exact opposite of what you want. Instead use a SwingWorker's doInBackground() method to run the long-running code. Regarding your second point, there's no difference whatsoever between SwingUtilities.invokeLater and EventQueue.invokeLater.
Make most all Swing calls on the Swing event thread, also a must.
Fantastic! Again, how do I do so? Same thing as above?
By using SwingUtilities.invokeLater(new MyRunnable) as noted above, or if you're using a SwingWorker then use its publish/process method pair as the SwingWorker tutorial will show you.
Call setVisible(true) on your glass pane since per the JRootPane API, all glasspanes are by default invisible.
Romain Guy's InfiniteProgressPanel doesn't seem to need a setVisible(true). It appears when the InfiniteProgressPanel.start() method is called.
I am not familiar with this, do you have a link?
Threads are different processes in the same program, per se.
In java, there are many different thread types, and the one you need for this job is SwingWorker.
The definition/use of this, from Oracle's docs, is:
When a Swing program needs to execute a long-running task, it usually uses one of the worker threads, also known as the background threads. Each task running on a worker thread is represented by an instance of javax.swing.SwingWorker. SwingWorker itself is an abstract class; you must define a subclass in order to create a SwingWorker object; anonymous inner classes are often useful for creating very simple SwingWorker objects.
As you can see, this is what you need; a background thread.
final InfiniteProgressPanel glassPane;
...
class GlassPaneHandler extends SwingWorker<String, Object> {
#Override
public String doInBackground() {
glassPane.start();
return setUpPaneAndStuff();
}
#Override
protected void done() {
try {
glassPane.stop();
} catch (Exception e) { } //ignore
}
private void setUpPaneAndStuff() {
//code
}
}
...
(new GlassPaneHandler()).execute(); //place this in your code where you want to initiate the pane
for more see:http://docs.oracle.com/javase/8/docs/api/javax/swing/SwingWorker.html
When you are updating a swing UI you need to do it in Swing's Event Thread. This includes creation of components or any sort of progress updates. You can do this via the SwingUtilities.invokeLater(Runnable) method.
Therefore, you should create the glasspane and show it via the invokeLater if in a background thread. Any progress updates to the glasspane from your long running process thread should be done via the invokeLater.
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.
Please explain invokeAndWait() method in SwingUtilities.I am unable to understand this.
Explain it very clearly. It would be of great help if you try out with an example.
Edited to add #noob's expansion of the question:
What's not clear about this?
Here's a modified usage example:
import javax.swing.SwingUtilities;
public class InvokeAndWaitStuff
{
public static void main(String[] args)
{
final Runnable doHelloWorld = new Runnable() {
public void run() {
System.out.println("Hello World on " + Thread.currentThread());
}
};
Thread appThread = new Thread() {
public void run() {
try {
SwingUtilities.invokeAndWait(doHelloWorld);
}
catch (Exception e) {
e.printStackTrace();
}
System.out.println("Finished on " + Thread.currentThread());
}
};
appThread.start();
}
}
Output:
Hello World on Thread[AWT-EventQueue-0,6,main]
Finished on Thread[Thread-0,5,main]
And why is this important?:
Causes doHelloWorld.run() to be
executed synchronously on the AWT
event dispatching thread. This call
blocks until all pending AWT events
have been processed and (then)
doHelloWorld.run() returns. This
method should be used when an
application thread needs to update the
GUI.
As far as I can tell, this is basically a bottleneck that forces GUI updates to be executed synchronously by a single thread, rather than asynchronously by multiple threads, which can potentially be unsafe.
To understand what invokeAndWait() does, you first need to understand the event/thread model of Swing.
Basically, everything that affects the GUI in any way must happen on a single thread. This is because experience shows that a multi-threaded GUI is impossible to get right.
In Swing, this special GUI thread is called the Event Dispatch Thread, or EDT. It is started as soon as a Swing top-level component is displayed, and it's bascially a worker thread that has a FIFO queue of event objects that it executes one after another.
When a Swing GUI needs to be drawn or updated, the JRE places an event on the EDT queue. User actions that cause listeners to be called start as events on the EDT queue. And (this is this is the important part) everything your program does that changes the GUI (like registering listeners, adding/removing GUI components or changing model data that the GUI displays) must be placed in the EDT queue, or the GUI can get corrupted.
And now for the finish: invokeAndWait() places the Runnable you pass to it into the EDT event queue and waits until the EDT has executed it. This should be used when a non-GUI thread needs to do something that affects the GUI, but also needs to wait until it is actually done before it can continue. If you just want to do something that affects the GUI but do not care when it is finished, you should instead use invokeLater().
I had a similar problem in a JTable. The program was blocked somewhere in "scrollRectToVisible" method. I have replaced the call by wrapping it in an invokeLater call.
The invokeAndWait did not resolve my block problem.
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
table.scrollRectToVisible(r);
}
});