Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Listen for when a Component is Shown for the First Time

I am trying to capture the very first moment when a component is shown on the screen without using 'dirty' solutions as with use of a timer. Basically, I want to know the moment when I can safely start using getLocationOnScreen() method on the component.

I thought that component listener could help but no luck here. I am stuck for now and do not know which listener to use for this. Any suggestions?

Here is some sample code which shows that a component listener fails.

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class CompListenerTest
{
    static ComponentListener cL = new ComponentAdapter()
    {
        @Override
        public void componentShown(ComponentEvent e)
        {
            super.componentShown(e);
            System.out.println("componentShown");
        }
    };

    static MouseListener mL = new MouseAdapter() 
    {

        @Override
        public void mousePressed(MouseEvent e)
        {
            super.mousePressed(e);
            JComponent c = (JComponent) e.getSource();
            System.out.println("mousePressed c="+c.isShowing());
        }

    };

    public static void main(String[] args)
    {
        JPanel p = new JPanel();
        p.setPreferredSize(new Dimension(300, 400));
        p.setBackground(Color.GREEN);
        p.addComponentListener(cL);
        p.addMouseListener(mL);

        System.out.println("initial test p="+p.isShowing());
        JPanel contentPane = new JPanel();
        contentPane.setBackground(Color.RED);
        contentPane.add(p);
        JFrame f = new JFrame();
        f.setContentPane(contentPane);
        f.setSize(800, 600);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);
    }
}

Thanks in advance.

like image 769
Boro Avatar asked Apr 25 '11 11:04

Boro


People also ask

What is component listener?

The Component listener is a listener interface for receiving component events. A component is an object having a graphical representation that can be displayed on the screen and that can interact with the user.

When the size location or visibility of a component changes which of the following events occurs?

Which of these events is generated when the size of an event is changed? Explanation: A ComponentEvent is generated when the size, position or visibility of a component is changed.

What is the relationship between GUI components and listeners?

A GUI in Java program is made up of on-screen components, events that those components generate, and listeners that respond to events when they occur.


2 Answers

The reason a ComponentListener doesn't work is that it reports changes to the visible property - and that is true by default, even without being part of the component hierarchy.

To be reliably notified, use a HierarchyListener


Edit (musings about my knowledge evolution in regard to this question/answers, not sure what the netiquette has to say about doing it ... simply guide me if that's the wrong way to go :-)

First: the question as asked in the subject is not necessarily related to the actual problem (as commented by Boro below - any way to link to a comment?): there's no need to keep some kind of local flag to decide whether or not it is safe to send a getLocationOnScreen to a component, simply ask the component itself. Learn-item 1 for myself :-)

Second: The question as asked is quite interesting. Five experts (including myself, self-proclaimed), five different answers. Which triggered a bit of digging on my part.

My hypothesis: ComponentEvents are not useful for notification of (first-)showing. I knew that componentShown is useless because it's a kind-of propertyChange notification of the visible property of a component (which rarely changes). Puzzled about the suggested usefulness of moved/resized, though.

Constructing a use-case: fully prepare the frame in the example and keep it ready for later showing, a typical approach to improve perceived performance. My prediction - based on my hypothesis: resized/moved fired at prepare-time, nothing at show-time (note: the isShowing is what we are after, that is the latter). A snippet to add in the OP's example:

    final JFrame f = new JFrame();
    f.setContentPane(contentPane);
    f.setSize(800, 600);
    //        f.pack(); 

    JFrame controller = new JFrame("opener");
    controller.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    Action open = new AbstractAction("open/hide second") {

        @Override
        public void actionPerformed(ActionEvent e) {
            f.setVisible(!f.isVisible());
        }

    };
    controller.add(new JButton(open));
    controller.pack();
    controller.setVisible(true);

Disappointment: no notification at prepare-time, notification at show-time, just as needed, my hypothesis seemed wrong ;-) Last chance: swap the setSize for a pack ... and voila, notification at prepare-time, no notification at show-time, happy me again. Playing a bit more: looks like ComponentEvents are fired if the a component is displayable, which may or may not be useful in some contexts but not if showing is the state we are after. The

New imperial rules (draft):
Do not use ComponentListener for notification of "showing". That's left-over from AWT-age.
Do use AncestorListener. That seems to be the Swing replacement, slightly misnomed notification of "added" which actually means "showing"
Do use HierarchyListener only if really interested in fine-grained state changes

like image 53
kleopatra Avatar answered Oct 12 '22 06:10

kleopatra


I"ve use an AncestorListener and handled the ancestorAdded event.

like image 25
camickr Avatar answered Oct 12 '22 04:10

camickr