Java 如果光标退出,如何在几秒钟后隐藏弹出窗口

Java 如果光标退出,如何在几秒钟后隐藏弹出窗口,java,swing,timer,cursor,hide,Java,Swing,Timer,Cursor,Hide,我有一个弹出的JDialog,它会显示3秒钟并进行处理。 它出现在光标位置,只有当光标退出弹出窗口时才需要处理 如果光标进入弹出窗口,计时器将停止并在退出时重新启动 但是我的第一个想法是使用dispose-定时器,它通过MouseListener启动和停止,但它不适用于某些JComponents,这会导致mouseExited() 我的第二个想法永远不会启动计时器 public void mouseExited( MouseEvent e ) { if(!Popup.this.getBo

我有一个弹出的
JDialog
,它会显示3秒钟并进行处理。
它出现在光标位置,只有当光标退出弹出窗口时才需要处理

如果光标进入弹出窗口,计时器将停止并在退出时重新启动

但是我的第一个想法是使用dispose-
定时器,它通过
MouseListener
启动和停止,但它不适用于某些
JComponent
s,这会导致
mouseExited()

我的第二个想法永远不会启动计时器

public void mouseExited( MouseEvent e ) {
    if(!Popup.this.getBounds().contains( e.getLocationOnScreen() )){
        timer.start();
    }
}
我不想将侦听器添加到弹出窗口中的每个组件。
有没有一个简单的方法可以做到这一点

例如:

public class Popup extends JDialog {

    private static final long serialVersionUID = 1337L;

    private final Timer timer = new Timer( 3000, new ActionListener() {
        @Override
        public void actionPerformed( ActionEvent e ) {
            Popup.this.dispose();
            System.exit( 0 );
        }
    });

    public Popup() {
        setBounds( 100, 100, 300, 300 );
        addMouseListener( new PopupBehavior() );
        getContentPane().setLayout( new BorderLayout() );
        getContentPane().add( new JTextArea(), BorderLayout.NORTH );
        getContentPane().add( new JSplitPane(0,new JPanel(), new JLabel("2")), BorderLayout.CENTER );
        getContentPane().add( new JProgressBar(), BorderLayout.SOUTH );
        getContentPane().add( new JLabel("west"), BorderLayout.WEST );
        getContentPane().add( new JSpinner(), BorderLayout.EAST );
    }

    public static void main( String[] args ) {
        SwingUtilities.invokeLater( new Runnable() {
            @Override
            public void run() {
                new Popup().setVisible( true );
            }
        });
    }

    private class PopupBehavior extends MouseAdapter {
        @Override
        public void mouseEntered( MouseEvent e ) {
            System.out.println("mouseEntered");
            timer.stop();
        }
        @Override
        public void mouseExited( MouseEvent e ) {
            System.out.println("mouseExited");
            timer.start();
        }
    }
}
例如(据我所知,大多数
JComponents
)都有
Model

如果要从模型或从预定义的
矩形中移出的鼠标启动
javax.swing.Timer

如果鼠标返回到预定义的
矩形
,则只需重新启动
javax.swing.Timer


卓越的sugestion自JToolTip以来

从jdk7开始,您可以使用JLayer装饰您的容器,并在其processMouseEvent中停止/启动计时器

class DisposingLayerUI extends LayerUI {

    @Override
    public void installUI(JComponent c) {
        super.installUI(c);
        JLayer jlayer = (JLayer)c;
        jlayer.setLayerEventMask(
                AWTEvent.MOUSE_EVENT_MASK 
        );
    }

    @Override
    public void uninstallUI(JComponent c) {
        JLayer jlayer = (JLayer)c;
        jlayer.setLayerEventMask(0);
        super.uninstallUI(c);
    }


    @Override
    protected void processMouseEvent(MouseEvent e, JLayer l) {
        if (e.getID() == MouseEvent.MOUSE_ENTERED) {
            timer.stop();
        } else if (e.getID() == MouseEvent.MOUSE_EXITED){
            timer.start();

        }
    }

}

// to use in your code, do all init and then decorate the contentPane
...
setContentPane(new JLayer(getContentPane(), new DisposingLayerUI()));

对于较旧的版本,您可以使用项目中的层(它是当前开发的层)或手动实现全局侦听器,如《任何帮助》中的f.i.所示。@trashgod-您不是建议向每个孩子递归注册侦听器,是吗?只有在实际涉及到
JSpinner
时才作为最后手段;您引用的
AWTEventListener
看起来更有希望。@trashgod同意最后的办法:-)在沙盒上下文中可能是必要的,因为沙盒上下文不允许注册AWTEventListener。JLayer也使用它,但作为特权操作的核心是更多的随机想法,这一次与接收儿童鼠标事件无关;-)