new thread not showing the frame - java

I am trying to establish a network connection and the details are in a JFrame. When user clicks a button, it should start the new thread and should show the wait message to the user until, the main thread establish a network connection. I wrote this code
public void actionPerformed(ActionEvent arg0) {
Thread ref = new Thread(new Test());//Create a new thread
ref.start();
new AIDRTConnManager().createConnection(ipAddress, portAddress);//main thread
}
//This is my Thread Class
public class Test implements Runnable{
JDialog waitDialog;
JPanel panel1 = new JPanel();
JLabel waitLabel;
JFrame frame;
public void run(){
frame = new JFrame();
waitDialog = new JDialog( frame,AIRDT.toolName, true );
waitDialog.setDefaultCloseOperation( JDialog.DO_NOTHING_ON_CLOSE );
JLabel waitLabel = new JLabel( "Trying to Connect to PleaseWait...",ErrorDialog.icon,SwingConstants.CENTER );
panel1.add( waitLabel );
waitDialog.add( panel1 );
waitDialog.setSize( 100, 40 );
waitDialog.setBounds( 500,300, 300, 80 );
waitDialog.setVisible( true );
}
}
But when I click the button, the Jdialog shows the empty frame, without the wait message (JLable) and once I done with the network connection, this wait message shows properly.
Where I am going wrong? Is this a Swing Issue (Or) Thread Issue?
Could you please help me to show a wait message until the completion of back end activity?

You're mixing up your threads here - all operations that interact with the UI, such as creating a new frame, must occur on the Event Dispatch Thread (EDT), or the "main" thread as you call it. Background tasks should be performed on a different thread.
Basically you have it backwards - you should perform the background work in the new thread, and create the new frame in the main thread, which is the opposite way to how you have it now.

The code under the actionPerformed executes under the Event Dispatch Thread (EDT), not on the main thread as you say in the comment.
This means that as long as the connection thing happens, the EDT is blocked, so it doesn't have to chance to process some other UI stuff like displaying your JDialog.
Also, not related to the issue, but please note that you create a JFrame that is never displayed and that is the parent of your JDialog.

Related

java swing progressBar [duplicate]

This question already has answers here:
Prevent Swing GUI locking up during a background task
(5 answers)
Closed 6 years ago.
I have written code using swing libs, that when added an actionlistener, won't update a progressBar.
Without a button and action listener, it works great. How to force a progressBar update as simply and cleanly as possible? Appended code is an easy to understand example that sums up my problem. If you comment out an ActionPerformed method and execute the program from main, it works just fine.
Do not just paste code whithout explaining.
ps.: I have seen this: swing progressBar threading
public class Okno {
private JProgressBar progressBar = new JProgressBar(0,306);
JFrame f = new JFrame("JProgressBar Sample");
JButton b = new JButton("start");
ActionListener a = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
barupdate();
}
};
private void barupdate(){
for(int p = 1; p<308;p=p+2){
System.out.println(p);
progressBar.setValue(p);
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private Okno(){
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
progressBar.setStringPainted(true);
f.add(progressBar, BorderLayout.SOUTH);
f.add(b, BorderLayout.NORTH);
b.addActionListener(a);
f.setSize(300, 300);
f.setVisible(true);
}
public static void main(String[] args) {
Okno okno = new Okno();
}
}
The problem is you have a loop where you are adjusting the progress bar setting that is being called from an action listener. The problem is, the bar won't update until after the listener is finished. And so you will get no updates. Not only that but you will bog down the gui because the window can't react to mouseclicks etc while you are in that action listener.
So the best way to handle this is instead to create a swing timer, in the action listener, and put the code for updating the button there, and start the timer in the action listener.
The timer should only update the bar once. and you should allow the fact that the swing timer will be called multiple times, to play the part of the repetitiveness. So you don't want to have any loops in your code.
Thread.sleep(50);
Don't use Thread.sleep(...). This will prevent the GUI from repainting itself until the loop has finished executing.
Instead you can use a SwingWorker.
Read the section from the Swing tutorial on Concurrency in Swing which has more information and contains a working example with a SwingWorker.
Also, look at the tutorial table of contents. There is a section on How to Use ProgressBars that also contains a working example. The tutorial is the first place to look for examples.

JDialog with a JProgressBar [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Java GUI JProgressBar not painting
I have a GUI that has the GUI Locked while processing an Action Event, so I need a progress bar to show up. I can get the JDialog to show up but the progress bar won't show up. I used SwingUtilities.invokeLater() and invokeAndWait() but to no avail. The progress bar will not show up. Any hints or help would be appreciated.
pb = new JProgressBar(0, 100);
pb.setPreferredSize(new Dimension(175, 40));
pb.setString("Working");
pb.setStringPainted(true);
JLabel label = new JLabel("Progress: ");
JPanel center_panel = new JPanel();
center_panel.add(label);
center_panel.add(pb);
dialog = new JDialog((JFrame) null, "Working ...");
dialog.getContentPane().add(center_panel, BorderLayout.CENTER);
dialog.pack();
dialog.setLocationRelativeTo(this); // center on screen
dialog.toFront(); // raise above other java windows
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
dialog.setVisible(true);
pb.setIndeterminate(true);
}
});
Thread.sleep(5000);
template = AcronymWizardController
.sharedInstance().readAndDislpayDocx(contdFile);
parseDocxText(contdFile);
pb.setIndeterminate(false);
savedFile.setText(contdFile.toString());
dialog.dispose();
Swing is a single threaded API, that is, all the UI updates and modifications are performed from within a single thread (known as the Event Dispatching Thread or EDT). Anything that blocks this thread will stop it from processing additional updates, like repaints.
You have a number of choices. Your immediate requirement is to move the long running task off the EDT. To do this you can either use a SwingWorker or a Thread.
From your description, a SwingWorker will be easier.
For a simple example, check out JProgressBar won't update
For more information, you should check out Concurrency in Swing
You other choice would be to use something like a ProgressMonitor, example here

