I am creating my own dialog which is basically a JPanel set as the glasspane on a JFrame. I want to make my dialog modal in the sense that all the code after the setVisible() is not executed while the dialog is visible and once the dialog is closed, the rest of the code after the setVisible() must continue.
To achieve this I am using a thread to display my dialog. I know that the SwingUtilities.invokeLater() method must be used to update the gui because it is executed in another thread. However my dialog does not show on the screen.
Here is my code example:
final JFrame frame = new JFrame();
frame.setBounds(0, 0, 1024, 768);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
JButton button = new JButton("Text");
button.setBounds(200, 300, 110, 50);
button.addActionListener(new ActionListener() {
boolean dispose;
public void actionPerformed(ActionEvent e) {
try {
Thread thread = new Thread(new Runnable() {
public void run() {
final JPanel panelGlass = new JPanel(null);
panelGlass.setBounds(frame.getBounds());
panelGlass.setBackground(Color.red);
frame.setGlassPane(panelGlass);
JButton btnClose = new JButton("close");
btnClose.setBounds(100, 100, 110, 50);
btnClose.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
dispose = true;
}
});
panelGlass.add(btnClose);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
dispose = false;
panelGlass.setVisible(true);
}
});
while (!dispose) {
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
panelGlass.setVisible(false);
}
});
thread.start();
thread.join();
} catch (Exception ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
frame.getContentPane().add(button);
frame.setVisible(true);
Why is my dialog not shown?
The problem is here:
thread.start();
thread.join();
You start the thread but you immediately wait for it to finish. This blocks the UI thread and doesn't allow it to process your SwingUtilities.invokeLater update.
I really don't see any good reason for that join call to exist.
You can't do that like that since
you're accessing Swing components from a thread other than the event disptach thread
the event disptach thread, where all the UI painting happens, is completely blocked by the call to Thread.join().
You should be able to do something like what you want with Java 7's SecondaryLoop, but I've never used it.
frame.getRootPane.setGlassPane
your idea is good, but have to consume() events came from keyboard, add there KeyListener only with e.consume() because GlassPane to consume only mouse events
create whole Gui with GlassPane too,
inside actionperformed to show prepared GlassPane, then to start a Runnable.Thread
I have one question here about multiply glasspane
use JLayer Java7, based on JXLayer Java6
your question is booking example for why reason is SwingWorker implemented in Java
reply from cellphone
Related
i wrote my code like below and LABEL moved correctly:
panel.setLayout(null);
JLabel label1=new JLabel("LABEL");
JLabel label2=new JLabel("0");
JButton btn1=new JButton("start");
btn1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e)
{
Thread t=new Thread()
{
public void run()
{
while(true)
{
try
{
Thread.sleep(10);
}
catch (Exception ex)
{}
label2.setText(String.valueOf(Integer.parseInt(label2.getText())+1));
label1.setLocation(label1.getX()+1, label1.getY());
}
}
};
t.start();
}
});
but when i wrote in Netbeans Jframe it didn't move!
is it possible that problem is from JFrame layout manager??
How can i solve it?
At the same problem, when i comment line A of below code changing location of jLabel2 working correctly but when both line A and B aren't comment jLabel2 never move!!
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
Thread t=new Thread()
{ public void run()
{ while(true)
{ try
{ Thread.sleep(10); }
catch (Exception ex) {}
/* line A */
jLabel1.setText(String.valueOf(Integer.parseInt(jLabel1.getText())+1));
/* line B */
jLabel2.setLocation(jLabel2.getX()+1, jLabel2.getY());
}
}
};
t.start();
}
Again
If you're animating a component, then the container that holds it needs to use a null layout. If you're not sure what layout it's using, ask it -- call getLayout() and print out the result.
Use a Swing Timer not a background thread to drive your animation. This will ensure that you make Swing calls on the Swing event thread, something that your code is not doing.
After moving your component, call revalidate() and repaint() on the container that holds it.
I have a Swing application where I wish to add some delay. I have a close button, which on clicking should display the JTextArea which displays "Closing database connections...." and then execute Database.databaseClose() method and System.exit(). I have tried using Thread.sleep() method as in the code below for the delay. When I execute the program, the screen freezes for 2 seconds and then closes without displaying the JTextArea. The close button and JTextArea is added to JFrame directly.
What I want is that on clicking the close button, the JTextArea should be displayed immediately and then the application should delay for 2 seconds before finally implementing the Database.databaseClose() method and exiting the program. The Database.databaseClose() method works just fine.
I am a beginner at Swings and would greatly appreciate it if anyone could modify the code to implement the requirement above. Thanks!
Here's the code snippet:
JButton btnClose = new JButton("Close");
btnClose.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
JTextArea txtrClosingDatabaseConnections = new JTextArea();
txtrClosingDatabaseConnections.setText("\r\n\tClosing database connections....");
getContentPane().add(txtrClosingDatabaseConnections);
validate();
repaint();
/*
try
{
Thread.sleep(2000);
}
catch (InterruptedException e2)
{
e2.printStackTrace();
}
*/
try
{
Database.databaseClose();
}
catch (Exception e1)
{
e1.printStackTrace();
}
System.exit(0);
}
});
getContentPane().add(btnClose);
Hej, this is an example method that initializes an JMenuBar on a JFrame in Swing.
private JMenuBar initMenuBar() {
JMenuBar menuBar = new JMenuBar();
JMenu fileMenu = new JMenu("File");
exitApp = new JMenuItem("Exit App");
exitApp.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Timer t = new Timer(2000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
JOptionPane.showMessageDialog(getParent(), "Closing App in 2 Seconds");
t.start();
}
});
fileMenu.add(exitApp);
menuBar.add(fileMenu);
return menuBar;
}
May it will help you. It creates an JOptionPane, which must be closed by clicking OK, then the JFrame will be closed after 2 seconds.
Your code is executing on the Event Dispatch Thread, so you can't use a Thread.sleep() since that will block the EDT and prevent it from repainting the GUI.
You need to use a separate Thread for you database processing. Read the section from the Swing tutorial on Concurrency for more information as well as a solution that uses a SwingWorker to manager this Thread for you.
The Timer is the solution. The Swing timer's task is performed in the event dispatch thread. This means that the task can safely manipulate components, but it also means that the task should execute quickly.
You can use Swing timers in two ways:
To perform a task once, after a delay.
For example, the tool tip manager uses Swing timers to determine when to show a tool tip and when to hide it.
To perform a task repeatedly.
For example, you might perform animation or update a component that displays progress toward a goal.
Please go through http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html for more details.
I am trying to make a simple JButton, which when being clicked causes a simple JLabel to change its text to "second text", after that I want the current thread to sleep for few seconds and finally the JLabel to change its text again, this time to a "third text". I think I have it done here, but it doesn't work the way I want it. The code provided below makes the JButton freeze for the specified timeframe, as if it is held down, and then the label changes to the its third state. Said in other words, the "seconds text" does not appear.
Please advise me how should it be done.
Thank you.
package testPackage;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Demo {
public static void main(String[] args) throws InterruptedException {
JFrame frame = new JFrame();
JButton button = new JButton("Click me!");
final JLabel label = new JLabel("first text");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 600);
JPanel panel = new JPanel();
panel.add(button);
panel.add(label);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
label.setText("second text");
try {
Thread.currentThread();
Thread.sleep(4000);
} catch (InterruptedException exc) {
System.out.println("Erorrrrr");
}
}
});
frame.add(panel);
frame.setVisible(true);
}
}
The change of text property is not the only thing that has to be done to see the result when you consider the internals of Java. The control also has to be redrawn (possibly invalidated).
By calling sleep you actually stop java GUI internal worker from redrawing the control you changed. It can happen only after the sleep has finished.
In the action performed method you need to release the main GUI Thread for the changes to occur:
So if you open a new Thread in the actionPerformed method it will release the main GUI thread then after the sleep call the label.setText("third text") this will change the label to second text first wait for 4secs and then change it to third text
#Override
public void actionPerformed(ActionEvent e) {
label.setText("second text");
new Thread(){
public void run(){
try {
//Thread.currentThread();
Thread.sleep(4000);
label.setText("third text");
} catch (InterruptedException exc) {
System.out.println("Erorrrrr");
}
}
}.start();
}
Your GUI runs on a thread. When you sleep that thread for x number of seconds, your GUI freezes for x number of seconds.
As noted in the comments by Marko, "you must instead schedule a delayed event with javax.swing.Timer"
If you sleep on the Event Dispatch Thread (the thread that handles GUI events), then the GUI will freeze. You could start a background thread from the action listener and to the sleeping there.
public void actionPerformed(ActionEvent e)
{
label.setText("text 1");
new Thread(new Runnable()
{
public void run()
{
try {
Thread.sleep(1000);
}catch (InterruptedException ignore){}
// queue Swing code for execution on the EDT
EventQueue.invokeLater(new Runnable()
{
public void run()
{
label.setText("text2");
}
});
}
}).start();
}
I want to know how to display loading dialog at center of app screen. An indefinite progress bar.
If you're talking about a JDialog, after calling pack() on it, call setLocationRelativeTo(null) to center it.
Here's how I typically show a "loading..." progress bar. The loading itself must happen on a background thread to make sure the progress bar keeps updating. The frame with the progress bar will be shown in the center of the screen.
public static void main(String[] args) throws Throwable {
final JFrame frame = new JFrame("Loading...");
final JProgressBar progressBar = new JProgressBar();
progressBar.setIndeterminate(true);
final JPanel contentPane = new JPanel();
contentPane.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
contentPane.setLayout(new BorderLayout());
contentPane.add(new JLabel("Loading..."), BorderLayout.NORTH);
contentPane.add(progressBar, BorderLayout.CENTER);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Runnable runnable = new Runnable() {
public void run() {
// do loading stuff in here
// for now, simulate loading task with Thread.sleep(...)
try {
System.out.println("Doing loading in background step 1");
Thread.sleep(1000);
System.out.println("Doing loading in background step 2");
Thread.sleep(1000);
System.out.println("Doing loading in background step 3");
Thread.sleep(1000);
System.out.println("Doing loading in background step 4");
Thread.sleep(1000);
System.out.println("Doing loading in background step 5");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// when loading is finished, make frame disappear
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.setVisible(false);
}
});
}
};
new Thread(runnable).start();
}
display loading dialog at center of app screen.
dialog.setLocationRelativeTo(...);
An indefinite progress bar.
Read the section from the Swing tutorial on How to Use Progress Bars
From the documentation:
JProgressBar progressBar = new JProgressBar();
progressBar.setIndeterminate(true);
This will create the progress bar. To center it, you should take a look at the different kinds of layout managers in java.
Without any examples of your existing code, it's hard to give a more precise answer to your question.
Hi is it possible to create a Java Swing JDialog box (or an alternative Swing object type), that I can use to alert the user of a certain event and then automatically close the dialog after a delay; without the user having to close the dialog?
This solution is based on oxbow_lakes', but it uses a javax.swing.Timer, which is intended for this type of thing. It always executes its code on the event dispatch thread. This is important to avoid subtle but nasty bugs
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Test {
public static void main(String[] args) {
JFrame f = new JFrame();
final JDialog dialog = new JDialog(f, "Test", true);
Timer timer = new Timer(2000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
dialog.setVisible(false);
dialog.dispose();
}
});
timer.setRepeats(false);
timer.start();
dialog.setVisible(true); // if modal, application will pause here
System.out.println("Dialog closed");
}
}
Yes - of course you can. Have you tried to schedule a close?
JFrame f = new JFrame();
final JDialog dialog = new JDialog(f, "Test", true);
//Must schedule the close before the dialog becomes visible
ScheduledExecutorService s = Executors.newSingleThreadScheduledExecutor();
s.schedule(new Runnable() {
public void run() {
dialog.setVisible(false); //should be invoked on the EDT
dialog.dispose();
}
}, 20, TimeUnit.SECONDS);
dialog.setVisible(true); // if modal, application will pause here
System.out.println("Dialog closed");
The above program will close the dialog after 20 seconds and you'll see the text "Dialog closed" printed to the console
I would use a Swing Timer. When the Timer fires the code will be executed in the Event Dispatch Thread automatically and all updates to the GUI should be done in the EDT.
Read the section from the Swing tutorial on How to Use Timers.