具有不可见内容的导致睡眠的框架
Sleep causing frame with invisible content
我有一个带有菜单栏菜单的框架,当我选择一个菜单项时,我希望程序显示一条消息,然后在几秒钟后(通过睡眠功能)自动关闭此消息。
但我得到的不是这个,而是空消息(带有不可见内容的 jdialog):
如果删除关闭消息,它的内容将在休眠时间后出现。
我需要更改什么才能获得正确的结果?
我想要这个:
完整的工作代码:
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);
}
}
}
您遇到线程问题:
sleep
在 AWT 的事件调度线程上执行,它执行 AWT 和 Swing 中的所有事件处理工作。因此,当您单击菜单项时,它会为 Message
创建对象,但会卡在 setVisible()
方法中,该方法通常会向 JDialog 发送一个事件以进行布局和显示。此消息进入 EDT 队列,在您的事件处理程序(actionPerformed
方法)完成后,它会得到处理。然而睡眠介于两者之间。
所以尝试这样的事情:
@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();
}
}
另一个使用swing.Timer
的解决方案
@Override
public void actionPerformed(ActionEvent e) {
JMenuItem source = (JMenuItem)e.getSource();
if(source == itmOpen){
JDialog message = new Message();
Timer timer = new Timer(1000 * 3, new ActionListener() {
public void actionPerformed(ActionEvent e) {
WindowEvent windowClosing = new WindowEvent(message, WindowEvent.WINDOW_CLOSING);
message.dispatchEvent(windowClosing);
}
});
timer.setRepeats(false);
timer.start();
}
}
我有一个带有菜单栏菜单的框架,当我选择一个菜单项时,我希望程序显示一条消息,然后在几秒钟后(通过睡眠功能)自动关闭此消息。
但我得到的不是这个,而是空消息(带有不可见内容的 jdialog):
如果删除关闭消息,它的内容将在休眠时间后出现。
我需要更改什么才能获得正确的结果?
我想要这个:
完整的工作代码:
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);
}
}
}
您遇到线程问题:
sleep
在 AWT 的事件调度线程上执行,它执行 AWT 和 Swing 中的所有事件处理工作。因此,当您单击菜单项时,它会为 Message
创建对象,但会卡在 setVisible()
方法中,该方法通常会向 JDialog 发送一个事件以进行布局和显示。此消息进入 EDT 队列,在您的事件处理程序(actionPerformed
方法)完成后,它会得到处理。然而睡眠介于两者之间。
所以尝试这样的事情:
@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();
}
}
另一个使用swing.Timer
的解决方案@Override
public void actionPerformed(ActionEvent e) {
JMenuItem source = (JMenuItem)e.getSource();
if(source == itmOpen){
JDialog message = new Message();
Timer timer = new Timer(1000 * 3, new ActionListener() {
public void actionPerformed(ActionEvent e) {
WindowEvent windowClosing = new WindowEvent(message, WindowEvent.WINDOW_CLOSING);
message.dispatchEvent(windowClosing);
}
});
timer.setRepeats(false);
timer.start();
}
}