Why actionPerform() run in Event Dispatch Thread but componentAdded() is not?

I have Ex1 below:
main(String args[]) {
JFrame frame = new JFrame("Title");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton button = new JButton("Press Here");
ContainerListener container = new ContainerAdapter() {
public void componentAdded(final ContainerEvent e) {
System.out.println("On the event thread? : " +
EventQueue.isDispatchThread());
}
};
frame.getContentPane().addContainerListener(container);
frame.add(button, BorderLayout.CENTER);
frame.setSize(200, 200);
System.out.println("I'm about to be realized: " +
EventQueue.isDispatchThread());
frame.setVisible(true);
}
My result is: On the event thread? : FALSE | I'm about to be realized: false
Other Ex2:
public class GridBagLayoutTester
extends JPanel implements ActionListener{
public GridBagLayoutTester() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
JButton button = new JButton("Testing");
// do something...
button.addActionListener(this);
add(button, gbc);
}
public void actionPerformed(ActionEvent e) {
System.out.println("On the event thread? : " +
EventQueue.isDispatchThread());
}
public static void main(String[] args) {
JFrame frame = new JFrame("GridBagLayoutDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container contentPane = frame.getContentPane();
contentPane.setLayout(new BorderLayout());
contentPane.add(new GridBagLayoutTester(), BorderLayout.CENTER);
frame.setSize(800, 600);
frame.pack();
frame.setVisible(true);
System.out.println("I'm about to be realized: " +
EventQueue.isDispatchThread());
}
}
result is: I'm about to be realized: false | On the event thread? : TRUE
My question is why Ex1- componentAdded() run in Intial Thread, but Ex2- actionPerformed() run in EDT ?
Few facts about GUI applications in Java:
- In Java GUI applications the main() method is short-lived, after scheduling the construction of GUI in the Event Dispatcher Thread (EDT) it quits.
- So its EDT's responsibility to handle the GUI.
Now coming to your code:
- Initial Thread is the main() thread, and EDT is the GUI Thread.
- In EX1 you are forcing the GUI to run on the main() thread which is a wrong way to do it, where as in EX2 when you use the GridBagLayoutTester which extends JPanel, main() thread gets an early chance to quite by delegating the work of GUI to the EDT.
- main() method should be used on to execute the EventQueue.invokeLater() method which further deals with the GUI, this will help the UI to be responsive and avoid dealing with any Non-UI work.
- Moreover Java has SwingUtilities Class that does a great synchronization between the UI and Non-UI work on the UI and Non-UI thread respectively.
Eg: The proper way of doing it.......
public class Test extends JFrame{
public Test(){
this.setSize(300,300);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args){
EventQueue.invokeLater(new Runnable(){
public void run(){
new Test().setVisible(true);
}
});
}
}
Your very first line in the main method creates a new object of type JFrame. This creation starts a new thread (in reality it starts more than one thread) - a new thread that waits for event queue items. This can be a mouse click for example.
To answer your question: The main thread - which is really called "main" - is invoking your 10 lines of code of the main method. This should be finished in some milliseconds. After that the main thread is gone, not existend anymore.
But as I said before, the AWT/Swing library has internally created one (yes, more) thread that is basically an ininite loop checking for user input. And the actionPerformed method is invoked from this thread.
My suggestion for you:
Create a breakpoint in your first line of the main method.
Debug your program.
When the debugger stops at line one (before JFrame is created) go to your command line and start jconsole
go to tab threads
notice thread "main"
execute single line (new JFrame)
notice coexistence of thread "main" and thread(s) "AWT-*"
press play on debugger and "main" will be gone but AWTs will persist

