3

I have a JDialog as a Popup which shows up for 3 seconds and dispose.
It comes up at cursor position and has to dispose only if the cursor exits the popup.

If the cursor entered the Popup the timer stops and start again on exit.

But my first idea with a dispose-Timer that starts and stops via MouseListener doesn't work with some JComponents, which causes a mouseExited().

My second idea will never start the Timer

public void mouseExited( MouseEvent e ) {
    if(!Popup.this.getBounds().contains( e.getLocationOnScreen() )){
        timer.start();
    }
}

I don't want to add the Listener to every component in the popup.
Is there an easy way to do that.

Example:

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();
        }
    }
}
oliholz
  • 7,447
  • 2
  • 43
  • 82
  • Any help [here](http://stackoverflow.com/questions/6495769/how-to-get-all-elements-inside-a-jframe/6495800#6495800). – trashgod Sep 01 '11 at 12:52
  • @trashgod - you aren't suggesting to recursively register a listener with every child, are you? – kleopatra Sep 01 '11 at 13:26
  • Only as a last resort if `JSpinner` is actually involved; the `AWTEventListener` you cited looks more promising. – trashgod Sep 01 '11 at 16:07
  • @trashgod agreed on last resort :-) Might be necessary in sandboxed contexts, f.i., which dont permit the register an AWTEventListener. Which is used by the JLayer as well, but being core as a priviledged action – kleopatra Sep 02 '11 at 08:02

2 Answers2

4

As of jdk7 you can decorate your container with a JLayer and stop/start the timer in its 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()));

For older versions, you can use the layer from the JXLayer project (it's were the current was developed) or go for a manually implements global listener, as f.i. shown in Global Event Listeners

kleopatra
  • 51,061
  • 28
  • 99
  • 211
2

just for example JButton (and as I know majorities of JComponents) has Model

if you'll start javax.swing.Timer from Model or from mousemoved out from pre-defined Rectangle

if mouse returns back to the pre-defined Rectangle then just restart javax.swing.Timer

excelent sugestion since about JToolTip here

Community
  • 1
  • 1
mKorbel
  • 109,525
  • 20
  • 134
  • 319