I have a login frame that i have to wait for from another thread. Upon successful login frame disposes itself. And i want to pop up the main frame for the application. Right now i am watching a boolean value to determine when to fire up the main frame. What is the correct way of doing this? Watching a boolean value just does not feel elegant.
If you have Java 5 or later available, you could use a CountDownLatch. For example, assuming the main frame is in control initially, have the main frame create the CountDownLatch with a count down of 1 and pass this latch to the login frame. Then have the main frame wait for the latch to become 0:
CountDownLatch loginSignal = new CountDownLatch(1);
... // Initialize login frame, giving it loginSignal
... // execute login frame in another Thread
// This await() will block until we are logged in:
loginSignal.await();
Have the login frame, when done, decrement the Latch:
loginSignal.countDown();
Ensure that there is no way for your login frame to exit where it forgets to decrement the latch! As soon as the CountDownLatch reaches 0, the main frame becomes runnable.
You could also use a Semaphore or Condition (or any of a few other choices from java.util.concurrent), but for this purpose, a CountDownLatch seems easier to use.
What you really must understand with dealing with Swing (and in fact AWT), is that you need to keep all interaction with the components of the AWT Event Dispatch Thread (EDT).
So, do the login off the EDT. Use a new Thread, or better a java.util.concurrent.ExecutorService. When you discover that you have been logged in, use java.awt.EventQueue.invokeLater to get back onto the EDT. Anonymous inner class are great for capturing context and, despite their horrendously verbose syntax, making the code shorter.
Related
I've been coding a simulation that has a JFrame GUI for parameter input, and a separate JFrame that runs an animation of the simulation.
I update the animation together with the simulation, so the call to repaint comes from the function runsimulation()
I have added an EXIT_ON_CLOSE for my main GUI frame, and while the animation is running I can close the frame and it doesn't pop up again, but I want to know if it is possible to shut down the simulation thread when I close the animation frame.
Because currently when I close the frame the simulation keeps on running in the background and finishes properly, but I'd like the close event on the animation frame to be a "cancel simulation" as well.
You have two choices here. One option is to make the running thread into a "Daemon" thread. This means that the thread will not keep the program running, so if you close the JFrame and exit the application it will terminate immediately.
Be aware that the long running thread could potentially get terminated abruptly and in the middle of processing things though.
The (probably better) way is to call interrupt() on the thread and have the thread check isInterrupted() at regular intervals and exit cleanly if the flag is set.
i need to develop java code to have JFrame with a text filed and button.Using Threads,i need to update time for every one minute in the title bar of JFrame.Using Another Thread i need to display textbox value in the console when a button is clicked.I have code for performing both operations (updating time for every min and getting text box value)but i dont know how to add two threads in same class.if anyone knows pls help me out
What you are asking is a dangerous thing to do in Swing. Swing components are not thread-safe and should only be updated from the Event Dispatching Thread (also known as the EDT or Swing Thread). To do this, Swing has utility methods such as SwingUtilities.invokeLater(Runnable) which will execute the code in the Runnable (at some point in the future) on the EDT. The idea is that you place your code to do Swing-things (like update the Title of the JFrame with the time) inside of a separate Runnable and pass it to invokeLater().
To do this, you can create an anonymous Runnable class:
Runnable updateJFrame = new Runnable () {
public void run () {
myJFrame.setTitle("My New Title");
}
};
SwingUtilities.invokeLater(updateJFrame);
Using invokeLater() also ensures that the components get refreshed/repainted properly after they have been updated. (The behavior you are seeing when using statics may actually be a refresh/repaint issue.) The moral of this story is that if you manipulate Swing components on a non-EDT thread, all bets are off.
I'm using the java swing library to develop a board game called DAO.
The problem is that after the human player makes its move, by clicking on the JButton with the piece image that he wants to play, I call the computer AI routine but inside the mouse event function. By doing this only when the function returns, the computer ends its turn, do the JButtons refresh their Images (setIcon comes in).
I'd like to know how can I force the JButtons to change their image at the moment they are clicked and not only when the mouse event function ends (as I need to handle data inside it).
I've tried all of this
myButtons[i][j].setIcon(xIcon);
myButtons[i][j].revalidate();
myButtons[i][j].repaint();
myButtons[i][j].validate();
None worked.
Thx in advance
You may want to try putting the action performed upon clicking the JButton into a Swing worker. This will allow the task to go on in the background, while the user can still click other buttons, etc.
See http://java.sun.com/docs/books/tutorial/uiswing/concurrency/simple.html.
There is a single thread used for all Swing activity.
Here's the process.
One event appears on the event queue
it is pulled from the queue and executed by The AWT Thread
Any new events created while this is executing are placed on the queue to be held until the currently running AWT event returns.
The event executing returns and the next event on the queue is dequeued and executed.
This means that if you need to do anything that takes more than, say 1/100 of a second or so, you shouldn't do it any thread started from a swing event. Instead, spawn your own thread and return the swing thread to the system so the GUI can be updated.
Now, your thread MUST NOT update any GUI objects! If you need to update a GUI object, use invokeLater to place your code back on the AWT thread.
New Java programmers not conforming to this rule and executing tasks on the AWT thread is almost certainly the biggest reason people think Java is slow.
I need to get some information from user by showing a JFrame
I need the first frame pause process until user enter data from the second frame
I thought about using wait() and notify() but I don't know how
How can I do this?
Thanks
It seems to that it would be a lot easier for you is you just use a modal JDialog, which you present to the user. The inputs whatever is needed there and the JFrame that popped the dialog will carry on after the dialog's closed. wait() and notify() are used for thread synchronization btw...
I've built a form with Netbeans's visual editor. When I press one of the buttons it should do the following :
set it to disabled
perform a task that takes some time
when the task finishes the button will be enabled again
However, the following happens:
the button remains in a pressed state until the task finishes
when the task finishes, the enabling/disabling of buttons will be very fast (they will happen, but you won't notice them)
This behaviour is not something I want. I tried using repaint on the JButton, on the JFrame and even on the JPanel containing the button, but I can't seem to get it to do what I want. Some hints?
When you do work in a button callback, you are stalling the GUI painting thread until it completes.
What you need to do is spawn a thread to do the long running task, and then have that thread use SwingUtilities.invokeLater() to update the UI when it completes. Not using invokeLater is not thread safe, and is generally bad mojo.
A basic example is:
button.setEnabled(false);
new Thread(new Runnable() {
public void run() {
// Do heavy lifting here
SwingUtilies.invokeLater(new Runnable() {
public void run() {
button.setEnabled(true);
}
});
}
}).start();
When you do things in a button callback, you are essentially stalling the gui painting thread - not just for the button, but for ANY gui painting. (Try covering the interface with another window and then exposing it again - it won't repaint until the task is finished!)
What you need to do is spawn a thread to do the long running task, and then have that thread use SwingUtilities.invokeLater() to do the enabling of the button. invokeLater forces the button enable to happen in the gui painting thread.
You may want to set a busy cursor or otherwise lock the interface while the long-running thread is operating.
The Concurrency in Swing tutorial from Sun is well worth a read. Excellent explanation and background reading, including the event dispatching thread, using worker threads, etc
You need to do the task that takes some time in a different thread.
The reason the button is blocking is because the work is being done in the same thread that draws the button. Once the work is done the button can do the rest of what you tell it to.
If you use a different thread the thread will go do the task while the drawing code can continue drawing the form.