Swing: How to prohibit interaction outside of JFrame/JDialog?

I'd like to show a progressbar and block interaction with my application frame while a thread is being executed.
In another thread someone suggested using JDialog instead of JFrame and setModal(true). However, when doing so the Dialog blocks the entire application.
This is essentially my code:
MyDialog dlg = new MyDialog();
dlg.setModal(true);
dlg.setVisible(true);
//do some stuff....
//(never executed when setModal(true)
dlg.setVisible(false);
The easiest way to do it would be using JXLayer and LockableUI.
Look here for an example of how this can be done.
Also note, that JXLayer made it into Java 7, and is available as javax.swing.JLayer.
The other thing is, that you should not execute long-running tasks insite Event Dispatch Thread. Read about SwingWorker and learn to write multithreaded code for Swing.
That is the point of a modal dialog, no interaction will happen outside the "box". The modal popup also halts the thread while waiting for user input. If you want to do other stuff while showing the dialog you will either have to do it in the dialog itself or start a new thread to take care of it.
Hope that helps!
With modal dialog try something like this:
final JDialog dlg = new JDialog();
dlg.setModal(true);
dlg.setSize(500, 500);
dlg.addWindowListener(new WindowAdapter() {
#Override
public void windowActivated(WindowEvent e) { //or other method
new Thread(new Runnable() {
public void run() {
try {
//execute your long running task
} //you should catch exception
finally {
dlg.setVisible(false);
dlg.dispose();
}
}
}).start();
}
});
dlg.setVisible(true);
I can also set GlassPane on your JFrame which will intercept any event from the user.

Create a plain message box that disappears after a few seconds in Java

I wonder what is the best approach to make a JOptionPane style plain message box disappear after being displayed for a set amount of seconds.
I am thinking to fire up a separate thread (which uses a timer) from the main GUI thread to do this, so that the main GUI can carry on processing other events etc. But how do I actually make the message box in this separate thread disappear and terminate the thread properly. Thanks.
Edit: so this is what I come up with by following the solutions posted below
package util;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import javax.swing.Timer;
public class DisappearingMessage implements ActionListener
{
private final int ONE_SECOND = 1000;
private Timer timer;
private JFrame frame;
private JLabel msgLabel;
public DisappearingMessage (String str, int seconds)
{
frame = new JFrame ("Test Message");
msgLabel = new JLabel (str, SwingConstants.CENTER);
msgLabel.setPreferredSize(new Dimension(600, 400));
timer = new Timer (this.ONE_SECOND * seconds, this);
// only need to fire up once to make the message box disappear
timer.setRepeats(false);
}
/**
* Start the timer
*/
public void start ()
{
// make the message box appear and start the timer
frame.getContentPane().add(msgLabel, BorderLayout.CENTER);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
timer.start();
}
/**
* Handling the event fired by the timer
*/
public void actionPerformed (ActionEvent event)
{
// stop the timer and kill the message box
timer.stop();
frame.dispose();
}
public static void main (String[] args)
{
DisappearingMessage dm = new DisappearingMessage("Test", 5);
dm.start();
}
}
Now the question is that, as i cam going to create multiple instances of this class throughout the course of the interaction between the user and the main GUI, I wonder whether the dispose() method cleans up everything properly every time. Otherwise, I may end up with accumulating lots of redundant objects in memory. thanks.
I think in your situation, you can't use any of JOptionPane static methods (showX...). You have to create a JOptionPane instance instead, then create a JDialog from it and show that JDialog yourself. Once you have JDialog, you can force its visibility.
// Replace JOptionPane.showXxxx(args) with new JOptionPane(args)
JOptionPane pane = new JOptionPane(...);
final JDialog dialog = pane.createDialog("title");
Timer timer = new Timer(DELAY, new ActionListener() {
public void actionPerformed(ActionEvent e) {
dialog.setVisible(false);
// or maybe you'll need dialog.dispose() instead?
}
});
timer.setRepeats(false);
timer.start();
dialog.setVisible(true);
I haven't tried it so I can't guarantee that it works but I think it should ;-)
Of course, here Timer is javax.swing.Timer, as someone else already mentioned, thus you're sure the action will run in the EDT and you won't have any problem with creating or terminating your own Thread.
Timers have their own threads. I think what you probably should do is create a new Timer (or, preferably, make one that you reuse till you don't need it any more), schedule a task that will ask for the message box to disappear and then have that task add another task to the event queue, which will remove the message box.
There might be a better way though.
In addition:
Yes, using javax.swing.timer would probably be better. The reason I talk about using two tasks in the above is that I assume you will have to execute your hiding method inside of the AWT thread to avoid certain subtle race issues that might arise. If you use javax.swing.Timer you're already executing in the AWT thread, so that point becomes moot.

Categories