I have a frame with menubar menu, when I'm selecting a menu item I want the program to show a message and then after few seconds(by sleep function) automatically close this message.
But instead of this I'm getting empty message (jdialog with invisible content):
If remove closing message, it content will appear after sleeping time.
What I need to change to get proper result?
I want to get this:
Full working code:
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.util.concurrent.TimeUnit;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.SwingUtilities;
public class MessageSleepTest extends JDialog {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run(){
new Frame("frame with menubar");
}
});
}
}
class Message extends JDialog {
public Message() {
this.setLayout(new GridLayout(0, 1));
this.add(new JLabel("Displaying this message for 3 seconds and then closing it...", JLabel.CENTER));
this.setAlwaysOnTop(true);
this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
}
}
class Frame extends JFrame{
public Frame(String title){
super(title);
setJMenuBar(new MenuBar());
setPreferredSize(new Dimension(500, 300));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setLocationRelativeTo(null); // center the frame
setVisible(true);
}
}
class MenuBar extends JMenuBar implements ActionListener{
public static JMenuItem itmOpen;
public MenuBar() {
JMenu menuFile = new JMenu("File");
itmOpen = new JMenuItem("Open...");
itmOpen.addActionListener(this);
add(menuFile);
menuFile.add(itmOpen);
}
@Override
public void actionPerformed(ActionEvent e) {
JMenuItem source = (JMenuItem)e.getSource();
if(source == itmOpen){
JDialog message = new Message();
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
WindowEvent windowClosing = new WindowEvent(message, WindowEvent.WINDOW_CLOSING);
message.dispatchEvent(windowClosing);
}
}
}
You have a threading problem:
The sleep
is performed on AWT's Event Dispatch Thread, which does all the event handling stuff in AWT and Swing. Therefore, when you click on the menu item, it creates the objects for the Message
, but gets stuck with the setVisible()
method, which in general sends an event to the JDialog to lay out and show itself. This message gets on the queue of the EDT, and after your event handler (the actionPerformed
method) finishes, it gets processed. However the sleep is between the two.
So try something like this:
@Override
public void actionPerformed(ActionEvent e) {
JMenuItem source = (JMenuItem) e.getSource();
if (source == itmOpen) {
final JDialog message = new Message();
new Thread( new Runnable() {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException ex) {
// Do nothing with it
}
WindowEvent windowClosing = new WindowEvent(message, WindowEvent.WINDOW_CLOSING);
message.dispatchEvent(windowClosing);
}
}).start();
}
}